舟山企业网站建设,网站建设实践报告绪论,个人网站备案 费用,苏州网站推广电话系列文章目录
内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API#xff08;第一章#xff09;从Vue2到Vue3【二】Composition API#xff08;第二章#xff09;从Vue2到Vue3【三】Composition API#xff08;第三章#xff09;从Vue2到Vue3【四】C…系列文章目录
内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API第一章从Vue2到Vue3【二】Composition API第二章从Vue2到Vue3【三】Composition API第三章从Vue2到Vue3【四】Composition API第四章从Vue2到Vue3【五】从Vue2到Vue3【五】——新的组件Fragment、Teleport、Suspense从Vue2到Vue3【六】从Vue2到Vue3【六】——Vue3的改变文末送书 文章目录 系列文章目录前言一、Vue2中的响应式原理二、模拟简易版响应式原理三、Vue2响应式数据带来的缺陷3.1 新增属性的响应问题3.2 数组变动的响应问题3.3 对象属性的删除问题 四、Vue2响应式缺陷的解决办法4.1 新增属性的响应问题4.2 数组变动的响应问题4.3 对象属性的删除问题 总结 前言
Vue是一款流行的JavaScript框架它以其简洁易用的语法和强大的响应式能力而受到广泛关注。Vue的响应式数据机制是其核心特性之一它能够自动追踪数据的变化并实时更新相关的视图。然而Vue 2中的响应式数据机制并非完美无缺本文将探讨Vue 2响应式原理及其存在的缺陷。 一、Vue2中的响应式原理
Vue 2的响应式原理 在Vue 2中响应式是通过使用Object.defineProperty()方法来实现的。 在组件实例化过程中Vue会对数据对象data进行递归地遍历将每个属性都转换为getter/setter并且为每个属性创建一个依赖追踪的系统。当属性被访问或修改时getter/setter会触发依赖追踪系统从而进行依赖收集和派发更新以保证数据和视图的同步。具体实现步骤如下 1.创建Observer对象通过递归地将data对象的属性转换为响应式属性使用Object.defineProperty()为每个属性添加getter和setter方法。Vue2中 通过使用 Object.defineProperty() 方法将对象的属性转换成 getter 和 setter当数据发生变化时会自动触发相应的更新函数实现数据的响应式。 2.创建Dep对象用来管理 Watcher它用来收集依赖、删除依赖和向依赖发送消息等。用于解耦属性的依赖收集和派发更新操作。 3.创建Watcher对象Watcher对象用于连接视图和数据之间的桥梁当被依赖的属性发生变化时Watcher对象会接收到通知并更新视图。当数据发生变化时它会通知订阅该数据的组件更新视图。Watcher 在实例化时会将自己添加到 Dep 中当数据发生变化时会触发相应的更新函数。 4.模板编译Vue会解析模板将模板中的数据绑定指令转译为对应的更新函数以便在数据发生变化时调用。 在修改对象的值的时候会触发对应的 setter setter通知之前依赖收集得到的 Dep 中的Watcher告诉它自己的值改变了需要重新渲染视图。这时候这些 Watcher就会开始调用 update 来更新视图, 对应的getter触发追踪把新值重新渲染到视图上 input用v-model绑定数据我们需要在input元素上添加事件监听每当input事件被触发时就修改对应的data,data里的数据又会响应式更新回视图
二、模拟简易版响应式原理
实现思路 定义一个Observe构造函数用于对data对象的属性进行数据劫持。我们使用Object.defineProperty()方法对data对象的每个属性进行劫持定义了属性的getter和setter方法。 在getter方法中我们返回属性的值。在setter方法中我们判断新值是否与旧值不同如果不同则更新属性的值并触发依赖更新。
!DOCTYPE html
htmlheadmeta charsetUTF-8 /titleDocument/title/headbodyscript typetext/javascript let data {name:前端百草阁,age:21,}function Observer(obj){//汇总对象中所有的键形成一个数组const keys Object.keys(obj)//遍历keys.forEach((k){Object.defineProperty(this,k,{get(){return obj[k]},set(val){console.log(${k}被改了我要通知Vue重新去解析模板.....)obj[k] val}})})}//创建一个监视的实例对象用于监视data中属性的变化const obs new Observer(data) //准备一个vm实例对象let vm {}vm._data data obs/script/body
/html这个时候原先data里的属性就会各自有一个为他们服务的getter和setter变成了具有响应式的属性
简易式版本的缺陷 缺陷一正常vue中会做一个数据代理当访问vm.name时访问的其实是vm._data.name这样做了数据代理后使用起来更方便 缺陷二 简易式版本没有考虑到data里面的属性值还是对象的情况在Vue中利用递归的方法将data里所有的属性通过递归的方式都转换为了响应式属性即使属性值是一个数组数组里藏了对象依然可以把对应的属性转换为响应式属性 这里有一个小tips,利用this指向obs访问this(obs)里的属性getter返回的其实是obj里的属性(数据代理)为什么要这样呢如果说你访问obj里的属性我真的通过getter给你返回了obj里对应的属性返回的obj里的属性又要去触发自己的getter,那是不是就陷入死循环了呢导致的问题就是无论你是触发getter 还是setter都会导致超出最大调用堆栈这个错误 解决这个问题还有一个办法就是利用闭包利用闭包把初始值传给value存起来了后续getter和setter都是针对闭包内的value和原本的obj隔离开了,当你访问或者设置obj.key的时候就会去修改对应的val(由于闭包val不会被垃圾机制回收)就不存在最大调用堆栈溢出的情况了
function observe(obj) {if (!obj || typeof obj ! object) {return;}Object.keys(obj).forEach(function(key) {defineReactive(obj, key, obj[key]); });
}function defineReactive(obj, key, val) {observe(val); // 递归地对data对象的属性进行数据劫持Object.defineProperty(obj, key, {get: function() {return val;},set: function(newValue) {if (newValue ! val) {val newValue;// 触发依赖更新updateView();}}});
}function updateView() {document.querySelector(h1).innerText vm.message;
}// 初始化数据劫持
observe(vm.$data);在上述代码中observe函数用于递归地对data对象的属性进行数据劫持。在defineReactive函数中我们使用Object.defineProperty()方法对data对象的每个属性进行劫持定义了属性的getter和setter方法。 在getter方法中我们返回属性的值。在setter方法中我们判断新值是否与旧值不同如果不同则更新属性的值并触发依赖更新。 最后我们调用observe(vm.$data)来初始化数据劫持使得Vue能够捕获到对data对象属性的访问和修改操作并触发相应的依赖更新。 三、Vue2响应式数据带来的缺陷
Vue 2中的响应式数据存在一些缺陷但通过使用Vue提供的补救办法可以解决大部分响应式数据的问题。
3.1 新增属性的响应问题
Vue在初始化时会对data对象的属性进行数据劫持但是对于后续新增的属性Vue无法自动进行响应式处理。 Vue 无法探测普通的新增属性 比如 this.myObject.saying hi这个新增的saying属性是不具有响应式的Vue探测不到
3.2 数组变动的响应问题
Vue对数组的变动例如通过索引修改数组元素、通过splice方法删除或插入元素无法直接进行响应式处理。
例如此时在data里定义了这些数据 data:{friends:[{name:jerry,age:35},{name:tony,age:36},前端百草阁]}不难发现数组中的对象都是响应式的但数组中的普通元素却不是响应式的意味着若直接修改数组中的元素Vue无法监测到 如果你通过数组下标修改对象属性的话是可以监测的因为对象里的属性都是响应式的但如果你通过数组下标修改普通元素是无法监测到的 如果用一个新数组覆盖掉原先的数组Vue是能监测到的
3.3 对象属性的删除问题
Vue无法直接检测到对象属性的删除操作。 利用delete删除对象的属性无法被Vue监测到
四、Vue2响应式缺陷的解决办法
4.1 新增属性的响应问题
Vue.set( target, propertyName/index, value ) 向响应式对象中添加一个 property并确保这个新 property 同样是响应式的且触发视图更新。它必须用于向响应式对象上添加新 property因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty ‘hi’) 给data中的student对象添加一个属性并且是响应式的有两种写法Vue.set或者this.$set
// Vue.set(this._data.student,sex,男) // 这里加不加_data实际上都可以就是一个数据代理访问谁都一样那我们肯定选择偷懒啦
this.$set(this.student,sex,男) // this代表vm vue实例对象实现了新增了student对象里的sex属性并且该属性有为自己服务的getter、setter具有响应式
但是Vue官网明确指出注意对象不能是 Vue 实例或者 Vue 实例的根数据对象。 简单来说就是set方法的第一个参数target不允许 是vmvue实例、也不允许是vm._data根数据对象
4.2 数组变动的响应问题
第一中解决办法使用数组变异方法Vue提供了一些数组变异方法例如push、pop、shift、unshift、splice、sort和reverse这些方法会触发数组的响应式更新。 如果不是这七个方法的话比如调用slice等数组方法的话记得要把返回的新数组覆盖掉原来的旧数组依然能触发响应式 第二种解决办法利用set方法set方法不但能解决对象新增属性的问题还能解决修改数组的问题(用的不多)
4.3 对象属性的删除问题
Vue.delete方法用来删除对象的属性并触发响应式更新。例如可以使用Vue.delete(vm.someObject, ‘propertyToDelete’)来删除一个属性。 正常的delete方法虽然确实删除了属性但是无法被监测到 利用Vue.delete完美解决删除对象属性无法被监测的问题很少用到或者vm.$delete(vm.person,name) 总结
Vue 2的响应式数据机制在大多数情况下能够满足我们的需求但也存在一些缺陷。 首先Vue无法直接响应新增的属性需要使用特定的方法进行补救。其次对于数组的变动和对象属性的删除Vue也无法直接进行响应式处理需要使用相应的方法来触发更新。这些缺陷在实际开发中可能会带来一些困扰。 但幸运的是Vue提供了一些补救的办法如Vue.set和Vue.delete方法以及数组变异方法。通过这些补救措施我们可以弥补Vue 2响应式数据机制的不足提升开发效率和用户体验。尽管如此我们也期待Vue未来版本的改进在响应式数据方面能够更加智能和灵活以满足更多复杂场景的需求。