Vue 数据响应式相关总结


Posted in Vue.js onJanuary 28, 2021

在说数据响应式之前,我们要解决一个很重要的问题,那就是Vue到底对data做了什么?先从getter和setter说起,我们用那个他们来对虚拟的属性进行读写。

getter和setter

有如下代码

let obj0 = {
 姓: "高",
 名: "圆圆",
 age: 18
};

// 需求一,得到姓名

let obj1 = {
 姓: "高",
 名: "圆圆",
 姓名() {
  return this.姓 + this.名;
 },
 age: 18
};

console.log("需求一:" + obj1.姓名());//高圆圆

此时我们log出来的结果是高圆圆,这个大家都能看懂,但是姓名后面的括号能删掉吗?不能,因为它是函数,那么我们怎么去掉括号呢?下面就有我们的需求二

// 需求二,姓名不要括号也能得出值

let obj2 = {
 姓: "高",
 名: "圆圆",
 get 姓名() {
  return this.姓 + this.名;
 },
 age: 18
};

console.log("需求二:" + obj2.姓名);//高圆圆

此时我们使用getter ,不加括号也能得出值。那么我们要怎么改变这个名字呢?

// 需求三:姓名可以被写

let obj3 = {
 姓: "高",
 名: "圆圆",
 get 姓名() {
  return this.姓 + this.名;
 },
 set 姓名(xxx){
  this.姓 = xxx[0]
  this.名 = xxx.slice(1)
 },
 age: 18
};

obj3.姓名 = '高媛媛'

console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`)//高媛媛

有get就有set,setter就是这样用的。我们用 属性值 = xxx 触发 set 函数,姓名就可以被写啦。但是我们在需求三中打出 console.log(obj3) 会得到如下图所示:

Vue 数据响应式相关总结

如图为什么会显示 姓名:(...) 呢? 这其实是一个get set,浏览器在显示这个姓名的时候就打印出 姓名:(...) ,这说明我们可以在需求三中对姓名进行读和写,但是并不存在一个叫做姓名的属性,而是有get和set来模拟对姓名进行的操作。

Object.defineProperty

在如上例子中,我们在定义对象的时候就直接使用get和set,但是如果对象已经被声明完了,那我们怎么继续加上get呢?我们就要用到Object.defineProperty,还是需求三,我们加入如下代码就可以在定义完之后再加get和set了:

var _xxx = 0
Object.defineProperty(obj3,'xxx',{
 get(){
  return _xxx
 },
 set(value){
  _xxx= value
 }
})

接下来我们就可以解决一开始的问题了:Vue到底对data做了什么?我们举几个例子看看:

let data0 = {
 n: 0
}

先声明一个data0,需求一:用 Object.defineProperty 定义 n:

let data1 = {}

Object.defineProperty(data1, 'n', {
 value: 0
})

console.log(`需求一:${data1.n}`)//需求一:0

需求二:n 不能小于 0:

let data2 = {}

data2._n = 0 // _n 用来偷偷存储 n 的值,默认为0

Object.defineProperty(data2, 'n', {
 get(){
  return this._n
 },
 set(value){
  if(value < 0) return
  this._n = value
 }
})

console.log(`需求二:${data2.n}`)//0
data2.n = -1
console.log(`需求二:${data2.n} 设置为 -1 失败`)//0设置为 -1 失败
data2.n = 1
console.log(`需求二:${data2.n} 设置为 1 成功`)//0设置为 1 成功

可是如果对方直接使用data2._n呢?我们能不能做到不在对象上暴露任何能够被访问的东西呢?这时候我们就要使用代理:

let data3 = proxy({ data:{n:0} }) // 括号里是匿名对象,无法访问

function proxy({data}){
 const obj = {}
 // 这里的 'n' 写死了,理论上应该遍历 data 的所有 key,这里做了简化
 // 因为我怕你们看不懂
 Object.defineProperty(obj, 'n', { 
  get(){
   return data.n
  },
  set(value){
   if(value<0)return
   data.n = value
  }
 })
 return obj // obj 就是代理
}

// data3 就是 obj
console.log(`需求三:${data3.n}`)
data3.n = -1
console.log(`需求三:${data3.n},设置为 -1 失败`)
data3.n = 1
console.log(`需求三:${data3.n},设置为 1 成功`)

可是如果不想用代理,要怎么做呢?

let myData = {n:0}
let data4 = proxy({ data:myData }) // 括号里是匿名对象,无法访问

// data3 就是 obj
console.log(`杠精:${data4.n}`)//0
myData.n = -1
console.log(`杠精:${data4.n},设置为 -1 失败了吗!?`)

现在这样还是能更改myData,所以我们又有一个需求:就算是用户擅自修改myData,也要拦截:

let myData5 = {n:0}
let data5 = proxy2({ data:myData5 }) // 括号里是匿名对象,无法访问

function proxy2({data}){
 // 这里的 'n' 写死了,理论上应该遍历 data 的所有 key,这里做了简化
 let value = data.n//保存开始的n
 Object.defineProperty(data, 'n', {//声明一个新的n
  get(){
   return value
  },
  set(newValue){
   if(newValue<0)return
   value = newValue
  }
 })

就加了上面几句,这几句话会监听 data

const obj = {}
 Object.defineProperty(obj, 'n', {
  get(){
   return data.n
  },
  set(value){
   if(value<0)return//这句话多余了
   data.n = value
  }
 })
 
 return obj // obj 就是代理
}

// data3 就是 obj
console.log(`需求五:${data5.n}`)//0
myData5.n = -1
console.log(`需求五:${data5.n},设置为 -1 失败了`)//0
myData5.n = 1
console.log(`需求五:${data5.n},设置为 1 成功了`)//1

当我们写vm = new Vue({data:myData})时,Vue做了两件事情:

  1. 让vm成为myData的代理(proxy),可以通过this访问vm
  2. 会对myData所有的属性进行监控,为了防止myData的属性变了,vm却不知道,知道了属性变化之后就可以调用render(data),UI就可以自动刷新

那么我们就可以回到标题了,什么是数据响应式呢?如果一个物体能够对外界的刺激做出反应,那么它就是响应式的。Vue的data是响应式的,const vm = new Vue({data:{n:0}})在这个代码中如果修改vm.n那么UI中的n就会做出相应的更新,Vue通过Object.defineProperty来实现数据响应式。
响应式网页又是什么呢?即如果改变窗口的大小,网页内容会做出相应的改变,那么这个网页就叫响应式网页。

以上就是Vue 数据响应式相关总结的详细内容,更多关于Vue 数据响应式的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue 表单输入框不支持focus及blur事件的解决方案
Nov 17 Vue.js
vue 插槽简介及使用示例
Nov 19 Vue.js
vue使用exif获取图片经纬度的示例代码
Dec 11 Vue.js
vue-cli4.0多环境配置变量与模式详解
Dec 30 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
vue中使用echarts的示例
Jan 03 Vue.js
vue 递归组件的简单使用示例
Jan 14 Vue.js
Vue SPA 首屏优化方案
Feb 26 Vue.js
Vue中foreach数组与js中遍历数组的写法说明
Jun 05 Vue.js
vue-router中hash模式与history模式的区别
Jun 23 Vue.js
Vue.Draggable实现交换位置
Apr 07 Vue.js
vue实现Toast组件轻提示
Apr 10 Vue.js
vue.js实现点击图标放大离开时缩小的代码
Jan 27 #Vue.js
vscode自定义vue模板的实现
Jan 27 #Vue.js
vue+echarts实现中国地图流动效果(步骤详解)
Jan 27 #Vue.js
vue3 watch和watchEffect的使用以及有哪些区别
Jan 26 #Vue.js
vue实现轮播图帧率播放
Jan 26 #Vue.js
vue 组件基础知识总结
Jan 26 #Vue.js
深入了解Vue动态组件和异步组件
Jan 26 #Vue.js
You might like
php cache类代码(php数据缓存类)
2010/04/15 PHP
composer.lock文件的作用
2016/02/03 PHP
yii2利用自带UploadedFile实现上传图片的示例
2017/02/16 PHP
thinkPHP5.0框架引入Traits功能实例分析
2017/03/18 PHP
PHP利用二叉堆实现TopK-算法的方法详解
2017/04/24 PHP
清华大学出版的事半功倍系列 javascript全部源代码
2007/05/04 Javascript
js循环改变div颜色具体方法
2013/06/25 Javascript
JS实现仿百度输入框自动匹配功能的示例代码
2014/02/19 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
2014/02/28 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
Javascript中的匿名函数与封装介绍
2015/03/15 Javascript
jQuery插件实现文字无缝向上滚动效果代码
2016/02/25 Javascript
jQuery插件EasyUI获取当前Tab中iframe窗体对象的方法
2016/08/05 Javascript
KnockoutJS 3.X API 第四章之数据控制流with绑定
2016/10/10 Javascript
jQuery实现圣诞节礼物动画案例解析
2016/12/25 Javascript
js实现导航跟随效果
2018/11/17 Javascript
微信小程序textarea层级过高的解决方法
2019/03/04 Javascript
element-ui 远程搜索组件el-select在项目中组件化的实现代码
2019/12/04 Javascript
[01:02]DOTA2辉夜杯决赛日 CDEC.Y对阵VG赛前花絮
2015/12/27 DOTA
python实现发送邮件及附件功能
2021/03/02 Python
简单了解OpenCV是个什么东西
2017/11/10 Python
Java编程迭代地删除文件夹及其下的所有文件实例
2018/02/10 Python
python微信跳一跳系列之自动计算跳一跳距离
2018/02/26 Python
Python处理中文标点符号大集合
2018/05/14 Python
使用python实现快速搭建简易的FTP服务器
2018/09/12 Python
详解安装mitmproxy以及遇到的坑和简单用法
2019/01/21 Python
django admin后台添加导出excel功能示例代码
2019/05/15 Python
pycharm修改file type方式
2019/11/19 Python
python 画3维轨迹图并进行比较的实例
2019/12/06 Python
python 实现有道翻译功能
2021/02/26 Python
餐厅楼面部长岗位职责范文
2014/02/16 职场文书
中学生关于梦想的演讲稿
2014/08/22 职场文书
2014公司年终工作总结
2014/12/19 职场文书
2015年度党风廉政建设工作情况汇报
2015/01/02 职场文书
公司老总年会致辞
2015/07/30 职场文书
Golang连接并操作MySQL
2022/04/14 MySQL