惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
博客园 - 三生石上(FineUI控件)
V
V2EX
博客园 - 司徒正美
小众软件
小众软件
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
雷峰网
雷峰网
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
爱范儿
爱范儿
博客园 - 聂微东
量子位
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Vercel News
Vercel News

韩小韩博客

你还在用真实邮箱注册网站?等等,你真的想清楚了吗? IPFS星际文件系统 最新二合一收款码 - 物理合并版 从Hexo到Astro博客1分钟迁移指南 Astro 添加 Waline 评论组件 腾讯云 EdgeOne Pages 实测对比:能否成为国内开发者的 Cloudflare Pages 最佳平替? Astro 中使用 Lenis 增加鼠标滚动阻尼感 一组手机和电脑动态壁纸分享【分享】 Astro 添加 Twikoo 评论组件 Astro主题-优雅的vhAstro-Theme【使用文档】 Fetch的GET、POST简单HTTP请求封装 一些实拍的手机壁纸 大理And威海【图】 很喜欢西湖的水【转自:狮子狮子鱼】 Tarot-塔罗牌占卜 Web Watermark 图片添加水印在线小助手 HanAnalytics访问分析Web统计托管于(Cloudflare Pages) 基于AI的微博动态心情分析 阿里云免费用9年ecs教程【适合轻量化服务如frp】 Cloudflare优选IP➕DnsPod的DDNS自动切换 混沌神器Clash全家桶 卷王都在用的变态休息法 NodeJs文本相似度去重脚本 骤雨重山无限存储图床托管于(Cloudflare Pages) 分享好看的天空和云(长期更新) Typecho转到Hexo(主题由Typecho-Joe-Theme转Butterfly主题) Typecho评论导出为Hexo的Valine、Twikoo等评论所支持的JSON文件 Safari浏览器内容被地址栏、菜单栏或工具栏遮挡导致的兼容问题 拼夕夕快速提现100元攻略 2024 平安喜乐
Vue.set与this.$set源码
.𝙃𝙖𝙣 · 2026-04-11 · via 韩小韩博客

avatar

.𝙃𝙖𝙣

一点 0分钟

Code

Vue.set()和this.$set()应用的场景

在 Vue 2.X 项目开发中,有时候需要对数组进行修改,或是对对象新增一个属性,但是发现页面并不会同步更新。例如:

const vm = new Vue({
  data: {
    arr: [1, 2],
    obj: {
      a: 3,
    },
  },
});
vm.$data.arr[0] = 3; // 页面不会发生改变
vm.$data.obj.b = 3; // 页面不会发生改变

此时就需要使用到 Vue.set() 或 this.$set()。这个2个的使用方法一样,不过一个是挂载在Vue身上,一个挂载在Vue.prototype上

// Vue.set
import { set } from "../observer/index";
Vue.set = set;
// this.$set
import { set } from "../observer/index";
Vue.prototype.$set = se;

使用Vue.set或this.$set来实现页面不更新的问题:

const vm = new Vue({
  data: {
    arr: [1, 2],
    obj: {
      a: 3,
    },
  },
});
// 修改数组
Vue.set(vm.$data.arr, 0, 3);
vm.$set(vm.$data.arr, 0, 3);
// 对象新增属性
Vue.set(vm.$data.obj, "b", 3);
vm.$set(vm.$data.obj, "b", 3);

set函数的源代码

../observer/index

function set (target: Array<any> | Object, key: any, val: any): any {
  // isUndef(target):用于判断传入的target是否是undefined或null
  // isPrimitive(target):用于判断传入的target是否是原始数据类型
  // 如果是 null 或者是 undefined 时,抛出异常
  if (process.env.NODE_ENV !== 'production' &&(isUndef(target) || isPrimitive(target))) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }

  // 如果传入了一个数组,并且传入的key是数组的有效值
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 用于设置数组的最大length
    // Math.max(target.length, key):取数组的length和key二者中的最大值
    target.length = Math.max(target.length, key)
    // 直接调用数组身上的splice方法,因为Vue里变异了数组方法,调用会触发dep.notify()
    target.splice(key, 1, val)
    return val
  }

  // 接下来就是对象的判断了
  // 如果传入的 key 在原对象中,说明已经是响应式了,直接修改即可
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }

  // 这里到最后的代码,都是对象不在原对象上,是新增的属性值
  const ob = (target: any).__ob__
  // 如果是Vue实例对象,或根数据对象,则抛出警告
  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
  }

  // 剩下就是给响应式对象增加一个 key 新属性,并通知更新
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}
Vue