首页 > 其他分享 >vue2-vm.$set,vm.$delete实现(三)

vue2-vm.$set,vm.$delete实现(三)

时间:2022-11-22 10:24:02浏览次数:45  
标签:__ set return vue2 val ob vm key target

vm.$set实现

语法: vm.$set(target, key, value)
参数:

{Object | Array} target
{String | Number} key
{any} value
返回值:{Function} unwatch

用法: 在object上设置一个属性,如果object 是响应式的, 那么添加的属性也会变为响应式。 这个方法可以用来避开 Vue.js不能侦测属性被添加的限制;

下面开始实现
首页给Vue挂载set方法

import {set} from './Observer'
Vue.prototype.$set = set

在Observer.js中添加 set方法
先处理数组方法

// 添加 set方法
export function set(target, key, val){

  // 如果 是数组,并且key 是有效的索引值
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 获取数组的最长的长度 ,有可能是 修改 list某一项,有可能是新增某一项
    target.length = Math.max(target.length, key)
    // 数组的 splice方法已经被侦测,索引调用splice方法会 自动触发依赖更新
    target.splice(key, 1, val)
    return val
  }
}

由于是给响应式数据target 设置新的 值key,并且变为响应式 。所以数组target的 七个方法 已经被处理为响应式了。直接添加或修改就行;

接下里处理对象 中已经存在的值

  // key已经存在 target中。那么key本来就是响应式的,这里只需要修改值就行
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }

处理对象 的新增

  // 获取 target的__ob__属性
  const ob = target.__ob__
  // 如果 是 VUe.js实例 或者 是根数据对象 直接返回并 不是生产环境警告
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  // 如果没有 __ob__,那么 target不是响应式的,直接修改返回(前提是响应式对象新增值才能变为响应式)
  if (!ob) {
    target[key] = val
    return val
  }
  // 给 target__ob__value 就是自己, 把新增 属性转换为响应式
  defineReactive(ob.value, key, val)
  // 通知 依赖更新
  ob.dep.notify()
  return val

上面会先判断 target不能是Vue的实例或者是Vue实例的根数据对象(this.$data), 再来判断 target 必须是响应式的前提下,再来给新增属性 调用defineReactive转换为响应式,之后自动 通知依赖更新;

Observer.js中 关于 set 的完整代码

export function set(target, key, val) {

  // 如果 是数组,并且key 是有效的索引值
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 获取数组的最长的长度 ,有可能是 修改 list某一项,有可能是新增某一项
    target.length = Math.max(target.length, key)
    // 数组的 splice方法已经被侦测,索引调用splice方法会 自动触发依赖更新
    target.splice(key, 1, val)
    return val
  }
  // key已经存在 target中。那么key本来就是响应式的,这里只需要修改值就行
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }

  // 获取 target的__ob__属性
  const ob = target.__ob__
  // 如果 是 VUe.js实例 或者 是根数据对象 直接返回并 不是生产环境警告
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  // 如果没有 __ob__,那么 target不是响应式的,直接修改返回(前提是响应式对象新增值才能变为响应式)
  if (!ob) {
    target[key] = val
    return val
  }
  // 给 target__ob__value 就是自己, 把新增 属性转换为响应式
  defineReactive(ob.value, key, val)
  // 通知 依赖更新
  ob.dep.notify()
  return val
}

vm.$delete实现

语法: vm.$delete(target, key)
参数:

{Object | Array} target
{String | Number} key
用法: 删除对象的属性。如果对象是响应式的,需要确保删除能触发更新视图(通知依赖更新)。避开vue.js不能检测属性被删除的限制;

代码实现

import {del} from './Observer'
Vue.prototype.$delete = del

Observer.js中实现 del方法


// 添加delete方法
export function del (target, key) {
  // 如果是数组,切key是下有效的
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 直接 删除就行  如果target 是响应式的,那么splice方法会自动触发依赖更新
    target.splice(key, 1)
    return
  }
  // 获取 __ob__
  const ob = target.__ob__
  // 判断 target 不能是Vue实例 且 不能是 Vue实例 的根属性对象
  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
  }
  // 如果key 不是target自身的属性, 停止程序继续执行
  if (!hasOwn(target, key)) {
    return
  }
  //  删除对象 上的 key值
  delete target[key]
  // 如果不是响应式 对象 直接返回
  if (!ob) {
    return
  }
  // 响应式对象的话 ,通知依赖更新
  ob.dep.notify()
}

del方法 其实上就是
delete this.obj.name // 删除对象上的值
this.obj__ob__.notify // 手动触发依赖更新

在代码中 多了一些边际判断而已

标签:__,set,return,vue2,val,ob,vm,key,target
From: https://www.cnblogs.com/Sultan-ST/p/16914258.html

相关文章

  • 浅析vm.$set方法
    先上官方文档:vm.$set(target,propertyName/index,value)参数:{Object|Array}target{string|number}propertyName/index{any}value返回值:设置的值。用法:......
  • 重新认识下JVM级别的本地缓存框架Guava Cache——优秀从何而来
    大家好,又见面了。本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面。如果感兴趣,欢迎关注以获取后续更新。不......
  • MAUI新生1.6-XAML语法基础:样式风格Style&Settter
    一、样式的定义和使用Style类似于前端的CSS,可以对视觉元素的样式进行有组织的管理,大量减少代码和重复工作量。Style需要结合资源字典使用,将Style定义在资源字典中,元素通过......
  • jstat查看jvm的GC情况[转]
    jps(JavaVirtualMachineProcessStatusTool)是JDK1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情......
  • set ip next-hop verify-availabitity
    setipnext-hopverify-availabitity   R2配置setipnext-hopverify-availabitity 让路由器搜索CDP邻居表来验证下一跳地址是否在列表中,如果不在,       ......
  • Pod控制器详解(StatefulSet)
    StatefulSet(有状态)概述无状态应用:认为Pod都是一样的。没有顺序要求。不用考虑在哪个Node节点上运行。随意进行伸缩和扩展。有状态应用:有顺序的要求。认为每个......
  • JVM笔记4-垃圾回收
    文章目录视频资源地址笔记资源地址我的笔记48-49.判断垃圾-引用计数50.可达分析51.可达分析-根对象视频资源地址B站https://www.bilibili.com/video/av7054......
  • Spring-IoC中Set和构造器注入
     新建Maven工程  修改pom文件1<?xmlversion="1.0"encoding="UTF-8"?>2<projectxmlns="http://maven.apache.org/POM/4.0.0"3xmlns:xsi="http......
  • 【菜菜的sklearn课堂笔记】支持向量机-线性SVM用于分类的原理
    视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili本节要注意一下决策边界和决策边际的概念。以上一节的二维数据为......
  • JVM虚拟机(整体架构、类文件结构)我来了~~~
    虚拟机1.1发展历程1.1.1java往事​ Java诞生在一群懒惰、急躁而傲慢的程序天才之中。​ 1990年12月,Sun的工程师PatrickNaughton被当时糟糕的SunC++工具折磨的快疯......