zoukankan      html  css  js  c++  java
  • & VUE 学习记录-1

    VUE学习记录

    Day01

    什么是Vue.js

    • Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机App, Vue语法也是可以用于进行手机App开发的,需要借助于Weex)
    • Vue.js 是前端的主流框架之一,和Angular.js、React.js 一起,并成为前端三大主流框架!
    • Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)
    • 前端的主要工作?主要负责MVC中的V这一层;主要工作就是和界面打交道,来制作前端页面效果;

    为什么要学习流行框架

    • 企业为了提高开发效率:在企业中,时间就是效率,效率就是金钱;
      • Jquery + art-template + Ajax
      • 在没有前端框架之前,我们前端需要经常的操作DOM元素;
      • 在项目中,vue 能够简化DOM操作,让程序员根本不用操作任何DOM元素,就能渲染页面;
      • 企业中,使用框架,能够提高开发的效率;
    • 提高开发效率的发展历程:原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js / Vue.js(能够帮助我们减少不必要的DOM操作;提高渲染效率;双向数据绑定的概念【通过框架提供的指令,我们前端程序员只需要关心数据的业务逻辑,不再关心DOM是如何渲染的了】)
    • 在Vue中,一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑;

    框架的区别

    • 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目。
      node 中的 express;
    • 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
      • 从Jquery 切换到 Zepto
      • 从 EJS 切换到 art-template

    Node(后端)中的MVC 与 前端中的 MVVM 之间的区别

    • MVC 是后端的分层开发概念;
    • MVVM是前端视图层的概念,主要关注于 视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View , VM ViewModel

    Vue之 - 基本的代码结构和插值表达式v-cloak

    • 使用 插值表达式,存在内容闪烁的问题,但是,v-text没有闪烁问题;
    • 在插值表达式中,可以使用 v-cloak 解决闪烁问题;
    • 插值表达式只会插入内容,并不会清楚其余的内容; v-text 会把元素中之前的内容都清空!

    Vue指令之v-text和v-html

    <div id="app">
       <div v-text="msg3"></div>
       <div v-html="msg3"></div>
    </div>
    
    
    <script>
        //这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
        let vue = new Vue({
            //指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
            el:'#app',   
    
            //data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
            data:{
                msg3:'<h6>小标题</h6>',
            }
        });
    
    </script>

    image-20210617122720209

    Vue指令之v-bind的三种用法

    • 直接使用指令v-bind
    • 使用简化指令:
    • 在绑定的时候,拼接绑定内容::title=”btnTitle + ‘, 这是追加的内容’”
    <body>
        <!--创建一个容器,将来使用VUE就可以控制这个指定容器中的所有DOM元素-->
        <div id="app">
            <!--v-bind: 可以为元素的属性绑定一些数据-->
            <input type="button" value="按钮" v-bind:title="btnTitle">
            <hr>
            <input type="button" value="按钮" v-bind:id="customIdName" >
            <hr>
    
            <!--v-bind: 这个指令可以被简写成 :-->
            <input type="button" value="按钮" :title="btnTitle">
            <hr>
            <input type="button" value="按钮" :id="customIdName" >
            <hr>
    
            <!--v-bind: 指令中,如果想要实现表达式的拼接,被拼接的字符串一定要用引号包裹起来,否则会被当做变量解析-->
            <input type="button" value="按钮" :title="btnTitle + '这是追加的内容'">
        </div>
    
        <script>
            //这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
            let vue = new Vue({
                el:'#app',//指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
                data:{//data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
                    btnTitle:'这是按钮的自定义title值',
                    customIdName:'这是按钮的自定义id值'
                }
            });
    
        </script>
    </body>

    Vue指令之v-on跑马灯效果

    跑马灯效果

       <!DOCTYPE html>
        <html lang="en">
    
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
            <script src="./lib/vue-2.5.9.js"></script>
    
        </head>
    
        <body>
        <div id="app">
            <!--<input type="button" value="浪起来" id="btn1" v-on:click="lang" >-->
            <input type="button" value="浪起来" id="btn1" @click="lang" >
            <input type="button" value="stop浪" id="btn2" @click="stop">
            <hr>
            <h3>{{ msg }}</h3>
    
        </div>
    
        <script>
            let vue = new Vue({
                el:'#app',
                data:{
                    msg: '猥琐发育别浪~',
                    intervalId: null //定时器的id
                },
                methods:{
                    lang(){
                        if(this.intervalId != null){
                            return;
                        }
                        //定时器
                        this.intervalId = setInterval(() => {
                            let header = this.msg.substring(0,1)
                            let body = this.msg.substring(1)
                            this.msg = body + header
                        },300);
                    },
                    stop(){
                        clearInterval(this.intervalId)
                    }
                }
            });
    
        </script>
        </body>
        </html>

    Vue指令之v-on的缩写@事件修饰符

    事件修饰符:

    事件修饰符之.stop详解

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="./lib/vue-2.5.9.js"></script>
    
        <style>
            #inner {
                background-color: pink;
                height: 150px;
                 200px;
            }
    
            #inner2 {
                background-color: pink;
                height: 150px;
                 200px;
            }
        </style>
    
    </head>
    
    <body>
    <div id="app">
        <!--此处点击按钮 会触发冒泡事件 btnClick->innerClick -->
        <div id="inner" @click="innerClick">
            <input type="button" value="按钮" @click="btnClick">
        </div>
        <hr>
    
        <div id="inner2" @click="innerClick">
            <!--.stop阻止冒泡事件-->
            <input type="button" value="按钮" @click.stop="btnClick">
        </div>
    </div>
    
    <script>
        let vue = new Vue({
            el: '#app',
            data: {},
            methods: {
                innerClick() {//内部的div点击事件
                    console.log("内部的div点击事件")
                },
                btnClick(){//按钮的点击事件
                    console.log("按钮的点击事件")
    
                }
            }
        });
    </script>
    </body>
    </html>

    image-20210617123146048

    事件修饰符之.capture .self .once 详解

        <body>
        <div id="app">
            <!--a链接-->
            <a href="http://www.baidu.com" @click.prevent="linkClick">百度百度</a>
    
            <!--表单-->
            <form @submit.prevent="postForm">
                <input type="text" name="username">
                <input type="text" name="gender">
                <input type="submit" value="提交表单">
            </form>
        </div>
    
        <script>
            let vue = new Vue({
                el: '#app',
                data: {},
                methods: {
                    linkClick(){
                        console.log("按钮呗点击了")
                    },
                    postForm(){
                        console.log("触发了表单的submit")
                        //阻止了form的默认行为之后,就可以在这里就可以自定义调用接口
                    }
                }
            });
    
        </script>
        </body>

    事件修饰符之.prevent详解

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="./lib/vue-2.5.9.js"></script>
    
        <style>
            .inner {
                background-color: pink;
                height: 150px;
                 200px;
            }
    
        </style>
    
    </head>
    
    <body>
    <div id="app">
        <!--.capture添加事件侦听器时使用事件捕获模式-->
        <div class="inner" @click.capture="innerClick">
            <input type="button" value="按钮" @click="btnClick">
        </div>
        <hr>
    
        <div class="inner" @click.self="innerClick">
            <!--.self只当事件在该元素本身(比如不是子元素)触发时触发回调-->
            <input type="button" value="按钮" @click="btnClick">
        </div>
            <hr>
        <!--.once只执行一次-->
        <div class="inner" @click.once="innerClick">
            <input type="button" value="按钮" @click="btnClick">
        </div>
    </div>
    
    <script>
        let vue = new Vue({
            el: '#app',
            data: {},
            methods: {
                innerClick() {//内部的div点击事件
                    console.log("内部的div点击事件")
                },
                btnClick(){//按钮的点击事件
                    console.log("按钮的点击事件")
    
                }
            }
        });
    </script>
    </body>

    capture

    image-20210617123244400

    self

    image-20210617123300194

    once

    image-20210617123309616

    Vue指令之v-model双向数据绑定

    • v-bind: 指令只能实现数据的单项绑定,从data自动同步到view上
    • 在Vue中,只有v-model指令实现了数据的双向绑定,其他指令都是单向
    • 注意:v-model只能应用在表单元素中
    • 表单元素 例:input text radio checkbox textarea select

    简易计算器案例

    <body>
            <div id="app">
                <input type="text" v-model="n1">
                <select v-model="opt">
                    <option value="+">+</option>
                    <option value="-">-</option>
                    <option value="*">*</option>
                    <option value="/">/</option>
                </select>
                <input type="text" v-model="n2">
                <input type="button" value="=" @click="calc">
                <input type="text" v-model="result">
    
            </div>
    
            <script>
                let vue = new Vue({
                    el: '#app',
                    data: {
                        n1: 0,
                        opt: '+',
                        n2: 0,
                        result: 0,
                    },
                    methods: {
                        calc(){
                            /*switch (this.opt){
                                case "+":
                                    this.result = parseFloat(this.n1) + parseFloat(this.n2);
                                    break;
                                case "-":
                                    this.result = parseFloat(this.n1) - parseFloat(this.n2);
                                    break;
                                case "*":
                                    this.result = parseFloat(this.n1) * parseFloat(this.n2);
                                    break;
                                case "/":
                                    this.result = parseFloat(this.n1) / parseFloat(this.n2);
                                    break;
                            }*/
                            eval(`this.result = parseFloat(this.n1) ${this.opt} parseFloat(this.n2);`)
    
    
    
                        }
                    }
                });
    
            </script>
        </body>

    在Vue中使用样式

    使用class样式

    • 数组
      <h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
    • 数组中使用三元表达式
      <h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
    • 数组中嵌套对象
      <h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
    • 直接使用对象
      <h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>

    使用内联样式

    • 1.直接在元素上通过:style的形式,书写样式对象
      • <h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
    • 2.将样式对象,定义到 data中,并直接引用到:style
      • 在data上定义样式:
      • ```html
        data: {

        h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }

      }
      ```

      • 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
        <h1 :style="h1StyleObj">这是一个善良的H1</h1>
      1. 在 :style 中通过数组,引用多个 data 上的样式对象
        • 在data上定义样式:
          ```
          data: {
          h1StyleObj: { color: ‘red’, ‘font-size’: ‘40px’, ‘font-weight’: ‘200’ },
          h1StyleObj2: { fontStyle: ‘italic’ }
          }
        • 在元素中,通过属性绑定的形式,将样式对象应用到元素中: <h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>

    Vue指令之v-for和key属性

    • 1.迭代数组
    <ul>
      <li v-for="(item, i) in list">索引:{{i}} --- 姓名:{{item.name}} --- 年龄:{{item.age}}</li>
    </ul>
    • 2.迭代对象中的属性

    循环遍历对象身上的属性

    <div v-for="(val, key, i) in userInfo">{{val}} --- {{key}} --- {{i}}</div>
    • 3.迭代数字
    <p v-for="i in 10">这是第 {{i}} 个P标签</p>
         <ul>
                <!--今后,只要涉及到了v-for这种循环,推荐给循环的每一项添加:key属性-->
                <!--:key属性,只接受number或string类型的数据,不要直接为:key指定对象-->
                <!--:key 指定的值必须具有唯一性-->
                <li v-for="(item,i) in list" :key="item.id">
                    <input type="checkbox">
                    {{ item.id }}---{{ item.name }}---{{ i }}</li>
            </ul>

    2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。

    当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

    为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

    Vue指令之v-if和v-show

    • v-if和v-show只有一个作用,就是根据指定的标识符,切换元素的显示和隐藏状态
    • v-if是实时的创建和移除元素,从而达到元素的显示和隐藏
    • v-show是通过为元素 添加活移除 display:none 来实现隐藏和显示的
    • 一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。

    品牌管理案例

    Vue调试工具vue-devtools

    作业

        <style>
            .normal{
                color: blue;
            }
            .active{
                color: red;
                font-weight: bold;
            }
    
        </style>
        </head>
        <body>
    
        <div id="app">
            <ul>
                <li v-for="(item,i) in list" :key="item.id"
                    :class="['normal',{active:i == selectedIndex?true:false}]"
                @click="change(i)">
                    <input type="checkbox" :checked="i == selectedIndex">
                    {{item.id}},{{item.name}},{{item.age}},{{item.sex}}
                </li>
            </ul>
    
        </div>
        <script>
            let vue = new Vue({
                el: '#app',
                data: {
                    selectedIndex: 0,
                    list: [
                        {id: 1, name: '王五', age: 12, sex: '男'},
                        {id: 2, name: '张三', age: 13, sex: '男'},
                        {id: 3, name: '小红', age: 14, sex: '女'},
                    ]
                },
                methods: {
                    change(i){
                        this.selectedIndex = i
                    }
                }
            });
        </script>
        </body>

    过滤器

    • 过滤器的使用注意事项:
    • 1.Vue.filter(‘过滤器的名称’,’过滤器的处理函数’)
    • 2.注意:过滤器的处理函数中,第一个形参,功能已经被规定好了,永远都是管道符前面的值
    • 3.调用过滤器 {{ item.ctime | formatDate }}
    • 4.在调用过滤器的时候 可以传递参数{{ item.ctime | formatDate(‘传递参数’) }}
    • 5.注意:调用过滤器传递的参数 只能从处理函数的第二个形参开始接收 因为第一个形参已经被管道符前面的值给占用了
    • 6.注意:过滤器的处理函数中 必须返回一个值
    • 7.可以连续使用管道符 调用多个过滤器 最终输出的结果 永远以最后一个过滤器为准
    • 8.注意:过滤器只能使用在差值表达中 或者 v-bind中 不能使用在其他地方 比如v-text就不支持

    全局过滤器

    <label>{{cTime | dataFormat()}}</lable>
    
           // 定义一个全局过滤器
            Vue.filter('dataFormat', function (input, pattern = '') {
                var dt = new Date(input);
                // 获取年月日
                var y = dt.getFullYear();
                var m = (dt.getMonth() + 1).toString().padStart(2, '0');
                var d = dt.getDate().toString().padStart(2, '0');
    
                // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
                // 否则,就返回  年-月-日 时:分:秒
                if (pattern.toLowerCase() === 'yyyy-mm-dd') {
                    return `${y}-${m}-${d}`;
                } else {
                    // 获取时分秒
                    var hh = dt.getHours().toString().padStart(2, '0');
                    var mm = dt.getMinutes().toString().padStart(2, '0');
                    var ss = dt.getSeconds().toString().padStart(2, '0');
    
                    return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
                }
            });

    私有过滤器

    当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器

    <div id="app">
            <label>{{msg | msgFilter | addStr}}</label>
        </div>
    
        <script>
    
            Vue.filter('msgFilter',function (msg){
                // let s = msg.replace('纯洁','邪恶');
                //  /g是全部匹配
                let s = msg.replace(/纯洁/g,'邪恶');
                console.log(s)
                return s;
            });
    
            let vue = new Vue({
                el: '#app',
                data: {
                    msg: '曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁'
                },
                methods: {
                },
                filters:{
                    addStr:function (data) {
                        return data+'~~~~~~~~~~~~~~~';
                    },
                    //当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器
                    msgFilter:function (data) {
                        return data+'=============';
                    },
                }
            });
        </script>

    自定义指令

    官方文档:https://cn.vuejs.org/v2/guide/custom-directive.html

    全局自定义指令

            <label>搜索:
                <input type="text" @change="search" v-model="keywords" v-focus>
            </label>
    
        Vue.directive('focus',{
              //全局自定义 获得焦点的v-focus指令
            //Vue 自定义指令的名称中,不需要写v-前缀,但是,在调用自定义指令的时候,必须在起那么加上v-前缀
            //参数列表中的第一个参数,永远是el 表示被绑定指令的那个元素
            //如果要操作元素的样式,写到bind就行
            bind:function (el){//当指令绑定到的元素,被Vue实例解析的时候,就会立即执行bind函数
                // console.log(el)
                //el.focus();//如果想要让文本框获得焦点,那么,文本框必须先插入到文档中才能生效
                // el.style.color='red'
    
            },
            //今后在自定义指令的时候,如果需要操作元素的JS行为 最好写到inserted中
            inserted:function (el){//调用时机:当指令绑定到的元素,被插入到文档的父节点的时候,调用inserted函数
                // console.log('2 inserted执行了')
                el.focus();
            }
        })
    

    私有自定义指令

    <th  v-color="'green'" v-bold="1000" v-italic>操作</th>
    
    
    let vue = new Vue({
            el: '#app',
            data: {},
            methods: {},
            //私有过滤器
            filters:{},
            //私有指令
            directives:{
                //让指定元素字体加粗的指令
                bold:{
                    bind(el,binding){
                        console.log(binding.value)
                        el.style.fontWeight = binding.value
                    },
                    inserted(el){}
                },
                //让文字倾斜的指令
                italic:function (el,binding) {
                    //此处用到了指令函数的简写形式,如果指令给定的是function,
                    // 则等同于把这个function中的代码,
                    // 分别定义到了bind和update中去;
                    el.style.fontStyle="italic"
    
                }
            },
        });

    image-20210617123948684

    键盘修饰符

        <label>NAME:
                <input type="text" v-model="name" @keyup.enter="add">
        </label>

    vue实例的生命周期

    image-20210617124005356

    • 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
    • 生命周期钩子:就是生命周期事件的别名而已;
    • 生命周期钩子 = 生命周期函数 = 生命周期事件
    • 主要的生命周期函数分类:
      • 创建期间的生命周期函数:
      • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
      • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
      • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
      • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
      • 运行期间的生命周期函数:
      • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
      • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
      • 销毁期间的生命周期函数:
      • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
      • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="../day01/lib/vue-2.5.9.js"></script>
    </head>
    
    <body>
    <div id="app">
        <input type="button" value="ChangeMsg" @click="msg='数据被修改了'">
        <h3 id="myh3">{{ msg }}</h3>
    </div>
    
    <script>
    
        let vue = new Vue({
            el: '#app',
            data: {
                msg: 'message'
            },
            methods: {
                show(){
                    console.log('show方法被调用了')
                }
            },
            //第一个生命周期函数 【创建阶段】
            beforeCreate(){
                // console.log(this.msg)
                // this.show()
            },
            //第二个生命周期函数 【创建阶段】
            //当执行到created函数的时候,data和methods都已经初始化完毕了,此时,可以随意的去访问 其中的数据或方法了
            //结论:如果要操作data中的数据,或调用methods中的函数,最早,只能在created函数中进行。
            created(){
                console.log(this.msg)
                this.show()
            },
            //第三个生命周期函数 表示即将挂载  【创建阶段】
            //当模板页面被编译好之后,就会立即执行beforeMount这个函数
            //此时,我们的HTML代码结构,已经在内存中创建好了,但是,尚未挂载到页面中
            //结论:在这个函数中,页面上的DOM元素是原始的插值表达式之类的VUE代码
            beforeMount() {
                // let elementById = document.getElementById('myh3');
                // console.log(elementById.innerHTML)
            },
            //第四个生命周期函数,表示页面已经完成了渲染,
            // 同时,mounted函数的执行,标志着创建阶段的结束,从此以后,Vue实例,就从创建阶段,进入到运行阶段
            //结论:如果大家要引用一些第三方的插件来操作DOM元素了,最好在mounted中去操作DOM元素,因为这时候才是真正的页面
            mounted(){
               /* let elementById = document.getElementById('myh3');
                console.log(elementById.innerHTML)*/
            },
    
            beforeUpdate(){
                /*let elementById = document.getElementById('myh3');
                console.log(elementById.innerHTML)*/
            },
            updated(){
                let elementById = document.getElementById('myh3');
                console.log(elementById.innerHTML)
            }
        });
        //Vue的实例,也分为三个阶段:分别是创建阶段、运行阶段、销毁阶段
        //在实例运行的三个阶段中,总是伴随着各种各样的事件,那个,这些事件,统称为实例的生命周期函数(钩子函数、生命周期事件)
    </script>
    </body>
    </html>

    vue-resource 实现 get, post, jsonp请求

    使用vue-resource请求数据

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="lib/vue-2.5.9.js"></script>
        <!--vue-resource 只能在vue的后面导入-->
        <script src="lib/vue-resource-1.3.4.js"></script>
    </head>
    
    <body>
    <div id="app">
        <input type="button" value="Get请求" @click="getInfo">
        <input type="button" value="Post请求" @click="postInfo">
        <input type="button" value="jsonp请求" @click="jsonpInfo">
    </div>
    
    <script>
        let vue = new Vue({
            el: '#app',
            data: {},
            methods: {
                //get方式请求数据
                /*getInfo(){
                    this.$http.get("http://www.liulongbin.top:3005/api/getlunbo").then(function (data) {
                        console.log(data)
                        console.log(data.body)
                    })
                }*/
                async getInfo(){
                    // let data = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                    // console.log(data.body)
                    // 此处{ body } 是取data中的body节点的内容!!!
                    let { body } = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                    console.log(body)
                },
                async postInfo(){
                    let { body } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
                    console.log(body)
                },
                async jsonpInfo(){
                    let { body } = await this.$http.jsonp("http://www.liulongbin.top:3005/api/jsonp")
                    console.log(body)
                }
            }
        });
    </script>
    </body>
    </html>

    axios结合vue发起请求

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="lib/vue-2.5.9.js"></script>
        <script src="lib/axios-v0.17.1.js"></script>
    </head>
    
    <body>
    <div id="app">
        <input type="button" value="Get请求" @click="getInfo">
        <input type="button" value="Post请求" @click="postInfo">
        <!--axios 不支持发送jsonp请求-->
        <!--<input type="button" value="jsonp请求" @click="jsonpInfo">-->
    </div>
    
    <script>
        //把axios挂载到Vue构造函数的原型上
        Vue.prototype.$http = axios
        let vue = new Vue({
            el: '#app',
            data: {},
            methods: {
                async getInfo(){
                    // let result = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
                    // console.log(result)
    
                    // let {data} = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
                    // console.log(data)
    
                    let {data} = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                    console.log(data)
                },
    
                async postInfo(){
                    let { data } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
                    console.log(data)
                }
            }
        });
    </script>
    </body>
    </html>

    Vue中的动画

    使用过渡类名

    1. html结构
      <div id="app">
      <input type="button" value="动起来" @click="myAnimate">
      <!-- 使用 transition 将需要过渡的元素包裹起来 -->
      <transition name="fade">
        <div v-show="isshow">动画哦</div>
      </transition>
      </div>
    2. VM实例
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
      el: '#app',
      data: {
      isshow: false
      },
      methods: {
      myAnimate() {
        this.isshow = !this.isshow;
      }
      }
      });
    3. 定义两组类样式
      /* 定义进入和离开时候的过渡状态 */
      .fade-enter-active,
      .fade-leave-active {
        transition: all 0.2s ease;
        position: absolute;
      }
      
      /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
      .fade-enter,
      .fade-leave-to {
        opacity: 0;
        transform: translateX(100px);
      }

    使用第三方 CSS 动画库

    https://cn.vuejs.org/v2/guide/transitions.html#自定义过渡类名

    1. 导入动画类库
      <link rel="stylesheet" type="text/css" href="./lib/animate.css">
    2. 定义transition及属性
      <transition
      enter-active-class="fadeInRight"
      leave-active-class="fadeOutRight"
      :duration="{ enter: 500, leave: 800 }">
        <div class="animated" v-show="isshow">动画哦</div>
      </transition>

    使用动画钩子函数

    1. 定义 transition 组件以及三个钩子函数:
      <div id="app">
         <input type="button" value="加入购物车" @click="flag=!flag">
      
         <transition
          @before-enter="beforeEnter"
          @enter="enter"
          @after-enter="afterEnter">
             <div id="ball" v-show="flag"></div>
         </transition>
      </div>
    2. 定义三个 methods 钩子方法:
      let vue = new Vue({
             el: '#app',
             data: {
                 flag: false //显示的状态
             },
             methods: {
                 beforeEnter(el){//小球开始动画之前的起始状态
                     el.style.transform='translate(0,0)'
                 },
                 enter(el,done){//小球动画结束之后的结束状态
                     //这里是固定写法,如果不写el.offsetWidth就无法实现动画效果
                     el.offsetWidth
                     el.style.transform='translate(150px,300px)'
                     el.style.transition='all 1s ease'
                     //当动画执行完毕后,会自动调用done这个函数,这个done就是afterEnter函数的引用
                     done()
                 },
                 afterEnter(el){//小球动画结束之后的回调函数,用来做一些清理工作
                     this.flag = !this.flag
                 },
             }
         });

    v-for 的列表过渡

    https://cn.vuejs.org/v2/guide/transitions.html#列表的进入和离开过渡

    1. 定义过渡样式:
      <style>
      .list-enter,
      .list-leave-to {
        opacity: 0;
        transform: translateY(10px);
      }
      
      .list-enter-active,
      .list-leave-active {
        transition: all 0.3s ease;
      }
      </style>
    2. 定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
      <div id="app">
      <input type="text" v-model="txt" @keyup.enter="add">
      
      <transition-group tag="ul" name="list">
        <li v-for="(item, i) in list" :key="i">{{item}}</li>
      </transition-group>
      </div>
    3. 定义 VM中的结构:
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        data: {
          txt: '',
          list: [1, 2, 3, 4]
        },
        methods: {
          add() {
            this.list.push(this.txt);
            this.txt = '';
          }
        }
      });

    视频中代码:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <link rel="stylesheet" href="./lib/animate.css">
        <script src="lib/vue-2.5.9.js"></script>
        <script src="lib/axios-v0.17.1.js"></script>
    
        <style>
            ul{
                list-style: none;
                padding: 0;
                margin: 0;
            }
    
            li{
                line-height: 30px;
                border: 1px dashed #ccc;
                margin: 5px;
                font-size: 12px;
                padding-left: 10px;
                 500px;
                cursor: pointer;
            }
            li:hover{
                background-color: orange;
                box-shadow: 0 0 7px gray;
                /*transition: all 0.6s ease;*/
            }
    
            .v-enter,
            .v-leave-to{
                opacity: 0;
                transform: translateY(200px);
            }
    
            .v-enter-active,
            .v-leave-active{
                transition: all 0.5s ease;
            }
    
            .v-move{/*让元素被改变定位的时候,有一个缓动效果*/
                transition: all 0.5s ease;
            }
    
            .v-leave-active{/*表示要被删除的哪个元素,让即将被移除的元素,脱离标准流,这样,后面的元素就能渐渐的浮动上来*/
                position: absolute;
            }
        </style>
    </head>
    
    
    <body>
    <div id="app">
    
        <div>
            Id: <input type="text" v-model="id">
            Name: <input type="text" v-model="name">
            <input type="button" value="添加" @click="add">
        </div>
    
        <transition-group tag="ul">
            <li v-for="(item,i) in list" :key="item.id" @click="remove(i)">{{item.id}}-- {{item.name}}</li>
        </transition-group>
    </div>
    
    <script>
        let vue = new Vue({
            el: '#app',
            data: {
                list: [
                    {id: 1,name: '高军军'},
                    {id: 2,name: '付哥哥'},
                    {id: 3,name: '玉姐姐'},
                    {id: 4,name: '斌哥哥'}
                ],
                id: '',
                name: ''
            },
            methods: {
                remove(i){
                    this.list.splice(i,1)
                },
                add(){
                    const p = {id: this.id,name: this.name}
                    // this.list.push(p)
                     this.list.unshift(p)//放最前面
                    this.id = this.name = ''
                }
            }
        });
    </script>
    </body>
    </html>

    列表的排序过渡

    <transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用

    • v-movev-leave-active 结合使用,能够让列表的过渡更加平缓柔和:
      .v-move{
      transition: all 0.8s ease;
      }
      .v-leave-active{
      position: absolute;
      }

    演示transition中name属性的重要性

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <link rel="stylesheet" href="./lib/animate.css">
        <script src="lib/vue-2.5.9.js"></script>
        <script src="lib/axios-v0.17.1.js"></script>
    
        <style>
            .v-enter,
            .v-leave-to{
                opacity: 0;
                transform: translateX(100px);
            }
    
            .v-enter-active,
            .v-leave-active{
                transition: all 0.4s ease;
            }
    
            .fade-enter,
            .fade-leave-to{
                opacity: 0;
                transform: translateX(100px);
            }
    
            .fade-enter-active,
            .fade-leave-active{
                transition: all 3s ease;
            }
    
        </style>
    </head>
    
    <body>
    <div id="app">
        <input type="button" value="Toggle" @click="flag=!flag">
        <transition>
        <h3 v-show="flag">111111111</h3>
        </transition>
    
        <hr>
    
        <input type="button" value="Toggle" @click="flag2=!flag2">
        <transition name="fade">
            <h3 v-show="flag2">111111111</h3>
        </transition>
    
    </div>
    
    <script>
        let vue = new Vue({
            el: '#app',
            data: {
                flag: true,
                flag2: true
            }
        });
    </script>
    </body>
    </html>

    Day02

    定义Vue组件

    • 什么是模块化:模块化是从代码的角度出发,分析项目,把项目中一些功能类似的代码,单独的抽离为一个个的模块;那么为了保证大家以相同的方式去封装模块,于是我们就创造了模块化的规范(CommonJS规范);
      • 模块化的好处:方便项目的开发;和后期的维护与扩展;今后如果需要某些固定功能的模块,则直接拿来引用就行,提高了项目开发效率!
    • 什么是组件化:从UI的角度出发考虑问题,把页面上有重用性的UI解构和样式,单独的抽离出来,封装为单独的组件;
      • 组件化的好处:随着项目规模的发展,我们手里的组件,会越来越多,这样,我们今后一个页面中的UI,几乎都可以从手中拿现成的组件拼接出来;方便项目的开发和维护;

    全局组件定义的三种方式

    第一种方式:

    1. 先调用 Vue.extend() 得到组件的构造函数:
      // 创建全局组件的第一种方式:   component
      const com1 = Vue.extend({
        template: '<h1>这是创建的第一个全局组件</h1>' // template 属性,表示这个组件的 UI 代码解构
      })
    2. 通过 Vue.component('组件的名称', 组件的构造函数) 来注册全局组件:
      // 使用 Vue.component 向全局注册一个组件
      // Vue.component('组件的名称', 组件的构造函数)
      Vue.component('mycom1', com1)
    3. 把注册好的全局组件名称,以标签形式引入到页面中即可:
      <!-- 如何引入一个全局的Vue组件呢? 直接把 组件的名称,以标签的形式,放到页面上就好了! -->
      <mycom1></mycom1>

    第二种方式:

    1. 直接使用 Vue.component('组件名称', { 组件模板对象 })
      const com2Obj = {
        // 1. template 属性中,不能单独放一段文本,必须用标签包裹起来;
        // 2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹;
        template: '<div><h2>这是直接使用 Vue.component 创建出来的组件</h2><h3>红红火火</h3></div>'
      }
      
      // 定义全局的组件
      // Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象
      Vue.component('mycom2', com2Obj)

    第三种方式:

    1. 先使用template标签定义一个模板的代码解构:
      <!-- 定义一个 template 标签元素  -->
      <!-- 使用 Vue 提供的 template 标签,可以定义组件的UI模板解构 -->
      <template id="tmpl">
      <div>
        <h3>哈哈,这是在外界定义的组件UI解构</h3>
        <h3>我是来捣乱的</h3>
      </div>
      </template>
    2. 使用Vue.component注册组件:
      // 这是定义的全局组件
      Vue.component('mycom3', {
        template: '#tmpl'
      })

    注意: 从更抽象的角度来说,每个组件,就相当于是一个自定义的元素; 注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

    定义私有组件

        const vm = new Vue({
            el: '#app',
            data: {},
            methods: {},
            components: {//定义实例中私有组件的 组件名称 和组件结构
                'mycom4': {
                    template: '<h6>啦啦啦啦啦啦</h6>'
                }
            }
        })

    组件中展示数据和响应事件

    Vue.component('mycom', {
          template: '<h3 @click="show">这是自定义的全局组件:{{ msg }}</h3>',
          data: function () { // 在 组件中,可以有自己的私有数据,但是,组件的 data 必须是一个 function,并且内部 return 一个 数据对象
            return {
              msg: '哈哈哈'
            }
          },
          methods: { // 尝试定义组件的私有方法
            show() {
              console.log('触发了组件的私有show方法!')
            }
          }
        })

    【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象

    通过计数器案例演示

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <!--1.导入Vue包-->
        <script src="../day01/lib/vue-2.5.9.js"></script>
    </head>
    
    <body>
    <!--2.创建要控制的区域-->
    <div id="app">
        <counter></counter>
        <counter></counter>
    </div>
    
    <script>
        const o = { count: 0 }
        //定义全局的组件
        //Vue.component的第二个参数,即接收组件的构造函数,同时也接收组件的一个对象
        Vue.component('counter', {
            template: `<div>
                        <input type="button" value="+1" @click="add">
                        <h3>当前count值为:{{count}}</h3>
                       </div>`,
            //为什么要把组件中的data定义为一个function呢?因为这样做的话,每当我们在页面上引用一次组件,
            // 必然会先调用这个data function,从而得到一个当前组件私有的数据对象;
            data: function (){
                //这是官方推荐的
                return {
                    count: 0
                }
    
                //这是自己改造后的形式
                //如果使用此种方式,当我们在页面上多次引用组件时,o始终是同一个对象,就会造成数据联动!!!
                // return o;
            },
            methods: {
                add(){//点击按钮让组件的count值自增+1
                    this.count++
                }
            }
        })
        const vm = new Vue({
            el: '#app',
            data: {},
            methods: {}
        })
    </script>
    
    
    </body>
    </html>

    使用flag标识符结合v-ifv-else切换组件

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <!--1.导入Vue包-->
        <script src="../day01/lib/vue-2.5.9.js"></script>
    </head>
    
    <body>
    <!--2.创建要控制的区域-->
    <div id="app">
        <input type="button" value="显示登录" @click="flag=true">
        <input type="button" value="显示注册" @click="flag=false" >
    
        <login v-if="flag"></login>
        <reg v-else="flag"></reg>
    </div>
    
    <script>
        Vue.component('login',{
            template: `<h3>登录模块1</h3>`
        })
    
        Vue.component('reg',{
            template: `<h3>注册模块2</h3>`
        })
        const vm = new Vue({
            el: '#app',
            data: {
                flag: true
            },
            methods: {}
        })
    </script>
    </body>
    </html>

    使用component标签的:is属性来切换组件,并添加动画

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="../day01/lib/vue-2.5.9.js"></script>
    
        <style>
            .v-enter{
                /*即将进入时候的坐标*/
                opacity: 0;
                transform: translateX(100px);
            }
    
            .v-leave-to{
                /*离开时候,最终到达的位置*/
                opacity: 0;
                transform: translateX(-100px);
            }
    
            .v-enter-active,
            .v-leave-active{
                transition: all 0.4s ease;
                position: absolute;
            }
        </style>
    
    </head>
    
    <body>
    <div id="app">
        <!--transition transition-group template component-->
        <!--通过component的:is属性 可以显示指定【名称】的组件-->
        <!--<component :is="componentId"></component>-->
        <a href="#" @click="comId='com1'">显示组件1</a> <br>
        <a href="#" @click="comId='com2'">显示组件2</a> <br>
        <a href="#" @click="comId='com3'">显示组件3</a> <br>
        <a href="#" @click="comId='com4'">显示组件4</a> <br>
    
        <!--mode="out-in"先离开之后再进入-->
        <transition mode="out-in">
         <component :is="comId"></component>
        </transition>
    </div>
    
    <script>
        Vue.component('com1',{
            template: `<h3>组件1-</h3>`
        })
        Vue.component('com2',{
            template: `<h3>组件2--</h3>`
        })
        Vue.component('com3',{
            template: `<h3>组件3---</h3>`
        })
        Vue.component('com4',{
            template: `<h3>组件4----</h3>`
        })
        const vm = new Vue({
            el: '#app',
            data: {
                comId: 'com1'
            },
            methods: {}
        })
    </script>
    </body>
    </html>

    父组件向子组件传值

    父组件向子组件传递普通数据和对象

    <div id="app">
        <!--父组件如果想给子组件传递数据,则需要使用属性绑定的形式-->
        <!--这样,子组件身上的自定义数据 就是你要传递给子组件的数据-->
        <com1 :obj="msgObj" :value="parentMsg"></com1>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                parentMsg: '普通值',
                msgObj: {//对象
                    address: '北京',
                    location: '顺义---马坡南'
                }
            },
            methods: {},
            components: {
                'com1': {
                    template: `<h3>好好 {{obj}} ---- {{value}}</h3>`,
                    props: ['obj','value']
                }
            }
        })
    </script>

    父组件向子组件传递方法

    <div id="app">
        <!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
        <!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
        <com1 @showme="show"></com1>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {},
            methods: {
                show(){
                    console.log('有人调用了父组件中的show方法')
                }
            },
            components: {
                'com1': {
                    <!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
                    template: `<div>
                                <input type="button" value="这是子组件的按钮" @click="btnClick">
                               </div>`,
                    methods: {
                        btnClick(){
                            //console.log('okok');
                            //调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
                            this.$emit('showme')
                        }
                    }
                }
            }
        })
    </script>

    子组件向父组件传值

    <div id="app">
        <!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
        <!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
        <com1 @showme="show"></com1>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msgFormSon: ''
            },
            methods: {
                show(arg1){
                    // console.log('有人调用了父组件中的show方法' + arg1)
                    //把子组件传递过来的数据,保存到父组件的data中
                    this.msgFormSon = arg1
                    console.log(this.msgFormSon)
                }
            },
            components: {
                'com1': {
                    <!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
                    template: `<div>
                                <input type="button" value="这是子组件的按钮" @click="btnClick">
                               </div>`,
                    data(){
                        return {
                            sonMsg: '这是子组件中的数据'
                        }
    
                    },
                    methods: {
                        btnClick(){
                            //console.log('okok');
                            //调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
                            //子组件向父组件传值本质上还是调用了父组件传递过来的方法,只不过,子组件在调用的时候把数据当做参数,传给这个方法了
                            this.$emit('showme',this.sonMsg)
                        }
                    }
                }
            }
        })
    </script>

    评论列表案例

    目标:主要练习父子组件之间传值

    <body>
    <div id="app">
        <cmt-box @add="addNewCnt"></cmt-box>
    
        <ul>
            <cmt-item v-for="(item,i) in list" :key="i" :item="item"></cmt-item>
        </ul>
    </div>
    <script>
        Vue.component('cmt-item',{
            template: `<ul>
                          <li>
                            <h3>评论人:{{ item.name }}</h3>
                            <h5>评论内容:{{ item.content }}</h5>
                          </li>
                       </ul>`,
            props:["item"]
    
        })
    
        Vue.component('cmt-box',{
            template: `
            <div>
                <label>评论人:</label>
                <br>
                <input type="text" v-model="name">
                <br>
                <label>评论内容:</label>
                <br>
                <textarea v-model="content"></textarea>
                <br>
                <input type="button" value="发表评论" @click="postComment">
            </div>`,
            data: function() {
                return {
                    name: '',
                    content: ''
                }
            },
            methods: {
                postComment(){//发表评论
                    const cmt = {name: this.name,content: this.content}
                    this.$emit('add',cmt)
                }
            },
        })
    
        const vm = new Vue({
            el: '#app',
            data: {
                list: [
                    {name:'张三',content:'沙发1'},
                    {name:'111',content:'沙发2'},
                    {name:'qqq',content:'沙发3'},
                    {name:'eee',content:'沙发4'}
                ]
            },
            methods: {
                addNewCnt(obj){//添加新评论
                     console.log('okokok')
                    this.list.push(obj)
                }
            }
        })
    </script>
    </body>
    

    使用this.$refs来获取元素

    <div id="app">
        <input type="button" value="点击获取元素的内容" @click="getInfo" ref="btn">
        <h3 ref="myh3">{{msg}}</h3>
    </div>
    <script>
    
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '000'
            },
            methods: {
                getInfo(){//点击按钮,获取H3中的文本内容
                    console.log(this.$refs.myh3.innerHTML)
                    console.log(this.$refs.btn.value)
                }
            }
        })
    </script>

    使用this.$refs来获取组件

    <body>
    <div id="app">
        <input type="button" value="获取页面上的组件" @click="getCom">
        <com1 ref="mycom"></com1>
    </div>
    <script>
        Vue.component('com1',{
            template: `
                <h3>这是一个小组件 {{msg}}</h3>
            `,
            data: function (){//子组件的私有数据
                return {
                    msg: 'ok'
                }
            },
            methods: {//子组件的方法
                show(){
                    console.log('有人调用了子组件的方法')
                }
            }
        })
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '000'
            },
            methods: {
                getCom(){
                    // console.log(this)
                    //修改子组件上的数据
                    // this.$refs.mycom.msg = '123'
                    //调用子组件中的方法
                    this.$refs.mycom.show()
                }
            }
        })
    </script>
    </body>

    在Vue组件中data和props的区别

    1. data 在组件中,要被定义成function并返回一个对象
    2. props 在组件中,要被定义成数组,其中,数组的值都是字符串名,表示父组件传递过来的数据;
    3. props 的数据,不要直接拿来修改,如果想要修改,必须在 data 上重新定义一个 属性,然后把属性的值 从 this.props 拿过来;

    data 上的数据,都是组件自己私有的, data 上的数据,都是可读可写的 props 数据,都是外界传递过来的数据, props 中的数据只能读取,不能重新写入

    什么是路由

    1. 对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
    2. 对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
    3. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);
    4. 前端的路由:就是根据不同的Hash地址,在页面上展示不同的前端组件;

    在 vue 中使用 vue-router

    1. 导入 vue-router 组件类库:
      <!-- 1. 导入 vue-router 组件类库 -->
      <script src="./lib/vue-router-2.7.0.js"></script>
    2. 使用 router-link 组件来导航
      <!-- 2. 使用 router-link 组件来导航 -->
      <router-link to="/login">登录</router-link>
      <router-link to="/register">注册</router-link>
    3. 使用 router-view 组件来显示匹配到的组件
      <!-- 3. 使用 router-view 组件来显示匹配到的组件 -->
      <router-view></router-view>
    4. 创建使用Vue.extend创建组件
      // 4.1 使用 Vue.extend 来创建登录组件
      var login = Vue.extend({
        template: '<h1>登录组件</h1>'
      });
      
      // 4.2 使用 Vue.extend 来创建注册组件
      var register = Vue.extend({
        template: '<h1>注册组件</h1>'
      });
    5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
      // 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
      var router = new VueRouter({
        routes: [
          { path: '/login', component: login },
          { path: '/register', component: register }
        ]
      });
    6. 使用 router 属性来使用路由规则
      // 6. 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        router: router // 使用 router 属性来使用路由规则
      });

    设置路由高亮 linkActiceClass

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="./lib/vue-2.5.9.js"></script>
        <!-- 1. 导入路由JS文件 -->
        <script src="./lib/vue-router-v3.0.1.js"></script>
    
        <style>
            .router-link-active {
                color: red;
                font-weight: bold;
                font-style: italic;
                font-size: 20px;
                text-decoration: underline;
            }
            .my-active {
                color: orange;
                font-size: 30px;
            }
        </style>
    </head>
    
    <body>
    <div id="app">
        <!-- 路由链接 -->
        <router-link to="/login">登录</router-link>
        <router-link to="/reg">注册</router-link>
    
        <!-- 展示路由组件的容器 -->
        <router-view></router-view>
    </div>
    
    <script>
        //2.定义两个要切换的组件
        const login = {
            template: '<h3>登录组件</h3>'
        }
        const reg = {
            template: '<h3>登录组件</h3>'
        }
        //3. 创建路由对象
        const router = new VueRouter({
            routes: [//路由规则的数组
                // { path: '/', component: login },
                { path: '/', redirect: '/login' },     // node 的 express 框架中,有 res.redirect('/login')
                {path: '/login',component: login},
                {path: '/reg',component: reg},
            ],
            linkActiceClass: 'my-actice' //配置默认被选中路由的高亮类名,默认类名为 router-link-actice
        })
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {},
            router // 4. 把路由对象,挂载到 VM 实例上
        });
    </script>
    </body>
    
    </html>

    设置路由切换动效

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="./lib/vue-2.5.9.js"></script>
        <!-- 1. 导入路由JS文件 -->
        <script src="./lib/vue-router-v3.0.1.js"></script>
    
        <style>
            .router-link-active {
                color: red;
                font-weight: bold;
                font-style: italic;
                font-size: 20px;
                text-decoration: underline;
            }
            .my-active {
                color: orange;
                font-size: 30px;
            }
            .v-enter,
            .v-leave-to {
                opacity: 0;
                transform: translateX(100px);
            }
            .v-enter-active,
            .v-leave-active {
                transition: all 0.3s ease;
                position: absolute;
            }
        </style>
    </head>
    
    <body>
    <div id="app">
        <!-- 路由链接 -->
        <router-link to="/login">登录</router-link>
        <router-link to="/reg">注册</router-link>
    
        <!-- 展示路由组件的容器 -->
        <transition>
            <router-view></router-view>
        </transition>
    </div>
    
    <script>
        // 2. 定义两个要切换的组件
        const login = {
            template: '<h3>登录组件</h3>'
        }
        const reg = {
            template: '<h3>注册组件</h3>'
        }
        // 3. 创建路由对象
        const router = new VueRouter({
            routes: [ // 路由规则的数组
                // { path: '/', component: login },
                { path: '/', redirect: '/login' },     // node 的 express 框架中,有 res.redirect('/login')
                { path: '/login', component: login },
                { path: '/reg', component: reg }
            ],
            linkActiveClass: 'my-active' // 配置默认被 选中路由的高亮类名的 , 默认类名为 router-link-active
        })
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {},
            router // 4. 把路由对象,挂载到 VM 实例上
        });
    </script>
    </body>
    
    </html>

    路由传参

    ?拼接传参

    <div id="app">
        <!-- 路由链接 -->
        <router-link to="/login?id=10">登录</router-link>
        <router-link to="/reg">注册</router-link>
    
        <!-- 展示路由组件的容器 -->
        <transition>
          <router-view></router-view>
        </transition>
      </div>
    
      <script>
        // 2. 定义两个要切换的组件
        const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
          template: '<h3>登录组件----{{$route.query.id}}</h3>',
          created() {
            console.log(this.$route.query)
            console.log(this.$route.query.id)
          }
        }
        const reg = {
          template: '<h3>注册组件</h3>'
        }
    
        // 3. 创建路由对象
        const router = new VueRouter({
          routes: [ // 路由规则的数组
            { path: '/', redirect: '/login' },
            { path: '/login', component: login },
            { path: '/reg', component: reg }
          ],
          linkActiveClass: 'my-active'
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          router // 4. 把路由对象,挂载到 VM 实例上
        });
      </script>

    在路由规则中定义参数

    <body>
      <div id="app">
        <!-- 路由链接 -->
        <router-link to="/login/10/zs">登录</router-link>
        <router-link to="/reg">注册</router-link>
    
        <!-- 展示路由组件的容器 -->
        <transition>
          <router-view></router-view>
        </transition>
      </div>
    
      <script>
        // 2. 定义两个要切换的组件
        const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
          template: '<h3>登录组件----{{ $route.params.id }} --- {{ $route.params.name }}</h3>',
          created() {
            console.log(this.$route)
          }
        }
        const reg = {
          template: '<h3>注册组件</h3>'
        }
    
        // 3. 创建路由对象
        const router = new VueRouter({
          routes: [ // 路由规则的数组
            { path: '/', redirect: '/login' },
            { path: '/login/:id/:name', component: login },
            { path: '/reg', component: reg }
          ],
          linkActiveClass: 'my-active'
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          router // 4. 把路由对象,挂载到 VM 实例上
        });
      </script>

    路由中使用prop获取参数

    { path: '/login/:id/:name', component: login ,props: true},
    const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
            props: ['name','id'],
            template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
            created() {
                console.log(this.$route)
            }
        }
    <div id="app">
        <!-- 路由链接 -->
        <router-link to="/login/10/zs">登录</router-link>
        <router-link to="/reg">注册</router-link>
    
        <!-- 展示路由组件的容器 -->
        <transition>
            <router-view></router-view>
        </transition>
    </div>
    
    <script>
        // 2. 定义两个要切换的组件
        const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
            props: ['name','id'],
            template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
            created() {
                console.log(this.$route)
            }
        }
        const reg = {
            template: '<h3>注册组件</h3>'
        }
        // 3. 创建路由对象
        const router = new VueRouter({
            routes: [ // 路由规则的数组
                { path: '/', redirect: '/login' },
                { path: '/login/:id/:name', component: login ,props: true},
                { path: '/reg', component: reg }
            ],
            linkActiveClass: 'my-active'
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {},
            router // 4. 把路由对象,挂载到 VM 实例上
        });
    </script>

    使用 children 属性实现路由嵌套

    <div id="app">
        <router-link to="/account">Account</router-link>
    
        <router-view></router-view>
      </div>
    
      <script>
        // 父路由中的组件
        const account = Vue.extend({
          template: `<div>
            这是account组件
            <router-link to="/account/login">login</router-link> | 
            <router-link to="/account/register">register</router-link>
            <router-view></router-view>
          </div>`
        });
    
        // 子路由中的 login 组件
        const login = Vue.extend({
          template: '<div>登录组件</div>'
        });
    
        // 子路由中的 register 组件
        const register = Vue.extend({
          template: '<div>注册组件</div>'
        });
    
        // 路由实例
        var router = new VueRouter({
          routes: [
            { path: '/', redirect: '/account/login' }, // 使用 redirect 实现路由重定向
            {
              path: '/account',
              component: account,
              children: [ // 通过 children 数组属性,来实现路由的嵌套
                { path: 'login', component: login }, // 注意,子路由的开头位置,不要加 / 路径符
                { path: 'register', component: register }
              ]
            }
          ]
        });
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          components: {
            account
          },
          router: router
        });
      </script>

    命名视图实现经典布局

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script src="./lib/vue-2.5.9.js"></script>
      <script src="./lib/vue-router-v3.0.1.js"></script>
      <style>
        html,
        body,
        h1 {
          margin: 0;
          padding: 0;
          font-size: 20px;
        }
    
        .header {
          height: 120px;
          background-color: darkcyan;
        }
    
        .container {
          height: 400px;
          display: flex;
        }
    
        .sidebar {
          background-color: orange;
          flex: 2;
        }
    
        .content {
          background-color: pink;
          flex: 10;
        }
    
        .footer {
          background-color: black;
          color: white;
          height: 100px;
        }
      </style>
    </head>
    
    <body>
      <div id="app">
        <!-- 路由的容器 -->
        <router-view name="top"></router-view>
        <div class="container">
          <router-view name="left"></router-view>
          <router-view name="right"></router-view>
        </div>
        <router-view name="bottom"></router-view>
      </div>
    
      <script>
    
        const header = {
          template: `<h1 class="header">头部区域</h1>`
        }
        const sidebar = {
          template: `<h1 class="sidebar">左侧侧边栏</h1>`
        }
        const content = {
          template: `<h1 class="content">主体内容区域</h1>`
        }
        const footer = {
          template: `<h1 class="footer">尾部</h1>`
        }
    
        const router = new VueRouter({
          routes: [
            // { path: '/', component: header }
            {
              path: '/', components: {
                //     组件名称 :  组件对象
                'top': header,
                'left': sidebar,
                'right': content,
                'bottom': footer
              }
            }
          ]
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          router
        });
      </script>
    </body>
    
    </html>

    watch属性的使用

    考虑一个问题:想要实现 两个文本框的内容改变,则全名的文本框中的值也跟着改变;(用以前的知识如何实现???)

    1. 场景一:watch监听data中属性的改变:
      <div id="app">
      <input type="text" v-model="firstName"> +
      <input type="text" v-model="lastName"> =
      <span>{{fullName}}</span>
      </div>
      
      <script>
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        data: {
          firstName: 'jack',
          lastName: 'chen',
          fullName: 'jack - chen'
        },
        methods: {},
        watch: {
          'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据
            this.fullName = newVal + ' - ' + this.lastName;
          },
          'lastName': function (newVal, oldVal) {
            this.fullName = this.firstName + ' - ' + newVal;
          }
        }
      });
      </script>
    2. 场景二:watch监听路由对象的改变:
      <div id="app">
      <router-link to="/login">登录</router-link>
      <router-link to="/register">注册</router-link>
      
      <router-view></router-view>
      </div>
      
      <script>
      var login = Vue.extend({
        template: '<h1>登录组件</h1>'
      });
      
      var register = Vue.extend({
        template: '<h1>注册组件</h1>'
      });
      
      var router = new VueRouter({
        routes: [
          { path: "/login", component: login },
          { path: "/register", component: register }
        ]
      });
      
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router: router,
        watch: {
          '$route': function (newVal, oldVal) {
            if (newVal.path === '/login') {
              console.log('这是登录组件');
            }
          }
        }
      });
      </script>

    computed计算属性的使用

    1. 默认只有getter的计算属性:
      <div id="app">
      <input type="text" v-model="firstName"> +
      <input type="text" v-model="lastName"> =
      <span>{{ fullName }}</span>
      </div>
      
      <script>
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        data: {
          firstName: 'jack',
          lastName: 'chen'
        },
        methods: {},
        computed: { // 计算属性; 特点:当计算属性中所以来的任何一个 data 属性改变之后,都会重新触发 本计算属性 的重新计算,从而更新 fullName 的值
          fullName() {
            return this.firstName + ' - ' + this.lastName;
          }
        }
      });
      </script>
    2. 定义有gettersetter的计算属性:
      <div id="app">
      <input type="text" v-model="firstName">
      <input type="text" v-model="lastName">
      <!-- 点击按钮重新为 计算属性 fullName 赋值 -->
      <input type="button" value="修改fullName" @click="changeName">
      
      <span>{{fullName}}</span>
      </div>
      
      <script>
      // 创建 Vue 实例,得到 ViewModel
      var vm = new Vue({
        el: '#app',
        data: {
          firstName: 'jack',
          lastName: 'chen'
        },
        methods: {
          changeName() {
            this.fullName = 'TOM - chen2';
          }
        },
        computed: {
          fullName: {
            get: function () {
              return this.firstName + ' - ' + this.lastName;
            },
            set: function (newVal) {
              var parts = newVal.split(' - ');
              this.firstName = parts[0];
              this.lastName = parts[1];
            }
          }
        }
      });
      </script>

    watchcomputedmethods之间的对比

    1. computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
    2. methods方法表示一个具体的操作,主要书写业务逻辑;
    3. watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computedmethods的结合体;
  • 相关阅读:
    线段树(已修改+补题
    畅通工程
    线段树
    charles
    flash
    mysql node pool
    node简单操作mysql的类
    小于任意数字的随机数
    文件系统的移植
    驱动
  • 原文地址:https://www.cnblogs.com/doagain/p/14969036.html
Copyright © 2011-2022 走看看