16-Vue核心-Vue数据监视

我们先探讨一个数据更新时的问题,假设在以下人员列表中,改变"马冬梅"的信息,可以通过什么方法

1)第一种方法(奏效)

数据更新时,方法奏效

this.persons[0].name = "马老师"
this.persons[0].age = 50
this.persons[0].sex = "男"

2)第二种方法(不奏效)

数据更新时,Vue不监听,模板不改变,但通过控制台命令,vm.persons[0].name  发现内部数据已经发生改变

this.persons[0] = {id:"001",name:"马老师",age:50,sex:"男"}

3)第三种方法(奏效)

// splice() 方法用于添加或删除数组中的元素
// 第一个参数代表要添加的索引位置,第二参数代表要添加或删除的个数,第三个参数代表内容
this.persons.splice(0,1,{id:"001",name:"马老师",age:50,sex:"男"})

 

完整代码:

复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>数据更新时的一个问题</title>
        <!--  引入Vue  -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!--  准备好一个容器  -->
        <div id="root">
            <!--  遍历数组  -->
            <h2>人员列表</h2>
            <button @click="updateData">更新马冬梅的信息</button>
            <ul>
                <li v-for="(p,index) in persons" :key="index">
                    姓名:{{p.name}} &nbsp&nbsp 年龄:{{p.age}} &nbsp&nbsp 性别:{{p.sex}}
                </li>
            </ul>
        </div>

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

            new Vue({
                el:"#root",
                data(){
                    return{
                        persons:[
                            {id:"001",name:"马冬梅",age:30,sex:"女"},
                            {id:"002",name:"周冬雨",age:28,sex:"女"},
                            {id:"003",name:"周杰伦",age:24,sex:"男"},
                            {id:"004",name:"温兆伦",age:32,sex:"男"}
                        ],
                    }
                },
                methods:{
                    updateData(){
                        // this.persons[0].name = "马老师"
                        // this.persons[0].age = 50
                        // this.persons[0].sex = "男"

                        // this.persons[0] = {id:"001",name:"马老师",age:50,sex:"男"}

                        // splice() 方法用于添加或删除数组中的元素
                        // 第一个参数代表要添加的索引位置,第二参数代表要添加或删除的个数,第三个参数代表内容
                        this.persons.splice(0,1,{id:"001",name:"马老师",age:50,sex:"男"})
                    }
                }
            })
        </script>
    </body>
</html>
复制代码

 

模拟一个数据监测

复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>数据更新时的一个问题</title>
        <!--  引入Vue  -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            // 阻止 vue 在启动时生成生产提示
            Vue.config.productionTip = false

            // 声明一个变量
            let data = {
                name:"马铃薯",
                address:"河北"
            }

            // // 声明一个中间变量
            // let tmp = ""
            // // 定时器方法,每隔一定时间就调用函数,方法或对象
            // setInterval(()=>{
            //     if(data.name !== tmp){
            //         tmp = data.name
            //         console.log("name正在被修改")
            //     }
            // },100)

            // 创建要给监视的实例对象,用于监视 data 中属性的变化
            const obs = new Observer(data)
            console.log(obs)

            // Observer 构造函数
            function Observer(obj){
                // 汇总对象中所有属性,形成一个数组
                const keys = Object.keys(obj)
                // 遍历,forEach() 方法对数组的每个元素执行一次提供的函数
                keys.forEach((k)=>{
                    // Object.defineproperty方法的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
                    Object.defineProperty(this,k,{
                        get(){
                           return obj[k]
                        },
                        set(val){
                            obj[k] = val
                            console.log(`${k}正在被修改,进行解析模板,生成虚拟DOM...`)
                        }
                    })
                })
            }

            //准备一个 vm 实例对象
            let vm = {}
            vm._data = data = obs

        </script>
    </body>
</html>
复制代码

Vue中set的使用

在student中,使用vue.set()方法添加一个sex属性,看看前后效果

复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Vue set的使用</title>
        <!--  引入Vue  -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
        <body>
        <!--  准备好一个容器  -->
        <div id="root">
            <!--  遍历数组  -->
            <h2>学校名称:{{name}}</h2>
            <h2>学校地址:{{address}}</h2>
            <hr/>
            <h2>学生姓名:{{student.name}}</h2>

            <button @click="addSex">添加一个性别属性,默认值是男的</button>
            <!--  控制台 Vue.set(vm._data.student,"sex","男") -->
            <!--  判断是否有学生的性别属性,有则进行展示,否则不展示  -->
            <h2 v-if="student.sex">学生性别:{{student.sex}}</h2>

            <h2>学生年龄:对内{{student.age.rAge}},对外:{{student.age.sAge}}</h2>

            <h2>爱好</h2>
            <ul>
                <li v-for="(f,index) in student.hobby" :key="index">{{f}}</li>
            </ul>

            <h2>朋友列表</h2>
            <ul>
                <li v-for="(f,index) in student.friends" :key="index">
                    姓名:{{f.name}} &nbsp&nbsp 年龄:{{f.age}}
                </li>
            </ul>
        </div>

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

            const vm = new Vue({
                el:"#root",
                data(){
                    return{
                        name:"尚硅谷",
                        address:"北京",
                        student:{
                            name:"马铃薯",
                            age:{
                                rAge:26,
                                sAge:30
                            },
                            hobby:["抽烟","喝酒","烫头"],
                            friends:[
                                {name:"大宇",age:26},
                                {name:"帆帆",age:26}
                            ]
                        }
                    }
                },
                methods:{
                    updateData(){
                        // this.persons[0].name = "马老师"
                        // this.persons[0].age = 50
                        // this.persons[0].sex = "男"

                        // this.persons[0] = {id:"001",name:"马老师",age:50,sex:"男"}

                        // splice() 方法用于添加或删除数组中的元素
                        // 第一个参数代表要添加的索引位置,第二参数代表要添加或删除的个数,第三个参数代表内容
                        this.persons.splice(0,1,{id:"001",name:"马老师",age:50,sex:"男"})
                    },
                    addSex(){
                        // Vue.set(vm._data.student,"sex","男")
                        Vue.set(this.student,"sex","男")
                    }
                }
            })
        </script>

    </body>
</html>
复制代码

1)初始效果

 2)使用Vue.set(vm._data.student,"sex","男"),添加之后的效果

 

Vue监视数据的原理

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

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

通过setter实现监视,且要在new Vue时就传入要监测的数据

1)对象中后追加的属性,Vue默认不做响应式处理

2)如需给后添加的属性做响应式,请使用如下API:

Vue.set(target, propertyName/index, value) 或 vm.$set(target, propertyName/index, value) 

3.如何监测数组中的数据

通过包裹数组更新元素的方法实现,本质就是做了两件事

1)调用原生对应的方法对数组进行更新

2)重新解析模板,进而更新页面

4.在Vue修改数组中的某个元素一定要用如下方法:

1)使用数组的这七个API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

push( )方法:可以将一个或者更多的参数添加在数组的尾部;返回添加后的数组的长度,原数组发生改变

// 写法:array.push(item1, item2, …, itemX)
var arr=[1,2,3,4];
var a=arr.push(9,8,7);
console.log(a,arr);

unshift( )方法:可以将一个或者更多的参数添加在数组的头部;返回添加后的数组的长度,原数组发生改变。

// 写法:array.unshift(item1,item2, …, itemX)
var arr=[1,2,3,4];
var a=arr.unshift(9,8,7);
console.log(a,arr);

pop( )方法:从数组尾部删除一个元素,返回这个被删除的元素,原数组发生改变。

// 写法:array.pop()
var arr=[1,2,3,4];
var a=arr.pop();
console.log(a,arr)

shift( ) 方法:从数组头部删除一个元素,返回这个被删除的元素,原数组发生改变。

// 写法:array.shift()
var arr = [1,2,3,4];
var a = arr.shift();
console.log(a,arr)

splice( ) 方法:方法用于添加或删除数组中的元素

没有参数,返回空数组,原数组不变;

一个参数,从该参数表示的索引位开始截取,直至数组结束,返回截取的 数组,原数组改变;

两个参数,第一个参数表示开始截取的索引位,第二个参数表示截取的长度,返回截取的 数组,原数组改变;

三个或者更多参数,第三个及以后的参数表示要从截取位插入的值。

var hobby = ["抽烟","喝酒","烫头"];
// 将数组的第一个元素改为”开车“
hobby.splice(0,1,"开车")
//删除第二个元素
hobby.splice(1,1)
console.log(hobby)

 2)Vue.set() 或 vm.$set()

// Vue.set()方法
Vue.set(vm._data.student,"sex","男")
Vue.set(this.student,"sex","男")

//vm.$set()方法
this.$set(this.student,"sex","男")

特别注意:Vue.set() 和 vm.$set() 不能给 vm 或 vm的根数据对象 添加属性 !!!

 

完整代码:

复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Vue set的使用</title>
        <!--  引入Vue  -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
        <body>
        <!--  准备好一个容器  -->
        <div id="root">
            <h1>学生信息</h1>

            <button @click="student.age++">年龄+1岁</button><br/>
            <button @click="addSex">添加性别属性,默认值:男</button><br/>
            <button @click="student.sex === '男' ? student.sex = '女' : student.sex = '男'">修改性别</button><br/>
            <button @click="addFriend">在列表首位添加一个朋友</button><br/>
            <button @click="updataFirstFriendName">修改第一个朋友的名字为:张三</button><br/>
            <button @click="addHobby">添加一个爱好</button><br/>
            <button @click="updateHobby">修改第一个爱好为:开车</button><br/>

            <h3>姓名:{{student.name}}</h3>
            <!--  控制台 Vue.set(vm._data.student,"sex","男") -->
            <!--  判断是否有学生的性别属性,有则进行展示,否则不展示  -->
            <h3 v-if="student.sex">学生性别:{{student.sex}}</h3>
            <h3>年龄:{{student.age}}</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}} &nbsp&nbsp 年龄:{{f.age}}
                </li>
            </ul>
        </div>

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

            const vm = new Vue({
                el:"#root",
                data(){
                    return{
                        student:{
                            name:"马铃薯",
                            age:26,
                            hobby:["抽烟","喝酒","烫头"],
                            friends:[
                                {name:"大宇",age:26},
                                {name:"帆帆",age:26}
                            ]
                        }
                    }
                },
                methods:{
                    addSex(){
                        // Vue.set(vm._data.student,"sex","男")
                        // Vue.set(this.student,"sex","男")
                        this.$set(this.student,"sex","男")
                    },
                    addFriend(){
                        // 在数组,第一个位置添加一个元素
                        this.student.friends.unshift({name:"钦权",age:24})
                    },
                    updataFirstFriendName(){
                        this.student.friends[0].name = "张三"
                    },
                    addHobby(){
                        // 在数组,最后一个位置添加一个元素
                        this.student.hobby.push("打豆豆")
                    },
                    updateHobby(){
                        // splice() 方法用于添加或删除数组中的元素
                        // 第一个参数代表要添加的索引位置,第二参数代表要添加或删除的个数,第三个参数代表内容
                        // this.student.hobby[0].splice(0,1,"开车")

                        // Vue.set(this.student.hobby,0,"开车")
                        this.$set(this.student.hobby,0,"开车")
                    }
                }
            })
        </script>
    </body>
</html>
复制代码

 

 



posted @   马铃薯1  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示