vue源码(二)
文章目录
- 数据代理
- 示例
- 初始化组件实例
- 计算属性
- 基本用法
- ComputedReflmpl类
- 计算属性的创建
- Vue3的特点及优势
- 声明式框架
- 采用虚拟DOM
- 区分编译时和进行时
- Vue3设计思想
数据代理
示例
以下代码主要是有一个msg的响应式数据,点击按钮后修改msg的内容。根据代码可知有两处都存在msg,那么,界面显示的内容是什么?点击按钮修改的又是哪一部分数据?
<template><p>{{ msg }}</p><button @click="changeMsg">点击试试</button>
</template>
<script>import { ref } from 'vue'export default {data() {return {msg: 'msg from data'}},setup() {const msg = ref('msg from setup')return {msg}},methods: {changeMsg() {this.msg = 'change'}}}
</script>
初始化组件实例
setCompontent在源码中的实现
export function setupComponent(instance, isSSR = false) {const { props, children } = instance.vnode// 判断组件是否是有状态的组件const isStateful = isStatefulComponent(instance)// 初始化 propsinitProps(instance, props, isStateful, isSSR)// 初始化 slotsinitSlots(instance, children)// 如果是有状态组件,那么去设置有状态组件实例const setupResult = isStateful? setupStatefulComponent(instance, isSSR): undefinedreturn setupResult
}
在以上setComponent中,组件渲染之后设置组件的状态,通过 isStatefulComponent(instance) 判断是否是有状态的组件,initProps 初始化 props;initSlots 初始化 slots;
根据组件是否是有状态的,来决定是否需要执行 setupStatefulComponent 函数。
判断是否有状态的组件的函数
function isStatefulComponent(instance) {return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
}
setupStatefulComponent函数
setupStatefulComponent就是设置有状态组件,对于有状态组件,Vue内部会保留组件状态数据
function setupStatefulComponent(instance, isSSR) {// 定义 Component 变量const Component = instance.type// 1. 创建渲染代理的属性访问缓存instance.accessCache = Object.create(null)// 2. 创建渲染上下文代理, proxy 对象其实是代理了 instance.ctx 对象instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers);// 3. 执行 setup 函数const { setup } = Componentif (setup) {// 如果 setup 函数带参数,则创建一个 setupContextconst setupContext = (instance.setupContext =setup.length > 1 ? createSetupContext(instance) : null)// 执行 setup 函数,获取结果const setupResult = callWithErrorHandling(setup, instance, 0, [instance.props, setupContext])// 处理 setup 执行结果handleSetupResult(instance, setupResult)} else {// 4. 完成组件实例设置finishComponentSetup(instance, isSSR)}
}
计算属性
基于响应式依赖进行缓存,并仅在依赖项变化时重新计算。
基本用法
import {reactive,computed} form "vue";
const state = reactive({count:1,
});
const plusOne = computed(()=>state.count+1);
console.log(plusOne.value) //2
state.count++;
console.log(plusOne.value) //3
ComputedReflmpl类
export class ComputedRefImpl<T> {//用于存储与此计算属性相关的依赖(副作用函数)。public dep?: Dep = undefined//用于存储计算属性的当前值private _value!: T//一个 ReactiveEffect 实例,用于封装计算属性的 getter 函数。//这个副作用函数会在依赖的响应式数据变化时重新执行,以更新计算属性的值public readonly effect: ReactiveEffect<T>//内部标志,用于标记这个对象是一个 Ref 类型,并且指示其只读状态。public readonly __v_isRef = truepublic readonly [ReactiveFlags.IS_READONLY]: boolean = falsepublic _cacheable: boolean/*** Dev only*/_warnRecursive?: boolean/*** 构造函数接收四个参数:* getter: 用户定义的计算属性的获取函数。* _setter: 用户定义的计算属性的设置函数,用于允许计算属性被赋新值。* isReadonly: 表明这个计算属性是否是只读的。* isSSR: 标记是否在服务器端渲染环境中使用,影响是否缓存计算结果。*/constructor(private getter: ComputedGetter<T>,private readonly _setter: ComputedSetter<T>,isReadonly: boolean,isSSR: boolean,) {//ReactiveEffect 被用于封装 getter 函数,确保每当依赖的数据变化时,都能够自动重新计算值,并缓存结果以提高性能。this.effect = new ReactiveEffect(() => getter(this._value),() =>triggerRefValue(this,this.effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect? DirtyLevels.MaybeDirty_ComputedSideEffect: DirtyLevels.MaybeDirty,),)this.effect.computed = thisthis.effect.active = this._cacheable = !isSSRthis[ReactiveFlags.IS_READONLY] = isReadonly}/*** 当访问计算属性的 value 时,会执行这个 getter 函数。* 这个函数首先检查是否需要重新计算计算属性的值(基于缓存逻辑和依赖数据的变化)。* 如果需要,它会运行封装的 getter 函数来更新 _value。* 然后,它会注册当前活动的副作用函数为这个计算属性的依赖,以便将来数据变化时能触发更新*/get value() {// the computed ref may get wrapped by other proxies e.g. readonly() #3376//“获取当前计算属性实例(this)背后的原始对象,并将其赋值给 self 变量”const self = toRaw(this)if ((!self._cacheable || self.effect.dirty) &&hasChanged(self._value, (self._value = self.effect.run()!))) {triggerRefValue(self, DirtyLevels.Dirty)}trackRefValue(self)if (self.effect._dirtyLevel >= DirtyLevels.MaybeDirty_ComputedSideEffect) {if (__DEV__ && (__TEST__ || this._warnRecursive)) {warn(COMPUTED_SIDE_EFFECT_WARN, `\n\ngetter: `, this.getter)}triggerRefValue(self, DirtyLevels.MaybeDirty_ComputedSideEffect)}return self._value}set value(newValue: T) {this._setter(newValue)}// #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.xget _dirty() {return this.effect.dirty}set _dirty(v) {this.effect.dirty = v}// #endregion
}
这个类通过 ReactiveEffect 封装 getter 函数,使计算属性能够响应依赖数据的变化。同时,通过缓存机制保证了性能的优化。
计算属性的创建
/*** 接受一个 getter 函数作为参数。这个 getter 函数定义了计算属性的计算逻辑,* 当依赖的响应式数据变化时,这个函数会被重新执行来更新计算属性的值。* 在这种情况下,计算属性是只读的,尝试写入会导致警告(在开发模式下)。*/
export function computed<T>(getter: ComputedGetter<T>,debugOptions?: DebuggerOptions,
): ComputedRef<T>/*** 接受一个包含 get 和 set 方法的对象 options 作为参数* 这允许你创建一个可写的计算属性。get 方法定义了计算逻辑,和只读计算属性一样。* set 方法允许你自定义当尝试修改计算属性的值时的行为,这在需要基于计算属性的值反向更新其依赖的响应式数据时非常有用。*/
export function computed<T>(options: WritableComputedOptions<T>,debugOptions?: DebuggerOptions,
): WritableComputedRef<T>export function computed<T>(getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,debugOptions?: DebuggerOptions,isSSR = false,
) {let getter: ComputedGetter<T>let setter: ComputedSetter<T>const onlyGetter = isFunction(getterOrOptions)if (onlyGetter) {getter = getterOrOptionssetter = __DEV__? () => {warn('Write operation failed: computed value is readonly')}: NOOP} else {getter = getterOrOptions.getsetter = getterOrOptions.set}//使用 ComputedRefImpl 类来实际创建计算属性const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)if (__DEV__ && debugOptions && !isSSR) {cRef.effect.onTrack = debugOptions.onTrackcRef.effect.onTrigger = debugOptions.onTrigger}return cRef as any
}
Vue3的特点及优势
声明式框架
采用虚拟DOM
传统更新页面,拼接一个完整的字符串innerHTML 全量重新渲染,添加虚拟DOM后,可以比较新旧虚拟节点,找到变化在进行更新。虚拟DOM就是一个对象,用来描述真实DOM。
区分编译时和进行时
- 我们需要有一个虚拟DOM,调用渲染方法将虚拟DOM渲染成真实DOM(缺点就是虚拟DOM编写麻烦)。
- 专门写个编译时可以将模板编译成虚拟DOM(在构建的时候进行编译性能更高,不需要再运行的时候进行编译,而且vue3在编译中做了很多优化)
Vue3设计思想
- Vue3.0注重模块上的拆分,Vue3中的模块之间耦合度低,模块可以独立使用。
- 通过构建工具Tree - shaking机制实现按需引入,减少用户打包后体积。组合式API。
- Vue3允许自定义渲染器,扩展能力强,扩展更方便。
- 使用RFC来确保改动和设计都是经过Vuejs核心团队探讨并得到确认的。也让用户可以了解每一个功能采用或废弃的前因后果。采用RFC。
相关文章:

vue源码(二)
文章目录 数据代理示例 初始化组件实例计算属性基本用法ComputedReflmpl类计算属性的创建 Vue3的特点及优势声明式框架采用虚拟DOM区分编译时和进行时 Vue3设计思想 数据代理 示例 以下代码主要是有一个msg的响应式数据,点击按钮后修改msg的内容。根据代码可知有两…...

Ubuntu切换lowlatency内核
文章目录 一. 前言二. 开发环境三. 具体操作 一. 前言 低延迟内核(Lowlatency Kernel) 旨在为需要低延迟响应的应用程序设计的内核版本。Linux-lowlatency特别适合音频处理、实时计算、游戏和其他需要及时响应的实时任务。其主要特点是优化了中断处理、调…...

C++算法——差分
1.差分 差分与前缀和的核心思想相同,是预处理,可以在暴力枚举的过程中,快速给出查询的结果,从而优化时间复杂度。 是经典的用空间替换时间的做法。 2.一维差分数组 前缀和与差分是⼀对互逆的运算,对差分数组做前缀…...

猫耳大型活动提效——组件低代码化
1. 引言 猫耳前端在开发活动的过程中,经历过传统的 pro code 阶段,即活动页面完全由前端开发编码实现,直到 2020 年接入公司内部的低代码活动平台,满足了大部分日常活动的需求,运营可自主配置活动并上线,释…...

亿级分布式系统架构演进实战(二)- 横向扩展(服务无状态化)
亿级分布式系统架构演进实战(一)- 总体概要 服务无状态化详细设计 目标:确保服务实例完全无状态,可任意扩缩容 1. 会话存储改造(Session Management) 核心问题:传统单体应用中,用…...

零成本短视频爆款制造手册
——Q版+情感+互动的流量密码拆解 适用平台:抖音/快手/视频号 核心指标:点赞率>10% | 完播率>40% | 涨粉成本<0.3元 一、底层逻辑框架 1. 爆款元素融合公式 [ 3秒钩子 ] + [ 7秒沉浸 ] + [ 5秒引爆 ] = 15秒黄金结构 │ │ └─▶ 互动指令+情感…...

红队思想:Live off the Land - 靠山吃山,靠水吃水
在网络安全领域,尤其是红队(Red Team)渗透测试中,“Live off the Land”(简称 LotL,中文可译为“靠山吃山,靠水吃水”)是一种极具隐秘性和实用性的攻击策略。这一理念源于现实生活中…...

C语言八股---预处理,编译,汇编与链接篇
前言 从多个.c文件到达一个可执行文件的四步: 预处理–>编译–>汇编–>链接 预处理 预处理过程就是预处理器处理这些预处理指令(要不然编译器完全不认识),最终会生成 main.i的文件 主要做的事情有如下几点: 展开头文件展开宏条件编译删除注释添加行号等信息保留…...

平衡二叉树(AVL树)
平衡二叉树是啥我就不多说了,本篇博客只讲原理与方法。 首先引入平衡因子的概念。平衡因子(Balance Factor),以下简称bf。 bf 右子树深度 - 左子树深度。平衡结点的平衡因子可为:-1,0,1。除此…...

SpringBoot(一)--搭建架构5种方法
目录 一、⭐Idea从spring官网下载打开 2021版本idea 1.打开创建项目 2.修改pom.xml文件里的版本号 2017版本idea 二、从spring官网下载再用idea打开 三、Idea从阿里云的官网下载打开 编辑 四、Maven项目改造成springboot项目 五、从阿里云官网下载再用idea打开 Spri…...

RabbitMQ使用延迟消息
RabbitMQ使用延迟消息 1.什么情况下使用延迟消息 延迟消息适用于需要在一段时间后执行某些操作的场景,常见的有以下几类: 1.1. 订单超时取消(未支付自动取消) 场景: 用户下单后,如果 30 分钟内未付款&a…...

MyBatis-Plus 分页查询接口返回值问题剖析
在使用 MyBatis-Plus 进行分页查询时,很多开发者会遇到一个常见的问题:当分页查询接口返回值定义为 Page<T> 时,执行查询会抛出异常;而将返回值修改为 IPage<T> 时,分页查询却能正常工作。本文将从 MyBatis-Plus 的分页机制入手,详细分析这一问题的根源,并提…...

DeepLabv3+改进7:在主干网络中添加SegNext_Attention|助力涨点
🔥【DeepLabv3+改进专栏!探索语义分割新高度】 🌟 你是否在为图像分割的精度与效率发愁? 📢 本专栏重磅推出: ✅ 独家改进策略:融合注意力机制、轻量化设计与多尺度优化 ✅ 即插即用模块:ASPP+升级、解码器 PS:订阅专栏提供完整代码 论文简介 近期有关移动网络设计…...

c语言笔记 内存管理之栈内存
物理内存和虚拟内存 在c语言的程序需要内存资源,用来存放变量,常量,函数代码等,不同的内容存放在不同的内存区域,不同的内存区域有着不同的特征。 c语言的每一个进程都有着一片结构相同的 虚拟内存,虚拟内…...

分布式事务的原理
文章目录 基于 XA 协议的两阶段提交(2PC)三阶段提交(3PC)TCC(Try-Confirm-Cancel)Saga 模式消息队列(可靠消息最终一致性) 分布式事务是指在分布式系统中,涉及多个节点或…...

鸿基智启:东土科技为具身智能时代构建确定性底座
人类文明的每一次跨越都伴随着工具的革新。从蒸汽机的齿轮到计算机的代码,生产力的进化始终与技术的“具身化”紧密相连。当大语言模型掀起认知革命,具身智能正以“物理实体自主决策”的双重属性重新定义工业、医疗、服务等领域的运行逻辑。在这场革命中…...

SQL29 计算用户的平均次日留存率
SQL29 计算用户的平均次日留存率 计算用户的平均次日留存率_牛客题霸_牛客网 题目:现在运营想要查看用户在某天刷题后第二天还会再来刷题的留存率。 示例:question_practice_detail -- 输入: DROP TABLE IF EXISTS question_practice_detai…...

MWC 2025 | 移远通信推出AI智能无人零售解决方案,以“动态视觉+边缘计算”引领智能零售新潮流
在无人零售市场蓬勃发展的浪潮中,自动售货机正经历着从传统机械式操作向AI视觉技术的重大跨越。 移远通信作为全球领先的物联网整体解决方案供应商,精准把握行业趋势,在2025世界移动通信大会(MWC)上宣布推出全新AI智能…...

sparkTTS window 安装
下载 Spark-TTS Go to Spark-TTS GitHubClick "Code" > "Download ZIP", then extract it. 2. 建立 Conda 环境 conda create -n sparktts python3.12 -y conda activate sparktts 3. Install Dependencies pip install -r requirements.txt In…...

数据库原理6
1.数据是信息的载体 2.数据库应用程序人员的主要职责:编写应用系统的程序模块 3.关系规范化理论主要属于数据库理论的研究范畴 4.数据库主要有检索和修改(包括插入,删除,更新)两大操作 5.概念模型又称为语义模型。…...

接口自动化入门 —— Http的请求头,请求体,响应码解析!
在接口自动化测试中,HTTP请求头、请求体和响应码是核心组成部分。理解它们的作用、格式和解析方法对于进行有效的接口测试至关重要。以下是详细解析: 1. HTTP 请求头(Request Header) 1.1 作用 请求头是客户端向服务器发送的附加…...

tcc编译器教程6 进一步学习编译gmake源代码
本文以编译gmake为例讲解如何使用tcc进行复杂一点的c代码的编译 1 简介 前面主要讲解了如何编译lua解释器,lua解释器的编译很简单也很容易理解.当然大部分c语言程序编译没那么简单,下面对前面的gmake程序进行编译. 2 gmake源码结构 首先打开之前tcc-busybox-for-win32\gmak…...

公司共享网盘怎么建立
公司共享网盘的建立,关键在于明确使用需求、选择合适的网盘服务、搭建统一的文件管理规范、做好权限分级与安全防护。尤其要强调选择合适的网盘服务这一点,如果企业规模较大,且对协同办公的需求强烈,就需要考虑支持多人实时协作、…...

【高分论文密码】AI大模型和R语言的全类型科研图形绘制,从画图、标注、改图、美化、组合、排序分解科研绘图每个步骤
在科研成果竞争日益激烈的当下,「一图胜千言」已成为高水平SCI期刊的硬性门槛——数据显示很多情况的拒稿与图表质量直接相关。科研人员普遍面临的工具效率低、设计规范缺失、多维数据呈现难等痛点,因此科研绘图已成为成果撰写中的至关重要的一个环节&am…...

深入理解Java中的static关键字及其内存原理
static是Java中实现类级共享资源的核心修饰符,它突破了对象实例化的限制,使得变量和方法能够直接与类本身绑定。这种特性让static成为构建工具类、全局配置等场景的利器,但同时也带来独特的内存管理机制需要开发者关注。 static修饰成员变量…...

linux 系统 之centos安装 docker
对于 CentOS 安装 Docker 的前置条件 首先,需要安装一些必要的软件包, 对于 CentOS 7,可以使用以下命令: sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加 Docker 仓库 设置 Docker 的官方仓库。对于 …...

Python语法核心架构与核心知识点:从理论到实践
一、Python的核心设计哲学 Python以“简洁优雅”为核心理念,遵循以下原则: # Zen of Python(输入 import this 可查看) >>> import this The Zen of Python, by Tim Peters ... Simple is better than complex. Readab…...

FreeRTOS(5)内核控制函数及其他函数
FreeRTOS 提供了一些用于控制内核的 API 函数,这些 API 函数主要包含了进出临界区、开关中断、启停任务调度器等一系列用于控制内核的 API 函数。本章就来学习 FreeRTOS 的内 核控制函数。 内核控制函数 1. 函数 taskYIELD() 此函数用于请求切换任务, …...

网络DNS怎么更改?
访问速度慢或某些网站无法打开?改变网络DNS设置可能会帮助解决这些问题。本文将详细介绍如何更改网络DNS,包括更改的原因、具体步骤。 一、为什么要更改DNS? 更改DNS的原因有很多,以下是一些主要的考虑因素:某些公共DNS服务器的响应速度比…...

VIC模型有哪些优势?适用哪些范围?基于QGIS的VIC模型建模;未来气候变化模型预测;基于R语言VIC参数率定和优化
VIC模型是一个大尺度的半分布式水文模型,其设计之初就是为了模拟大流域的水文过程;它能够计算陆地-大气的能量通量,考虑土壤性质和土地利用的影响,自带有简化的湖泊/湿地模块,也能够将植被状况,…...