首页 > 语言 > JavaScript > 正文

Vue源码之关于vm.$delete()/Vue.use()内部原理详解

2024-05-06 15:39:57
字体:
来源:转载
供稿:网友

vm.$delete()

vm.$delete用法见官网。

为什么需要Vue.delete()?

在ES6之前, JS没有提供方法来侦测到一个属性被删除了, 因此如果我们通过delete删除一个属性, Vue是侦测不到的, 因此不会触发数据响应式。

见下面的demo。

<!DOCTYPE html><html lang="en"> <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <meta http-equiv="X-UA-Compatible" content="ie=edge" />  <title>Vue Demo</title>  <script src="https://cdn.jsdelivr.net/npm/vue"></script> </head> <body>  <div id="app">   名字: {{ user.name }} 年纪: {{ user.age }}   <button @click="addUserAgeField">删除一个年纪字段</button>  </div>  <script>   const app = new Vue({    el: "#app",    data: {     user: {      name: "test",      age: 10     }    },    mounted() {},    methods: {     addUserAgeField() {      // delete this.user.age; // 这样是不起作用, 不会触发数据响应式更新      this.$delete(this.user, 'age') // 应该使用     }    }   });  </script> </body></html>

源码分析内部实现

源码位置vue/src/core/instance/state.js的stateMixin方法

export function stateMixin (Vue: Class<Component>) {  ...    Vue.prototype.$set = set  Vue.prototype.$delete = del    ...}

然后查看del函数位置, vue/src/core/observer/index.js。

/** * Delete a property and trigger change if necessary. * target: 将被删除属性的目标对象, 可以是对象/数组 * key: 删除属性 */export function del (target: Array<any> | Object, key: any) { // 非生产环境下, 不允许删除一个原始数据类型, 或者undefined, null if (process.env.NODE_ENV !== 'production' &&  (isUndef(target) || isPrimitive(target)) ) {  warn(`Cannot delete reactive property on undefined, null, or primitive value: ${(target: any)}`) } // 如果target是数组, 并且key是一个合法索引,通过数组的splcie方法删除值, 并且还能触发数据的响应(数组拦截器截取到变化到元素, 通知依赖更新数据) if (Array.isArray(target) && isValidArrayIndex(key)) {  target.splice(key, 1)  return } // 获取ob const ob = (target: any).__ob__ // target._isVue: 不允许删除Vue实例对象上的属性 // (ob && ob.vmCount): 不允许删除根数据对象的属性,触发不了响应 if (target._isVue || (ob && ob.vmCount)) {  process.env.NODE_ENV !== 'production' && warn(   'Avoid deleting properties on a Vue instance or its root $data ' +   '- just set it to null.'  )  return } // 如果属性压根不在对象上, 什么都不做处理 if (!hasOwn(target, key)) {  return } // 走到这一步说明, target是对象, 并且key在target上, 直接使用delete删除 delete target[key] // 如果ob不存在, 说明target本身不是响应式数据, if (!ob) {  return } // 存在ob, 通过ob里面存储的Dep实例的notify方法通知依赖更新 ob.dep.notify()}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选