Vue核心(三)

在这里插入图片描述

Vue核心知识点(三)

前言

本博客是对以下视频教程做的一个笔记总结,这个笔记和视频不是一一对应的,但可作为参考,不喜勿喷。

2021最新Vue迅速上手教程丨vue3.0入门到精通

本博客是Vue核心知识点的第三篇,第二篇在这儿:Vue核心(二) 。由于内容太多,分三篇来写。

如果对你有所帮助,欢迎点赞,评论,转发。

这篇博客的主要内容有:

  • v-for(列表渲染)深入了解。
  • Vue数据监测原理分析。
  • Vue生命周期。

1、v-for(列表渲染)深入了解

这里主要是对v-for中,key的原理进行分析。

1.1 示例代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>key的原理</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h3>遍历数组</h3>
    <!--once: 只调用一次函数-->
    <button @click.once="add">添加一个老王</button>
    <ul>
        <!--index作为key-->
        <!--<li v-for="(p,index) of persons" :key="index">
            {{p.name}}&#45;&#45;{{p.age}}
            <input type="text">
        </li>-->

        <!--id作为key(id是唯一的)-->
        <li v-for="(p,index) in persons" :key="p.id">
            {{p.name}}--{{p.age}}
            <input type="text">
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                //每条数据的id是全局唯一的
                persons: [
                    {id: '001', name: '张三', age: 18},
                    {id: '002', name: '李四', age: 19},
                    {id: '003', name: '王五', age: 20},
                ]
            };
        },
        methods: {
            add() {
                console.log("add...");
                let p = {id: '004', name: '老王', age: 22};
                /*往数组头插入元素*/
                this.persons.unshift(p);
            }
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
</script>
</html>

1.2 key原理分析

1、index作为key

手动在后面的输入框中输入内容,如下:

在这里插入图片描述

往数组头添加一个老王之后:

在这里插入图片描述

很显然,出现了问题,元素的顺序出现了问题

原理如下:

在这里插入图片描述

2、id作为key

还是之前的数据,在数组头插入一个老王之后,如下图:

在这里插入图片描述

可以看到,下面的数据并没有发生混乱

原理如下:

在这里插入图片描述

1.3 总结

面试题:React、Vue中的key有什么作用?(key的内部原理)

  • 虚拟DOM中key的作用:

    • key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,

    • 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

    • 对比规则:

      1. 旧虚拟DOM中找到了与新虚拟DOM相同的key:

        • ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!

        • ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

      2. 旧虚拟DOM中未找到与新虚拟DOM相同的key:

        • ①.创建新的真实DOM,随后渲染到到页面。
  • 用index作为key可能会引发的问题:

    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作,
    • 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
    • 如果结构中还包含输入类的DOM:
    • 会产生错误DOM更新 ==> 界面有问题。
  • 开发中如何选择key?

    • 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
    • 使用index作为key是没有问题的。

1.4 案例_过滤列表

输入名字,显示对应的人。

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>列表过滤</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <!--输入名字进行人员查找-->
    <input type="text" placeholder="请输入名字" v-model="keyWord"/>
    <ul>
        <li v-for="(p,index) of filPersons" :key="p.id">
            {{p.name}}--{{p.age}}--{{p.sex}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    /*方式一:watch实现*/
    /*const vm = new Vue({
        data() {
            return {
                keyWord: "",
                persons: [
                    {id: '001', name: '胡歌', age: 19, sex: '男'},
                    {id: '002', name: '周冬雨', age: 20, sex: '女'},
                    {id: '003', name: '赵丽颖', age: 21, sex: '女'},
                    {id: '004', name: '杨幂', age: 22, sex: '女'}
                ],
                filPersons: []
            };
        },
        watch: {
            keyWord: {
                immediate: true, //初始化调用一次 handler
                handler(newValue) {
                    this.filPersons = this.persons.filter((p) => {
                        //对name进行字符串匹配
                        let result = p.name.indexOf(newValue) !== -1;
                        console.log(result); //结果是布尔值(true or false)
                        return result;
                    });
                },
            }
        }
    });
    /!*挂载Vue实例到root容器上*!/
    vm.$mount('#root');*/

    /*用computed实现*/
    new Vue({
        el: '#root',
        data: {
            keyWord: "",
            persons: [
                {id: '001', name: '胡歌', age: 19, sex: '男'},
                {id: '002', name: '周冬雨', age: 20, sex: '女'},
                {id: '003', name: '赵丽颖', age: 21, sex: '女'},
                {id: '004', name: '杨幂', age: 22, sex: '女'}
            ],
        },
        //注意!!!!!巨坑!!!!computed是和data同级的!!!!
        computed: {
            /*普通写法*/
            /*filPersons: {
                get() {
                    return this.persons.filter((p) => {
                        return p.name.indexOf(this.keyWord) !== -1;
                    });
                }
            }*/

            /*简写*/
            filPersons() {
                return this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                });
            }
        }
    });
</script>
</html>

1.5 案例_列表排序

对列表进行升序,降序排列,也可以恢复原顺序。

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>列表过滤</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button @click="sortType=2">年龄升序</button>
    <button @click="sortType=1">年龄降序</button>
    <button @click="sortType=0">年龄原顺序</button>
    <ul>
        <li v-for="(p,index) of filPersons" :key="p.id">
            {{p.name}}--{{p.age}}--{{p.sex}}
        </li>
    </ul>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                keyWord: '',
                sortType: 0, //0原顺序 1降序 2升序
                persons: [
                    {id: '003', name: '赵丽颖', age: 21, sex: '女'},
                    {id: '002', name: '周冬雨', age: 20, sex: '女'},
                    {id: '005', name: '王老胡', age: 23, sex: '男'},
                    {id: '004', name: '杨幂', age: 22, sex: '女'},
                    {id: '001', name: '胡歌', age: 19, sex: '男'},
                ],
            };
        },
        //注意!!computed和data是同级的!!!
        computed: {
            filPersons() {
                let arr = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                });
                //判断一下是否需要排序(0表示不排序,不会进入处理逻辑)
                if (this.sortType) {
                    arr.sort((p1, p2) => {
                        //p2.age - p1.age降序,p1.age - p2.age升序
                        return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
                    });
                }
                return arr;
            }
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
</script>
</html>

2、Vue数据监测原理分析

2.1 Vue数据更新的问题

点击按钮,更新胡歌的信息。

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Vue数据更新的问题</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <button @click="updateUserInfo()">更新胡歌的信息</button>
    <ul>
        <li v-for="(p,index) of persons" :key="p.id">
            {{p.name}}--{{p.age}}--{{p.sex}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                keyWord: "",
                persons: [
                    {id: '001', name: '胡歌', age: 19, sex: '男'},
                    {id: '002', name: '周冬雨', age: 20, sex: '女'},
                    {id: '003', name: '赵丽颖', age: 21, sex: '女'},
                    {id: '004', name: '杨幂', age: 22, sex: '女'}
                ],
                filPersons: []
            };
        },
        methods: {
            //更新用户信息
            updateUserInfo() {
                // this.persons[0].name = '景天'; //奏效(页面同步更新)
                // this.persons[0].age = 30; //奏效(页面同步更新)
                // this.persons[0].sex = '男'; //奏效(页面同步更新)
                this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
                console.log(this.persons[0]);
            }
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
</script>
</html>

结果如下:

在这里插入图片描述

出现了数据不一致的问题。那又该如何解决呢?

别急,下面我们就一起来探究一下Vue监测数据变化的原理。

2.2 Vue数据监测原理_对象

2.2.1 示例代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Vue监测数据变化的原理</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2>学校:{{school}}</h2>
    <h2>地址:{{address}}</h2>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                school: '北京理工',
                address: '北京',
                //Vue内部会递归查找属性,如果发现是对象属性,则会继续递归查找,
                //直到找到单一的属性,然后给这个单一属性分配一组getter和setter。
                student: {
                    name: 'tom',
                    age: {
                        rAge: 30,
                        sAge: 18,
                    },
                    friends: [
                        {name: 'jerry', age: 29}
                    ]
                }
            };
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
</script>
</html>

总结

  • Vue内部会递归查找属性,如果发现是对象属性,则会继续递归查找,
  • 直到找到单一的属性为止。
  • Vue会给data中的每一个自定义属性分配一组getter和setter。
2.2.2 原理分析

在这里插入图片描述

2.2.3 总结
  • Vuedata中的每一个自定义属性,都匹配了一组gettersetter
  • 假如data中定义了一个school属性,则当school属性值发生改变的时候,对应的setter就会被调用,
  • 然后Vue就会重新解析模板,接下来就会生成新的虚拟DOM
  • 然后Vue就会对比新旧的虚拟DOM(diff算法),
  • 最后生成真实DOM更新页面

2.3 模拟一个数据监测

为了对Vue数据监测原理有更深的理解,我们来看看和模拟一下Vue中是怎么做的数据监测。

以监测对象数据为例。

2.3.1 示例代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>模拟一个数据监测</title>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
</div>
</body>

<script type="text/javascript">
    //1、准备好数据,等一下要监测这里面数据的变化
    let data = {
        school: '北京理工',
        address: '北京'
    };

    //2、定义一个构造函数,用于对data对象中的数据进行处理
    function Observer(obj) {
        //汇总对象中的所有属性,形成一个数组
        // ['school','address']
        const keys = Object.keys(obj);
        //遍历
        keys.forEach((k) => {
            //this:为当前Observer的实例对象
            //k:为每一个属性
            Object.defineProperty(this, k, {
                /*往Observer实例对象(this)中添加一个属性 k ,
                当有人读取Observer实例对象上的属性 k 时,
                就把传入对象obj的属性 k 对应的值返回*/
                get() {
                    return obj[k];
                },
                set(newValue) {
                    //Vue会在这里触发一些解析模板的函数,重新解析模板。
                    console.log(`${k}被修改了,我要去解析模板,生成虚拟DOM,对比新旧虚拟DOM...要开始忙了~`);
                    obj[k] = newValue;
                }
            });
        });
    }

    //3、创建一个监视的实例对象,用于监视data中数据的变化
    const obs = new Observer(data);
    //准备一个vm实例对象
    let vm = {};
    vm._data = data = obs;
</script>
</html>

对属性值进行修改,控制台输出如下:

在这里插入图片描述

2.4 Vue.set的使用

向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Vue.set的使用</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <button @click="addSex">添加一个性别属性,默认值是男</button>
    <h2>学生信息</h2>
    <h3>名字:{{student.name}}</h3>
    <h3>年龄:{{student.age}}</h3>
    <!--如果学生的性别有值就显示这个标签,无(undefined)则不显示-->
    <h3 v-if="student.sex">性别:{{student.sex}}</h3>
    <h3>朋友们:</h3>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}==={{f.age}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                student: {
                    name: '张三',
                    age: 20,
                    friends: [
                        {name: '李四', age: 18},
                        {name: '王五', age: 19},
                    ]
                }
            };
        },
        methods: {
            addSex() {
                //注意!!!不能往data中直接添加属性,只能往data中的某个属性里,添加属性
                //往vue实例,data中的student上添加一个sex属性,默认值为:男
                // Vue.set(this.student, 'sex', '男');
                this.$set(this.student, 'sex', '男');
            }
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
</script>
</html>

总结

  • Vue.set( target, propertyName/index, value )
  • vm.$set( target, propertyName/index, value ) 【vm为Vue实例对象】
  • 向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。
  • 参数
    • {Object | Array} target
    • {string | number} propertyName/index
    • {any} value
  • 返回值:设置的值。

官网:全局API-Vue.set的使用

2.5 Vue数据监测原理_数组

2.5.1 示例代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Vue监测数据变化的原理_数组</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h3>名字:</h3>
    <ul>
        <li v-for="(name,index) in fullName" :key="index">
            {{name}}
        </li>
    </ul>
    <h3>爱好:</h3>
    <ul>
        <li v-for="(h,index) of hobby" :key="index">
            {{h}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //关闭Vue的生产提示
    const vm = new Vue({
        data() {
            return {
                fullName: {
                    firstName: '张',
                    lastName: '三'
                },
                hobby: ['抽烟', '喝酒', '烫头']
            };
        }
    });
    /*挂载Vue实例到root容器上*/
    vm.$mount('#root');
    let arr = [1, 3, 5];
</script>
</html>
2.5.2 原理分析

官网链接:Vue监测数组的更新改变

如下图,在控制台输出_data发现,数组元素没有对应的gettersetter

在这里插入图片描述

可见,数组里的每个元素不是靠getter和setter来实现数据劫持的,

也就是说,数组里的每个元素都没有对应的getter和setter,

当数组中的元素的值发生改变时,vue不会监测到这次改变,页面也就不会同步更新。

从下图中我们可以看到,JS中原生数组中调用的方法,在数组原型对象上可以找到,

也就是说,当我们调用数组上的方法时,实际上内部会去原型对象上找对应的方法,

调用的是数组原型对象上的方法。

在这里插入图片描述

从下面这张图中可以验证上面的结论,可以看出,原生数组上的方法就是数组原型对象上的方法,

但也可以发现,Vue实例管理的数组调用的方法,却不是原生数组的方法。

在这里插入图片描述

通过查阅资料发现,Vue实例上的数组调用的方法,实际上是Vue中的方法,

这些方法是被包装(加工)过的,所以和原生数组上的方法不一样,

Vue在其中做了两件事情(以push方法为例):

  1. 第一步,还是调用一下Array原型上的方法(push),
  2. 第二步,调用方法,去解析模板和更新页面。

这也就解释了**【2.1 Vue数据更新的问题】**当中的这段代码不奏效的原因。

//更新用户信息
updateUserInfo() {
    // this.persons[0].name = '景天'; //奏效(页面同步更新)
    // this.persons[0].age = 30; //奏效(页面同步更新)
    // this.persons[0].sex = '男'; //奏效(页面同步更新)
     this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
     console.log(this.persons[0]);
}

因为Vue当中没有为数组中的每一个元素提供gettersetter方法,Vue监测不到数组元素值的变化,

所以导致数组中元素值发生改变了,页面也没有同步更新,也就是操作不奏效,

只有调用对应改变数组的方法,页面才会同步更新。

Vue 将被侦听的数组的变更方法进行了包裹(包装,加工),所以它们也将会触发视图更新。

这些被包裹过的方法包括:

  • push():往数组最后位置新增一个元素。
  • pop():删除数组中最后一个元素。
  • shift():删除数组中的第一个元素。
  • unshift():往数组第一个位置插入一个元素。
  • splice():往数组中指定位置插入(或删除,或替换)某个元素。
  • sort():对数组中的元素进行排序。
  • reverse():反转数组。

原因弄明白之后,**【2.1 Vue数据更新的问题】**中遗留的问题也就解决了。如下:

//更新用户信息
updateUserInfo() {
    // this.persons[0].name = '景天'; //奏效(页面同步更新)
    // this.persons[0].age = 30; //奏效(页面同步更新)
    // this.persons[0].sex = '男'; //奏效(页面同步更新)
    //this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
    /*splice(start,deleteCount,items)
     * start: 要替换的元素位置,从0开始
     * deleteCount: 替换(删除)的数量
     * items: 新元素*/
     this.persons.splice(0, 1, {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效(页面同步更新)
     console.log(this.persons[0]);
}

也可以采用set方式来解决,如下:

//参数一:要修改的元素,
//参数二:要修改的元素的位置,
//参数三:新元素
Vue.set(this.persons,0,{id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效
vm.$set(this.persons,0,{id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效

备注:使用过滤器,将过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面

2.6 总结Vue数据监测

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>总结Vue数据监测</title>
    <style>
        button {
            margin-top: 10px;
        }
    </style>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>s
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h1>学生信息</h1>
    <button @click="student.age++">年龄+1岁</button>
    <br/>
    <button @click="addSex">添加性别属性,默认值:男</button>
    <br/>
    <button @click="student.sex = '未知' ">修改性别</button>
    <br/>
    <button @click="addFriend">在列表首位添加一个朋友</button>
    <br/>
    <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button>
    <br/>
    <button @click="addHobby">添加一个爱好</button>
    <br/>
    <button @click="updateHobby">修改第一个爱好为:开车</button>
    <br/>
    <button @click="removeSmoke">过滤掉爱好中的抽烟</button>
    <br/>
    <h3>姓名:{{student.name}}</h3>
    <h3>年龄:{{student.age}}</h3>
    <h3 v-if="student.sex">性别:{{student.sex}}</h3>
    <h3>爱好:</h3>
    <ul>
        <li v-for="(h,index) in student.hobby" :key="index">
            {{h}}
        </li>
    </ul>
    <h3>朋友们:</h3>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}--{{f.age}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el: '#root',
        data: {
            student: {
                name: 'tom',
                age: 18,
                hobby: ['抽烟', '喝酒', '烫头'],
                friends: [
                    {name: 'jerry', age: 20},
                    {name: 'tony', age: 21}
                ]
            }
        },
        methods: {
            addSex() {
                // Vue.set(this.student,'sex','男')
                this.$set(this.student, 'sex', '男')
            },
            addFriend() {
                this.student.friends.unshift({name: 'jack', age: 70})
            },
            updateFirstFriendName() {
                this.student.friends[0].name = '张三'
            },
            addHobby() {
                this.student.hobby.push('学习')
            },
            updateHobby() {
                // this.student.hobby.splice(0,1,'开车')
                // Vue.set(this.student.hobby,0,'开车')
                this.$set(this.student.hobby, 0, '开车')
            },
            removeSmoke() {
                //过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面
                this.student.hobby = this.student.hobby.filter((h) => {
                    return h !== '抽烟'
                })
            }
        }
    })
</script>
</html>

总结

Vue监视数据的原理

  1. Vue会监视data所有层次的数据。

  2. 如何监测对象中的数据?

    • 通过setter实现监视,且要在new Vue时就传入要监测的数据。
    • 对象中后追加的属性,Vue默认不做响应式处理。
    • 如需给后添加的属性做响应式,请使用如下API:
      • Vue.set(target,propertyName/index,value)
      • vm.$set(target,propertyName/index,value)
  3. 如何监测数组中的数据?

    • 通过包裹(包装,加工)数组更新元素的方法实现,本质就是做了两件事:
      • 调用原生对应的方法对数组进行更新。
      • 重新解析模板,进而更新页面。
    • Vue修改数组中的某个元素一定要用如下方法:
      • push()、pop()、shift()、unshift()、splice()、sort()、reverse()
      • Vue.set()vm.$set()
      • 特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data,_data) 添加属性!!!
  4. 使用过滤器,将过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面。


3、Vue生命周期

3.1 引出生命周期

需求:文字从清晰变透明,透明度逐渐变化,透明度小于或等于0时,重新变为1。

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>引出生命周期</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2 v-if="a">你好啊</h2>
    <h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。

    new Vue({
        el: '#root',
        data: {
            a: false,
            opacity: 1
        },
        methods: {},
        //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
        mounted() {
            console.log('mounted', this);
            setInterval(() => {
                this.opacity -= 0.01;
                if (this.opacity <= 0) {
                    this.opacity = 1
                }
            }, 16)
        },
    })

    //通过外部的定时器实现(不推荐)
    /* setInterval(() => {
        vm.opacity -= 0.01
        if(vm.opacity <= 0) vm.opacity = 1
    },16) */
</script>
</html>

总结

生命周期

  • 也叫:生命周期回调函数、生命周期函数、生命周期钩子。
  • 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
  • 生命周期函数中的this指向是 vm组件实例对象

3.2 分析生命周期

如图:

在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>分析生命周期</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2 v-text="n"></h2>
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
    <button @click="bye">点我销毁vm</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。

    new Vue({
        el: '#root',
        //可以把html代码写在template里,需要用引号包裹,页面就可以省略这部分代码了
        // template:`
        // 	<div>
        // 		<h2>当前的n值是:{{n}}</h2>
        // 		<button @click="add">点我n+1</button>
        // 	</div>
        // `,
        data: {
            n: 1
        },
        methods: {
            /*改变n的值*/
            add() {
                console.log('add');
                this.n++;
            },
            /*销毁vm*/
            bye() {
                console.log('bye');
                this.$destroy();
            }
        },
        /*监视属性*/
        watch: {
            /*监视n是否被修改*/
            n() {
                console.log('n变了');
            }
        },

        /********************Vue生命周期函数******************************/

        beforeCreate() {
            console.log('beforeCreate');
        },
        /*初始化:数据监测,数据代理,下一阶段开始解析模板*/
        created() {
            console.log('created');
        },
        beforeMount() {
            console.log('beforeMount');
        },
        /*初始化完成*/
        mounted() {
            console.log('mounted');
        },
        beforeUpdate() {
            console.log('beforeUpdate');
        },
        /*更新完成,数据和页面实现同步,都是最新的*/
        updated() {
            console.log('updated');
        },
        /*Vue实例销毁之前*/
        beforeDestroy() {
            console.log('beforeDestroy');
        },
        destroyed() {
            console.log('destroyed');
        },
    });
</script>
</html>

3.3 总结生命周期

代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>总结生命周期</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
    <h2 :style="{opacity}">欢迎学习Vue</h2>
    <button @click="opacity = 1">透明度设置为1</button>
    <button @click="stop">点我停止变换</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。

    new Vue({
        el: '#root',
        data: {
            opacity: 1
        },
        methods: {
            stop() {
                this.$destroy()
            }
        },
        //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
        mounted() {
            console.log('mounted', this);
            this.timer = setInterval(() => {
                console.log('setInterval');
                this.opacity -= 0.01;
                if (this.opacity <= 0) this.opacity = 1
            }, 16)
        },
        beforeDestroy() {
            clearInterval(this.timer);
            console.log('vm即将驾鹤西游了')
        },
    })
</script>
</html>

总结

常用的生命周期钩子

  1. mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
  2. beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
  3. 关于销毁Vue实例:
    • 销毁后借助Vue开发者工具看不到任何信息。
    • 销毁后自定义事件会失效,但原生DOM事件依然有效
    • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

4、结语

到此,Vue的核心内容差不多学习完了,接下来就是组件的内容了,如果这篇博客对你有帮助,欢迎点赞,评论,转发,一起进步,谢谢。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunnyboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值