vue实现双向绑定原理(vue实现双向数据绑定)
vue实现双向绑定原理
vue实现双向数据绑定本文实例为大家分享了vue实现双向数据绑定的具体代码,供大家参考,具体内容如下
vue中数组与对象采用了不同的绑定方式
1.vue对象数据绑定
(1)数据侦测
在js中,我们使用Object.defineProperty()和ES6的proxy来对对象进行侦测
在vue2.x中使用的是Object.defineProperty()来对对象进行数据侦测,我们首先对Object.defineProperty进行封装,有如下的代码:
function defineReactive(data, key, val){ if(typeof val === 'object') new Observer(val) let dep = new Dep(); Object.defineProperty(data, key, val) { enumerable: true, configurable: true, get: function () { dep.depend(); return val; }, set: function() { if(val === newVal) { return ; } val = newVal; dep.notify() } } }
需要传递的参数只有data, key, val,每当从data中的key中读取数据的时候触发get,修改的数据的时候触发set
(2)依赖收集
先收集依赖,等到属性发生改变的时候,再把收集到的依赖循环触发一遍就好了,在getter中收集依赖,在setter中触发依赖
依赖类Dep
export default class Dep { constructor() { this.subs = [] } addSub() { this.subs.push(sub) } removeSub(sub) { remove(this.subs, sub) } depend() { if(window.target) { this.addSub(window.target) } } notify() { const subs = this.subs.slice() for(let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } } function remove(arr, item) { if(arr.length) { const index = arr.indexOf(item) if(index > -1) { return arr.splice(index, 1) } } }
watcher类是我们收集的依赖
export default class Watcher { constructor(vm, expOrFn, cb) { this.vm = vm this.getter = parsePath(expOrFn) this.cb = cb this.value = this.get() } get() { window.target = this let value = this.getter.call(this.vm, this.vm) window.target = undefined return value } update() { const oldValue = this.value this.value = this.get() this.cb.call(this.vm, this.value, oldValue) } }
(3)递归侦测所有key (Observer)
export class Observer { constructor(value) { this.value = value; if(!Array.isArray(value)) { this.walk(value) } } walk(obj) { const keys = Object.keys(obj) for(let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i], obj[keys[i]]) } } }
Observer类就是将对象的所有属性变为响应式的
2.Array的变化侦测
(1)数组中追踪变化用的是拦截器覆盖原型方法
const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto); //和数组原型一样的对象作为拦截器 ['push','pop','shift','unshift','splice','sort','reverse'].forEach(function (method) { const original = arrayProto[method] Object.defineProperty(arrayMethods, method, { value: function mutator(...args) { return original.apply(this, args) }, enumerable: false, writable: true, configurable: true }) })
拦截器覆盖原型只有一句话
value.__proto__ = arrayMethods
如果没有__proto__属性,vue将会把这些arrayMethods挂载到被侦测的数组上
数组与对象类似,都是在getter中收集依赖,而数组触发依赖实在拦截器里面
数组的依赖保存在Observer实例上,依赖必须是getter和拦截器中都可以访问到的
__ob__是不可枚举属性,这个属性的值就是当前Observer实例
把Dep实例保存在Observer的属性上,如果value已经有__ob__属性,则不需要重复创建Observer实例,避免重复侦测value的变化
像数组的依赖发送通知
this.__ob__.dep.notify();
(2).侦测数据变化的具体方法
循环数组中的每一项,执行observe函数来侦测变化
observeArray(items) { for(let i = 0; l = items.length; i < l; i++) { observe(items[i]); } }
数组需要侦测新的元素
通过拦截push,unshift,splice等方法,并且把args存储在inserted中
if(inserted) ob.observeArray(inserted)
总结:
Array追踪变化的方式和Object不一样,所以我们通过创建拦截器去覆盖数组原型的方式来追踪变化,为了不污染全局Array.prototype,我们在Observer中只针对需要侦测变化的数组使用__proto__来覆盖原型。
Array收集依赖的方式和Object一样,都在getter中收集,在拦截器中触发,依赖保存在Observer实例上。在Observer上,我们每个侦测的数据都标记上了__ob__,并把this(Observer)保存在__ob__上,主要是为了保证同一数据只被侦测一次,另外可以很方便的通过__ob__从而拿到Observer实例上保存的依赖。数组需要循环把每一个数组项都变成响应式的,当数组中新增元素的时候,我们把参数提取出来,然后使用observeArray对新增的数据进行变化侦测,对于数组,只能拦截原型方法,对于一些特有的方法就无法拦截。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持开心学习网。
- vue实现一个炫酷的日历组件(vue利用Moment插件格式化时间的实例代码)
- vue2和vue3都如何创建项目(vue3.0+vite2实现动态异步组件懒加载)
- springboot+vue项目演示(springboot+VUE实现登录注册)
- vue3组件通讯消息(Vue3实现Message消息组件示例)
- dockernginx服务器教程(Docker镜像+nginx 部署 vue 项目的方法)
- vue左右滑动切换(vue实现界面滑动效果)
- vue 底层原理(浅谈Vue插槽实现原理)
- vue滚动条下拉翻页(Vue中利用better-scroll组件实现横向滚动功能)
- vue左侧边栏的制作(Vue+Vant实现顶部搜索栏)
- vue 为什么使用虚拟dom(Vue虚拟Dom到真实Dom的转换)
- vue pdf预览插件(Vue-pdf实现在线预览PDF文件)
- vue编程加入购物车(vuex实现简单的购物车功能)
- vue虚拟滚动条(vue轻松实现虚拟滚动的示例代码)
- vue找不到水印设置(Vue使用自定义指令实现页面底部加水印)
- vue三种判断条件(Vue中插槽和过滤器的深入讲解)
- 使用vue独立开发组件(vue单文件组件的实现)
- 吐槽完《弧光大作战》之后,我们和设计师聊了聊魔兽首款手游的立项初衷和未来(吐槽完弧光大作战之后)
- 魔兽争霸3自定义战役少年杰雷 2(魔兽争霸3自定义战役少年杰雷)
- 今日菜价 芥兰涨幅最高 1.33 ,花菜降幅最高 3.10(今日菜价芥兰涨幅最高)
- 今日菜价 椰菜涨幅最高 3.25 ,水空心菜降幅最高 2.58(今日菜价椰菜涨幅最高)
- 今日菜价 红三鱼涨幅最高 4.41 ,黄鳝降幅最高 5.06(红三鱼涨幅最高)
- 今日菜价 西生菜涨幅最高 6.19 ,生菜降幅最高 5.38(西生菜涨幅最高)
热门推荐
- SQLServer2019安装教程图文详解(SQLServer2019安装教程图文详解)
- Sql Server profiler 分析器的理解
- linux查看负载命令(在Linux命令行中使用计算器的5个命令详解)
- vue-cli安装教程学习(Vue新手指南之创建第一个vue-cli脚手架程序)
- MySQL与Oracle数据类型对应关系
- zabbix数据库解析(zabbix agent2 监控oracle数据库的方法)
- vue怎么实现预览与放大(Vue实现牌面翻转效果)
- nvarchar(max)
- pythonlist类型教程(Python List cmp知识点总结)
- 怎么用腾讯云主机搭建网站(用云主机怎么搭建网站?云主机建网站完整流程)