Vue.observable的理解

news2024/12/4 2:59:25

 

一、Observable 是什么

Observable 翻译过来我们可以理解成可观察的

先来看其在Vue中的定义

Vue.observable,让一个对象变成响应式数据。Vue 内部会用它来处理 data 函数返回的对象

返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器

Vue.observable({ count : 1})

其作用等同于

new vue({ count : 1})

 Vue 2.x 中,被传入的对象会直接被 Vue.observable 变更,它和被返回的对象是同一个对象

 Vue 3.x 中,则会返回一个可响应的代理,而对源对象直接进行变更仍然是不可响应的

二、使用场景

在非父子组件通信时,可以使用通常的bus或者使用vuex,但是实现的功能不是太复杂,而使用上面两个又有点繁琐。这时,observable就是一个很好的选择

创建一个js文件 

// 引入vue
import Vue from 'vue
// 创建state对象,使用observable让state对象可响应
export let state = Vue.observable({
  name: '张三',
  'age': 38
})
// 创建对应的方法
export let mutations = {
  changeName(name) {
    state.name = name
  },
  setAge(age) {
    state.age = age
  }
}

.vue文件中直接使用即可

<template>
  <div>
    姓名:{{ name }}
    年龄:{{ age }}
    <button @click="changeName('李四')">改变姓名</button>
    <button @click="setAge(18)">改变年龄</button>
  </div>
</template>
import { state, mutations } from '@/store
export default {
  // 在计算属性中拿到值
  computed: {
    name() {
      return state.name
    },
    age() {
      return state.age
    }
  },
  // 调用mutations里面的方法,更新数据
  methods: {
    changeName: mutations.changeName,
    setAge: mutations.setAge
  }
}

 
三、原理分析

源码位置:src\core\observer\index.js

export function observe (value: any, asRootData: ?boolean): Observer | void {
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob: Observer | void
  // 判断是否存在__ob__响应式属性
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    shouldObserve &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    // 实例化Observer响应式对象
    ob = new Observer(value)
  }
  if (asRootData && ob) {
    ob.vmCount++
  }
  return ob
}

 Observer

export class Observer {
    value: any;
    dep: Dep;
    vmCount: number; // number of vms that have this object as root $data

    constructor (value: any) {
        this.value = value
        this.dep = new Dep()
        this.vmCount = 0
        def(value, '__ob__', this)
        if (Array.isArray(value)) {
            if (hasProto) {
                protoAugment(value, arrayMethods)
            } else {
                copyAugment(value, arrayMethods, arrayKeys)
            }
            this.observeArray(value)
        } else {
            // 实例化对象是一个对象,进入walk方法
            this.walk(value)
        }
}

 walk函数

walk (obj: Object) {
    const keys = Object.keys(obj)
    // 遍历key,通过defineReactive创建响应式对象
    for (let i = 0; i < keys.length; i++) {
        defineReactive(obj, keys[i])
    }
}

 defineReactive方法

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  const dep = new Dep()

  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }

  let childOb = !shallow && observe(val)
  // 接下来调用Object.defineProperty()给对象定义响应式属性
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      // #7981: for accessor properties without setter
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      // 对观察者watchers进行通知,state就成了全局响应式对象
      dep.notify()
    }
  })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/553258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDF.js实现按需分片加载pdf文件-包含前后端开发源码和详细开发教程

PDF.js实现按需加载pdf文件 说明前言前端项目分片加载的效果前端项目结构前端核心代码项目运行与访问 后端项目项目结构核心代码实现注意事项 项目源码 说明 本文主要是介绍pdf.js的前后端项目的实现&#xff0c;包含可直接运行的源码。由于本人偏向于后端开发&#xff0c;因此…

Redis设计逻辑及生产部署问题整理

数据结构 redis数据结构包括&#xff1a;简单动态字符串SDS、链表、字典、跳跃表、整数组合、压缩列表。 SDS&#xff1a;在增加/减少字符串时不会频繁进行内存充分配&#xff0c;采用了空间预分配和惰性空间释放两种优化策略。 链表&#xff1a;链表节点使用void*保存节点值&a…

Stable Diffusion Web-UI 安装指南

Stable DIffusion 是 Stability.AI 开源的 text-to-image 模型&#xff0c;目前类似产品有 Midjourney 以及 OpenAI 的 DELL-2 &#xff1b;从AI绘画效果上来说&#xff0c;Midjourney 目前公认是最好的&#xff1b;但从模型的可玩性和发展潜力来看&#xff0c;个人观点来看&am…

【009】C++数据类型之转义字符和类型转换

C数据类型之转义字符和类型转换 引言一、转义字符1.1、概念1.2、八进制转义1.3、十六进制转义 二、类型转换2.1、自动类型转换原则2.2、强制类型转换 三、C新特性中类型转换的扩展3.1、隐式类型转换3.2、显式类型转换 总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高…

Packet Tracer – 配置单臂路由器 VLAN 间路由

Packet Tracer – 配置单臂路由器 VLAN 间路由 地址分配表 设备 接口 IPv4 地址 子网掩码 默认网关 R1 G0/0.10 172.17.10.1 255.255.255.0 不适用 G0/0.30 172.17.30.1 255.255.255.0 不适用 PC1 NIC 172.17.10.10 255.255.255.0 172.17.10.1 PC2 NIC 1…

游乐园里,一边带小孩,一边写代码,分享一些有趣好玩儿的嵌入式软硬件资讯...

作者&#xff1a;晓宇&#xff0c;排版&#xff1a;晓宇 微信公众号&#xff1a;芯片之家&#xff08;ID&#xff1a;chiphome-dy&#xff09; 01 边带小孩边写代码 以前觉得&#xff0c;自己下班后都还有大把时间&#xff0c;下班了回到家还能再干个两三个小时&#xff0c;学…

定义运营系统架构

介绍 供应商提供的信息系统随着新功能和实施策略不断发展。可用选项的复杂性和多样性使许多公司难以充分讨论和比较可能满足或不满足其要求的替代方案。 供应商通常会推广由公司或个人工具箱中的产品或解决方案支持的架构。如果公司对其运营系统的架构没有清晰的愿景&#xf…

第九章:C语言的简单结构体

作为一个人有什么关于人的属性呢&#xff1f;简单的梳理一下&#xff0c;人的属性有自己的名字&#xff0c;年龄&#xff0c;身高&#xff0c;体重...。当然关于人的属性还有很多&#xff0c;当我们C语言来描述一下人的属性&#xff0c;就需要定义多个变量&#xff0c;那我们这…

21天学会C++:Day4----函数重载

CSDN的uu们&#xff0c;大家好。这里是C入门的第四讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. 函数重载的知识点 2. 为什么C语言不支持函数重载而C支持呢&…

springboot贫困生勤工助学评定管理系统

本系统尝试使用springboot在网上架构一个动态的贫困生管理系统&#xff0c;以使每一用户在家就能通过系统来进行贫困生管理。 Spring Boot 是 Spring 家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程。也可以说 Spring Boot 能简化我们之前采用S…

数据结构学习记录——图应用实例-拯救007(问题描述、解题思路、伪代码解读、C语言算法实现)

目录 问题描述 解题思路 伪代码 总体算法 DFS算法 伪代码解读 总体算法 DFS算法 具体实现&#xff08;C语言&#xff09; 问题描述 在老电影“007之生死关头”&#xff08;Live and Let Die&#xff09;中有一个情节&#xff0c;007被毒贩抓到一个鳄鱼池中心的小岛…

Matlab - Plot in plot(图中画图)

Matlab - Plot in plot&#xff08;图中画图&#xff09; 这是在MATLAB中创建一个嵌入式图形的示例&#xff0c;可以在另一个图形中显示。 与MATLAB中的“axes”函数相关。 Coding % Create data t linspace(0,2*pi); t(1) eps; y sin(t);% Place axes at (0.1,0.1) with w…

学系统集成项目管理工程师(中项)系列24a_信息系统集成专业技术知识(上)

1. 信息系统的生命周期 1.1. 【19下选10】 1.2. 立项 1.2.1. 形成《需求规格说明书》并确定立项 1.2.1.1. 【21上选11】 1.3. 开发 1.3.1. 【22下选10】 1.3.2. 以立项阶段所做的需求分析为基础&#xff0c;进行总体规划。之后&#xff0c;通过系统分析、系统设计、系统…

ChatGPT4 镜像网站推荐

文章目录 1. TomChat2. Ai Doge3. 二狗问答4. 小莓用AI5. Ora6. ChatGPT镜像7. ChatGPT镜像8. VIVI-AI9. 小杰AI10. ChatGPT Web11. AIchatOS 什么是ChatGPT? ChatGPT&#xff0c;全称&#xff1a;聊天生成预训练转换器&#xff08;英语&#xff1a;Chat Generative Pre-train…

辅助驾驶功能开发-功能规范篇(16)-2-领航辅助系统NAP-HMI人机交互

书接上回 2.3.7HMI人机交互 2.3.7.1显示 (1)图标 序号 图标状态 (图形、颜色供参考) 含义说明 备注 1 辅助驾驶功能READY

Winform窗体利用WebApi接口实现ModbusTCP数据服务

在上位机开发过程中&#xff0c;有时候会遇到需要提供数据接口给MES或者其他系统&#xff0c;今天跟大家分享一下&#xff0c;如何在Winform等桌面应用程序中&#xff0c;开发WebApi接口&#xff0c;提供对外modbus设备的数据服务。通讯模型是&#xff1a; 为了更好地演示应用场…

华为OD机试真题 Java 实现【简单的解压缩算法】【2023Q1 200分】

一、题目描述 现需要实现一种算法&#xff0c;能将一组压缩字符串还原成原始字符串&#xff0c;还原规则如下&#xff1a; 1、字符后面加数字N&#xff0c;表示重复字符N次。例如&#xff1a;压缩内容为A3&#xff0c;表示原始字符串为AAA。 2、花括号中的字符串加数字N&…

MyBatis环境搭建+第一个MyBatis程序

目录 1.MyBatis是什么&#xff1f; 2.MyBatis开发环境搭建 3.我的第一个MyBatis程序 1.MyBatis是什么&#xff1f; MyBatis是一款数据库框架&#xff0c;是一款优秀的持久层框架&#xff0c;它不仅支持用户自定义SQL和存储过程&#xff0c;而且还具有高级映射功能。简单来说…

【重新定义matlab强大系列九】函数isoutlier查找数据中的离群值

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

【TikZ 简单学习(上):基础绘制】Latex下的绘图宏包

【TikZ 简单学习[上]基础绘制】Latex下的绘图宏包 前置简单图形绘制基本架构路径绘制添加样式/风格弧线绘制剪切抛物线和正弦曲线绘制填充和绘制渲染绘制箭头循环添加文本信息绘制一个角度 前置 Latex 可以解决绘制这些东西&#xff1a; ∫ a b 1 x d x \int_a^b\frac{1}{x}dx…