Vue检测数据

50 阅读1分钟

1.更新时遇到的一个问题

   <div id="root">
    <button @click="updateMei">更新第一列</button>
    <h1>人员列表</h1>
    <ul>
        <!-- (p,index) in persons -- :key="index" -->
        <li v-for="p of persons" :key="p.id">
            {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
    </ul>

</div>
<script>

    const vm = new Vue({
        el: '#root',
        data: {
            keyword: '',
            persons: [
                { id: '001', name: '马冬梅', age: '18', sex: '女' },
                { id: '002', name: '周冬雨', age: '19', sex: '女' },
                { id: '003', name: '周杰伦', age: '20', sex: '男' },
                { id: '004', name: '温兆伦', age: '22', sex: '男' }

            ]

        },
        methods: {
            updateMei() {
                /*this.persons[0].name = '马老师'//奏效
                this.persons[0].age = '50'//奏效
                this.persons[0].sex = '男'//奏效*/
                this.persons[0] = { id: '001', name: '马老师', age: '50', sex: '男' }
            }
        },
    })
</script>

用this.persons[0].name = '马老师'//奏效
this.persons[0].age = '50'//奏效
this.persons[0].sex = '男'//奏效 可以实现更新 image.png

用这个 this.persons[0] = { id: '001', name: '马老师', age: '50', sex: '男' 则不能更新 image.png

2.Vue检测数据改变的原理

 <!-- 准备一个容器 -->
<div id="root">
    <h1>名字:{{name}}</h1>
    <h1>地址:{{address}}</h1>
</div>
<script>
    Vue.config.productionTip = false //设置为 false 以阻止 vue 在启动时生成生产提示。

    //创建Vue实例
    const vm = new Vue({
        el: '#root',//el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
        data: {//data用于储存数据,数据供el指定的容器使用,值我们先暂时写成一个对象
            name: 'world',
            address: '地球',
            a: {
                b: 'nihao',
                c: {
                    d: '第四层'

                }
            },
            e: [
                {
                    f: '数据里的'
                },
                {
                    g: {
                        h: '数据里再深一层'
                    }
                }

            ]

        }
    })
</script>

image.png

3.模拟一个数据检测 image.png

image.png

image.png

 <script>
    let data = {
        name: 'world',
        a: {
            b: 'nihao'
        }
    }

    // let tmp = 'world'
    // setInterval(() => {
    //     if (data.name !== tmp) {
    //         tmp = data.name
    //         console.log('name被改了')
    //     }
    // }, (100))

    // Object.defineProperty(data, 'name', {
    //     get() {
    //         return data.name
    //     },
    //     set(val) {
    //         data.name = val
    //     }
    // })


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

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

    function Observer(obj) {
        //汇总对象中所有的属性形成一个数组
        const keys = Object.keys(obj)
        //遍历
        keys.forEach((k) => {
            Object.defineProperty(this, k, {
                get() {
                    return obj[k]
                },
                set(val) {
                    console.log(`$(k)被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了 `)
                    obj[k] = val
                }
            })
        })
    }
</script>

image.png

4.Vue.set的使用

<!-- 准备一个容器 -->
<div id="root">
    <h1>名字:{{name}}</h1>
    <h1>地址:{{address}}</h1>
    <h2>学生姓名:{{students.name}}</h2>
    <button @click="addsex">添加性别</button>
    <h2 v-show="students.sex">学生性别:{{students.sex}}</h2>
    <h2>学生真实年龄:{{students.age.realAge}};对外年龄:{{students.age.sAge}}</h2>
    <ul>学生朋友:
        <li v-for="f of friends">{{f.name}}-{{f.age}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false //设置为 false 以阻止 vue 在启动时生成生产提示。

    //创建Vue实例
    const vm = new Vue({
        el: '#root',//el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
        data: {//data用于储存数据,数据供el指定的容器使用,值我们先暂时写成一个对象
            name: 'world',
            address: '地球',
            students: {
                name: 'Tom',
                // sex: '男',
                age: {
                    realAge: 30,
                    sAge: 25

                }
            },
            friends: [
                {
                    name: 'Make',
                    age: 31

                },
                {
                    name: 'Mary',
                    age: 28,
                }

            ]

        },
        methods: {
            addsex() {
                // Vue.set(this.students, 'sex', '男')
                this.$set(this.students, 'sex', '男')

            }
        },
    })
</script>

image.png


image.png

5.Vue检测数据改变的原理-数组 image.png

 <!-- 准备一个容器 -->
<div id="root">
    <h1>名字:{{name}}</h1>
    <h1>地址:{{address}}</h1>
    <h2>学生姓名:{{students.name}}</h2>
    <button @click="addsex">添加性别</button>
    <h2 v-show="students.sex">学生性别:{{students.sex}}</h2>
    <h2>学生真实年龄:{{students.age.realAge}};对外年龄:{{students.age.sAge}}</h2>
    <ul>学生爱好:
        <li v-for="(h,index) in hobby" :key="index">{{h}}</li>
    </ul>
    <ul>学生朋友:
        <li v-for="(f,index) in friends" :key="index">{{f.name}}-{{f.age}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false //设置为 false 以阻止 vue 在启动时生成生产提示。

    //创建Vue实例
    const vm = new Vue({
        el: '#root',//el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
        data: {//data用于储存数据,数据供el指定的容器使用,值我们先暂时写成一个对象
            name: 'world',
            address: '地球',
            students: {
                name: 'Tom',
                // sex: '男',
                age: {
                    realAge: 30,
                    sAge: 25

                }
            },
            hobby: ['抽烟', '喝酒', '烫头'],
            friends: [
                {
                    name: 'Make',
                    age: 31

                },
                {
                    name: 'Mary',
                    age: 28,
                }

            ]

        },
        methods: {
            addsex() {
                // Vue.set(this.students, 'sex', '男')
                this.$set(this.students, 'sex', '男')

            }
        },
    })
</script>

image.png

image.png

因此可以解决《1.更新时遇到的一个问题》 image.png 点击按钮后也会使马冬梅变成马老师 image.png

6.总结Vue数据监控

<!-- 准备一个容器 -->
<div id="root">
    <h1>学生信息</h1>
    <button @click="students.age++">年龄+1岁</button><br>
    <button @click="addSex">添加性别属性,默认值:男</button><br>
    <button @click=" students.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>
    <h2>学生姓名:{{students.name}}</h2>
    <h2 v-show="students.sex">学生性别:{{students.sex}}</h2>
    <h2>学生真实年龄:{{students.age}}</h2>
    <ul>学生爱好:
        <li v-for="(h,index) in students.hobby" :key="index">{{h}}</li>
    </ul>
    <ul>学生朋友:
        <li v-for="(f,index) in students.friends" :key="index">{{f.name}}-{{f.age}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false //设置为 false 以阻止 vue 在启动时生成生产提示。

    //创建Vue实例
    const vm = new Vue({
        el: '#root',//el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
        data: {//data用于储存数据,数据供el指定的容器使用,值我们先暂时写成一个对象
            students: {
                name: 'Tom',
                // sex: '男',
                age: 18,
                hobby: ['抽烟', '喝酒', '烫头'],
                friends: [
                    {
                        name: 'Make',
                        age: 20

                    },
                    {
                        name: 'Mary',
                        age: 19,
                    }

                ]


            },

        },
        methods: {
            addSex() {
                // Vue.set(this.students, 'sex', '男')
                this.$set(this.students, 'sex', '男')

            },
            addFriend() {
                this.students.friends.unshift({ name: 'jack', age: 3 })

            },
            updateFirstFriendName() {
                this.students.friends[0].name = '张三'
                // this.students.friends[0].age = 90

            },
            addHobby() {
                this.students.hobby.push('学习')

            },
            updateHobby() {
                // this.students.hobby.splice(0, 1, '开车')
                // Vue.set(this.students.hobby, 0, '开车')
                this.$set(this.students.hobby, 0, '开车')

            },
            removeSmoke() {
                this.students.hobby = this.students.hobby.filter((h) => {
                    return h !== '抽烟'

                })
            }
        },
    })
</script>

image.png

总结 image.png