你知道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项目实现共用一个node-modules文件夹

    实现多个Vue项目共用一个node_modules文件夹可以通过以下步骤: 将node_modules文件夹移动到一个独立的位置,并确保该位置对所有项目都可访问。例如,在你的根目录下创建一个名为shared的文件夹,并将node_modules文件夹移动到该文件夹中。 在每个项目的根目录下都创建一个名为node_modules的符号链接,并将其指向上述位置的…

    Vue 2023年5月28日
    00
  • web前端vue实现插值文本和输出原始html

    要实现通过Vue进行插值文本和输出原始HTML,我们需要掌握以下几个核心概念: 插值表达式:Vue使用双括号{{}}进行插值,将绑定的数据渲染到模板中。 v-html指令:Vue中的v-html指令可用于输出被渲染为HTML的数据,但要注意防止XSS攻击。 以下是详细步骤: 1. 插值表达式 在Vue中,我们可以使用插值表达式来动态地将数据展示到模板中。插值…

    Vue 2023年5月28日
    00
  • vue项目前端埋点的实现

    下面是关于“vue项目前端埋点实现”的完整攻略: 什么是前端埋点? 前端埋点是指在页面中添加一些跟踪代码,记录用户行为、操作等数据,并将这些数据发送到后台进行统计分析的过程。前端埋点可以用来了解用户的兴趣、行为习惯等,方便网站开发者及时发现问题,为优化网站提供数据支持。 前端埋点的实现方式 前端埋点的实现方式通常有两种,一种是通过在路由钩子函数中进行埋点,另…

    Vue 2023年5月29日
    00
  • 利用Vue Native构建移动应用的全过程记录

    利用Vue Native构建移动应用的全过程记录 Vue Native 是一个利用 Vue.js 和 React Native 建立移动应用程序的框架,使开发人员拥有更好的体验和开发效率。 准备工作 安装 Node.js 和 npm 安装 Vue CLI 和 React Native 命令行工具 (CLI) 安装 Expo 命令行工具 编辑器:推荐使用 Vi…

    Vue 2023年5月27日
    00
  • 详解Vue实现直播功能

    详解Vue实现直播功能 概述 Vue是一款流行的前端框架,提供了一种现代化的方式来构建交互式用户界面。在这篇文章中,我们将详细介绍如何在Vue应用中实现直播功能。 实现步骤 1. 前置条件 在开始实现直播功能之前,需要确保读者已经掌握以下的前置知识: Vue.js基础 Node.js基础 WebSocket协议 2. 构建Vue应用 首先,我们需要使用Vue…

    Vue 2023年5月28日
    00
  • 配置vue全局方法的两种方式实例

    当我们在使用 Vue.js 开发时,我们经常需要在多个组件中使用同一个方法,这时候可以将这个方法作为全局方法。Vue.js 提供了两种方式来配置全局方法。 1.通过 Vue.prototype 实现全局方法 在 Vue.js 初始化时可以通过 Vue.prototype 给 Vue 实例添加自定义属性。通过 Object.defineProperty 实现这…

    Vue 2023年5月28日
    00
  • vue3如何实现挂载并使用axios

    当我们使用Vue3框架开发应用程序时,我们需要使用Axios实现数据通信。在Vue3中,Axios是一个可以在后台执行请求的JavaScript库。在本篇攻略中,我们将会介绍如何在Vue3中挂载及使用Axios。以下分为以下五个步骤: 安装Axios 在Vue3中使用Axios需要安装Axios。你可以通过npm或者yarn进行安装Axios: npm in…

    Vue 2023年5月28日
    00
  • vue 组件开发原理与实现方法详解

    Vue 组件开发原理与实现方法详解 Vue 组件是 Vue.js 中的一个重要概念,允许我们将一个页面拆分成多个独立的、可复用的部分,并且每个组件拥有自己的数据、样式和行为。组件化开发大大提高了应用程序的可维护性和可扩展性。 本文将从以下三个方面介绍 Vue 组件开发的原理和实现方法: 组件的基本原理 组件的实现方法 Vue 组件的使用示例 一、组件的基本原…

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