你知道Vue中神奇的$set是如何实现的吗?

当你使用Vue的时候,可能会遇到一种情况:当向一个已经定义好的Vue实例中给不存在的属性赋值时,这个属性不会自动响应式地更新视图。这是因为Vue在实例化时只对已经存在的属性设置了响应式,如果后续添加了新的属性,就需要手动调用$set去设置响应式。

$set实现的原理是通过调用对象的defineReactive()方法,将新增的属性动态转换成getter/setter,并将其添加到Vue实例的响应式数据中。定义响应式数据的过程需要从Vue源码中逐步分析。

首先在Vue.js中使用了defineProperty()方法来实现数据双向绑定的。在new Vue()初始化创建实例时,会调用initState()方法为实例添加响应式数据,最终走到set()方法,执行赋值操作时会调用defineReactive()方法进行Setter的监听。

defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
return val
},
set: function reactiveSetter(newVal) {
if (newVal === val) {
return
}
val = newVal
// 触发更新
dep.notify()
}
})
}

而$set()实现的关键在于调用了Vue源码核心所在的defineProperty()方法,并将属性设置为响应式:

Vue.set(obj, 'newkey', 123)

Vue源码如下--

function set (target: Array | Object, key: any, val: any): any {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(Cannot set reactive property on undefined, null, or primitive value: ${(target: any)})
}
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (target: any).ob
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
}
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}

举个实例:

let vm = new Vue({
  data: {
    person: {
      name: 'Tom'
    }
  }
})

vm.$set(vm.person, 'age', 20)

第一步,将vm.person传给$set(),这个person对象包含属性name。

第二步,调用Vue.set(obj, 'newkey', 123)为person对象动态添加age属性。Vue源码中判断age属性本来不存在,就会走到新添加属性的逻辑中,调用defineReactive()方法对其实现双向绑定。

第三步,这时候Vue已经将age属性转换成了getter/setter,并添加到了响应式数据中。这意味着,当不通过$set()而是直接通过person.age = 18修改age属性时,并不会触发视图更新。

所以说,当我们使用$set()方法时,$set()实际上是将数据变为响应式,即使数据是在定义实例后动态添加的。

再举一个实例:

let vmData = {
  person: {
    name: 'Tom'
  }
}

// 将vmData变成Vue实例的数据,使其响应式
let vm = new Vue({
  data: vmData 
})

// 这次不用$set,直接定义属性
vmData.person.age = 20

console.log(vmData.person.age) // 20

这里我们将vmData定义为一个普通的对象,并且在实例化Vue时将它作为响应式数据传入。接着,直接给person.age赋值,这样控制台输出的结果就是20。

这时你会发现,定义一个普通对象并将它作为响应式数据传入,这个对象的属性也会随着Vue实例的改变而改变,这是因为Vue在实例化时对所有属性都是自动进行了响应式的处理。

总之,$set() 就是为了解决Vue在实例化时无法自动新增属性并响应的问题。通过使用$set(),可以将新增的属性变成响应式的,从而触发组件的重新渲染视图。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:你知道Vue中神奇的$set是如何实现的吗? - Python技术站

(0)
上一篇 2023年5月29日
下一篇 2023年5月29日

相关文章

  • Vue Router 实现动态路由和常见问题及解决方法

    让我来详细讲解一下“Vue Router 实现动态路由和常见问题及解决方法”的完整攻略。 一、动态路由的实现 1. 动态路由的定义 Vue Router 的动态路由,是指路由路径中包含变量的路由。例如,我们需要设计一个新闻详情页的路由,每篇新闻的 ID 都不同,我们可以在路由路径中使用变量表示这个 ID,例如 /news/:id。 2. 动态路由的示例 Vu…

    Vue 2023年5月27日
    00
  • 图文讲解vue的v-if使用方法

    下面是图文讲解Vue的v-if使用方法的完整攻略: 一、v-if的基本使用 在Vue中,使用v-if指令可以根据表达式的真假值来有条件地渲染某个DOM元素。 <template> <div> <p v-if="flag">这是一段有条件渲染的文本</p> </div> </…

    Vue 2023年5月28日
    00
  • 一次用vue3简单封装table组件的实战过程

    下面给出使用Vue 3简单封装table组件的完整攻略: 1. 创建组件 首先,我们需要在Vue项目中创建一个table组件。可以通过以下命令创建: vue create my-app 其中,my-app是你的项目名称。 在创建好项目后,我们可以在src/components目录下创建一个table目录,并在其中添加Table.vue文件来实现Table组件…

    Vue 2023年5月28日
    00
  • 详解vue-cli 构建Vue项目遇到的坑

    详解vue-cli 构建Vue项目遇到的坑 简介 vue-cli是Vue.js官方提供的一款构建工具,可以快速创建单页应用或组件库,提供webpack打包、ES6转译、热更新等功能,可以大大减轻开发者的工作量。然而,使用vue-cli创建项目时,也会遇到各种坑,这里将对一些常见的问题进行详解。 坑1:vue-cli3无法预览组件库 使用vue-cli3创建组…

    Vue 2023年5月28日
    00
  • vue项目或网页上实现文字转换成语音播放功能

    实现文字转换成语音播放功能,需要用到Web API中的SpeechSynthesis接口,这是一个实现文本转语音的JavaScript接口。在Vue项目或网页中,可以通过以下步骤来实现: 步骤一:创建Vue组件 首先,需要创建一个Vue组件来实现文本转语音的功能。比如,在.vue文件中,可以创建一个包含输入框、按钮和语音播放控件的组件,如下所示: <t…

    Vue 2023年5月28日
    00
  • vue实现PC端录音功能的实例代码

    Vue实现PC端录音功能的实例代码需要通过JS录音库来实现,常用的开源录音库有Recorder.js和RecordRTC,这两个库都可以用于Vue项目的录音。 下面是实现步骤及示例代码: 步骤一:安装录音库 使用npm安装Recorder.js或RecordRTC npm install recorderjs npm install recordrtc 步骤…

    Vue 2023年5月28日
    00
  • 源码揭秘为什么 Vue2 this 能够直接获取到 data 和 methods

    为什么 Vue2 this 能够直接获取到 data 和 methods? 原因就在于Vue内部通过一些技巧将 data 和 methods 注入到组件实例上。在组件初始化的过程中,Vue会将 data 和 methods 进行响应式处理,并且将其转换为可观察的对象和函数。在此过程中,Vue会通过 Object.defineProperty() 把 data…

    Vue 2023年5月27日
    00
  • 在Vue3项目中使用如何echarts问题

    集成echarts到Vue3项目中 首先我们需要安装echarts库和vue-echarts库,打开命令行输入以下命令: npm install echarts vue-echarts 在Vue3项目中以组件的形式使用echarts,需要在组件中引入以下代码: import ECharts from ‘vue-echarts’ import ‘echarts…

    Vue 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部