IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue数据代理与数据监测 -> 正文阅读

[JavaScript知识库]Vue数据代理与数据监测

一、数据代理

1.什么是数据代理?

数据代理:通过一个对象代理对另一个对象中属性的操作

2.Vue数据代理

通过vm对象来代理配置对象data中所有属性的操作。
(如果想访问data里的数据,可以直接通过实例对象,如vm.name,vm.age拿到具体的数值,之所以能这样做,就是因为Vue实现了数据代理)

3.为什么要用数据代理

更方便的读取和修改data中的属性

4.为什么要先将数据收集到_data中,再代理出去

为了更高效地实现数据监测

5.实现原理

①Vue将配置对象data进行了一次加工,然后将加工后的数据收集到vm._data中,实例对象通过vm._data的方式可以拿到加工后的data。但是属性的值不再直接给出,而是通过响应式getter来获取,当data中数据改变的时候,就会调用响应式setter,导致重新解析模板,然后生成新的虚拟DOM进行新旧DOM对比,最后更新页面。
在这里插入图片描述

②然后通过Object.defineProperty()让vm上拥有vm._data中的所有属性,即配置对象data中的所有属性,从而实现了数据代理。

模拟数据绑定到vm._data的过程:

   <script type="text/javascript">
        let data={
            name:"gyc",
            age:18
        }

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

        // 准备一个vm实例对象
        let vm={}
        //将obs赋值给vm._data,从而vm._data可以监视data中属性的变化
        vm._data=data=obs

        function Observer(obj){
            //获取监视对象obj的所有属性
            const keyArr=Object.keys(obj)
            // 遍历属性,将obj的所有属性定义给Obeserver实例对象
            keyArr.forEach((key)=>{
                Object.defineProperty(this,key,{
                    get(){
                        return obj[key]
                    },
                    set(val){
                        obj[key]=val
                    }
                })
            })
        }
    </script>

在这里插入图片描述
在这里插入图片描述

注意:_data里面不是数据代理,而是做了一个数据劫持。Vue去监测_data中的数据变化,从而达到界面也跟着变化。
添加到vm上的属性才是数据代理

二、数据监测

1.监测对象

首先写出需要用到的静态页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新数据</title>
    <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>
       <h2>学生性别:{{student.sex}}</h2>
       <h2>学生年龄:{{student.age}}</h2>
       <h1>朋友</h1>
       <ul>
           <li v-for="(f,index) in student.friends" :key="index">
               {{f.name}} - {{f.age}}
           </li>
       </ul>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
        const vm = new Vue({
            el: '#root',
            data:{
                name:'JLU',
                address:'jilin',
                student:{
                    name: 'gyc',
                    age: 20,
                    friends: [
                        {name: 'jack', age: 21},
                        {name: 'mary', age: 20}
                    ]
                },
            }
        })
    </script>
</body>
</html>

在这里插入图片描述
需要注意的是,模板中的{{sex}}并没有出现在data中。当输出一个对象中不存在的属性值时,会输出undifined,但经过Vue处理后,不会将undifined显示到页面上,而是什么都不显示,控制台也不报错。

现在的需求是,添加一个按钮,点击按钮,为学生添加性别属性。要求不能改变data中现有的属性,即sex不能直接添加到data中。

前面提到过_data,考虑将sex添加到_data中,浅试一下:
在这里插入图片描述
页面效果:
在这里插入图片描述
可以发现,添加的sex属性并没有渲染到页面上
查看vm._data:
在这里插入图片描述
可以看到通过这种方式添加属性,_data中添加了sex,但是没有生成相应的setter和getter,这说明后添加的属性不是响应式属性,无法渲染到页面上。

2.Vue.set监测对象

为了解决上面的问题,为后添加的属性设置响应式,需要使用Vue提供的API:
? Vue.set(target,propertyName/index,value)
? vm.$ser(target,propertyName/index,value)

通过Vue.set()试一下是否可以实现功能:
在这里插入图片描述
页面效果:
在这里插入图片描述
发现通过这种方式可以将新添加的属性渲染到页面上。
在实现功能后我们可以考虑一下优化简写,由于数据代理,vm.student === vm._data.student,所以可以简写为Vue.set(vm.student,‘sex’,‘女’)。

完整的实现上面提出的需求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新数据</title>
    <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>
       <h2 v-show="student.sex">学生性别:{{student.sex}}</h2>
       <h2>学生年龄:{{student.age}}</h2>
       <h1>朋友</h1>
       <ul>
           <li v-for="(f,index) in student.friends" :key="index">
               {{f.name}} - {{f.age}}
           </li>
       </ul>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
        const vm = new Vue({
            el: '#root',
            data:{
                name:'JLU',
                address:'jilin',
                student:{
                    name: 'gyc',
                    age: 20,
                    friends: [
                        {name: 'tom', age: 19},
                        {name: 'richard', age: 20}
                    ]
                },
            },
            methods:{
                addSex(){
                    Vue.set(this.student,'sex','女')
                }
            }
        })
    </script>
</body>
</html>

在这里插入图片描述
但是使用这样的方法有一定的局限性,上面的例子是给data中的student对象添加新的属性,假如直接给data对象添加属性呢?
比如假设需要在这里添加一个新的属性建校事件time,如果仍然采用Vue.set方法的话,就会报错。
在这里插入图片描述
注意:Vue.set只适用于给data中的对象添加新的属性(例如:data.student),而不能直接给data添加新的属性。

3.监测数组

先给出静态页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新数据</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
       <button @click="addSex">点击按钮新增性别</button>
       <h2>学校名称:{{name}}</h2>
       <h2>学校地址:{{address}}</h2>
       <hr/>
       <h2>学生姓名:{{student.name}}</h2>
       <h2>学生性别:{{student.sex}}</h2>
       <h2>学生年龄:{{student.age}}</h2>
       <h1>朋友</h1>
       <ul>
           <li v-for="(f,index) in student.friends" :key="index">
               {{f.name}} - {{f.age}}
           </li>
       </ul>
       <h1>爱好</h1>
       <ul>
           <li v-for="(h,index) in student.hobby" :key="index">
               {{h}}
           </li>
       </ul>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
        const vm = new Vue({
            el: '#root',
            data:{
                name:'JLU',
                address:'jilin',
                student:{
                    name: 'gyc',
                    age: 20,
                    friends: [
                        {name: 'tom', age: 19},
                        {name: 'richard', age: 20}
                    ],
                    hobby:['吃饭','睡觉','打豆豆']
                },
            },

            methods:{
                addSex(){
                    this.$set(this.student, 'sex', '男')
                }
            }
        })
    </script>
</body>
</html>

其中student.hobby是数组
此时页面效果为:
在这里插入图片描述
在控制台中打印vm._data后我们可以清晰的看到,对于student中的hobby数组,数组整体来说有get和set,是响应式的。但是数组里面的元素并非响应式,而是简单的挂在了数组中。
在这里插入图片描述
现提出一个需求,将hobby数组中的第一项 吃饭 改成 学习。
如果通过索引来改变数组中的值,将hobby[0]改为学习:
在这里插入图片描述
vm._data中已经修改了,但是没有渲染到页面上,页面没反应:
在这里插入图片描述
在Vue中,如果想要通过索引修改数组中的数值,就需要使用某些特殊方法

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

这些方法都会引起数组本身的变化,称为变更方法

因此,想要实现上面提出的需求,可以通过以下两种方法实现:
①通过splice()方法

vm.student.hobby.splice(0,1,'学习')

②通过Vue.set()

Vue.set(vm.student.hobby,0,'学习')

注意这里Vue.set()的第二个参数是数组中元素的下标。

对于一些数组的非变更方法,例如filter()、concat() 和 slice(),并不会引起数组本身的变化,若想要调用这些方法实现响应式,可以用新数组替换旧数组。例如:

 this.student.hobby=this.student.hobby.filter((item)=>{
                        return item!='吃饭'
                        })

4.Vue监测总结

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

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

     ? 通过setter事件监视,且要在new Vue时就传入要监测的数据

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

         ? (2).如需给后添加的属性做响应式,需要使用以下API:

           ? Vue.set(target,propertyName/index,value)

           ? vm.$ser(target,propertyName/index,value)

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

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

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

?        (2).重新解析模板,进而更新页面
   
4.在Vue修改数组中的某个元素需要用到以下方法:

?    1.使用这些API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()

   ? 2.Vue.set()或vm.$set
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:26:06  更:2022-03-24 00:26:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:23:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码