type
status
date
slug
summary
tags
category
icon
password
Vue 的响应式系统
Vue 的响应式系统是其核心功能之一,它使得数据的变化能够自动同步到 DOM 中,从而实现双向数据绑定。Vue 3 使用了 Proxy 对象来实现数据的响应式,而 Vue 2 使用的是 Object.defineProperty 来实现。
让我们从 Vue 3 的实现开始
1. Proxy 对象
Vue 3 使用
Proxy 对象来实现数据的响应式。Proxy 对象可以在数据访问和修改的时候监听进行拦截操作。具体来说,Vue 3 在创建一个 Vue 实例时,会使用 Proxy 来包裹所有实例数据。2. 依赖收集
当数据发生变化时,Vue 会收集依赖,并且在数据变动时通知所有依赖它的变量去更新。
依赖收集过程
- 读取数据时收集依赖:当模板中使用了双花括号表达式(即
v-model="message"或{{ message }})时,Vue 会在get方法中收集这些依赖。
- 数据变更时通知依赖:当数据被修改时(通过
set方法),所有依赖这个数据的变量都会在下次渲染时被通知,从而重新计算和渲染。
3. 发布-订阅模式
Vue 使用发布-订阅模式来管理依赖关系。它在
get 和 set 方法中传递依赖信息,当数据变更时,通过发布通知所有依赖的视图进行更新。示例代码
下面是一个使用 Vue 3 的响应式示例:
Vue 2 的实现
在 Vue 2 中,响应式系统是通过
Object.defineProperty 实现的。Vue 2 在数据对象上覆盖了属性的 get 和 set 方法:依赖收集举例
总结
Vue 的响应式系统的核心是通过
Proxy 或 Object.defineProperty 来拦截数据的读取和修改操作,并在数据变化时通知所有依赖它的视图进行更新。依赖收集和发布机制确保了数据变化时视图的自动更新。生命周期钩子的基本概念
以下是一些常见的生命周期钩子及其执行顺序:
beforeCreate:实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created:实例创建完成后被调用,这时的实例已经完成了数据观测 (data observer) 和 event/watcher 事件配置。
beforeMount:在挂载开始之前被调用,并且在虚拟 DOM 树生成之后,DOM 树生成之前。
mounted:在挂载完成后被调用,DOM 已经渲染完成了。
beforeUpdate:组件更新时,数据变动之前调用。
updated:在渲染完成后调用 (三个钩子:beforeUpdate、updated仅在keep-alive组件中首次激活和重新激活时调用)。
beforeDestroy:实例销毁之前调用。
destroyed:实例销毁后调用。
activated:当keep-alive中的组件激活时调用。
deactivated:当keep-alive中的组件停用时调用。
示例场景
假设你正在开发一个简单的计数器应用,用户可以点击按钮增加计数,并且想要记录每次计数的变化情况。你可以使用
beforeUpdate 和 updated 生命周期钩子来记录这些信息。解释
- beforeUpdate
- 在
beforeUpdate钩子中,组件即将进行更新,但是更新之前的 DOM 还没变化。这里可以记录更新前的count值。 - 上述代码中的
beforeUpdate钩子会在每次数据变化并更新 DOM 前打印即将更新的count值。
- updated
updated钩子在组件更新并完成之后执行。这里可以记录更新后的count值。- 代码中的
updated钩子会在每次数据变化并更新 DOM 后打印更新后的count值。
更复杂的场景
假设你需要在组件激活和停用时记录某些状态,可以使用
activated 和 deactivated 钩子。解释
- activated
activated钩子在组件被激活(从挂载到视图中的keep-alive组件重新显示)时调用。你可以在这个钩子中初始化一些状态或进行必要的操作。- 代码中的
activated钩子会在组件重新激活时打印当前的count值。
- deactivated
deactivated钩子在组件被停用(从挂载到视图中的keep-alive组件移除)时调用。你可以在这个钩子中清理一些状态或资源。- 代码中的
deactivated钩子会在组件停用时打印当前的count值。
总结
通过使用这些生命周期钩子,你可以在组件的不同阶段执行自定义逻辑,帮助你更好地控制组件的行为和状态。
Vue 基本工作原理
Vue 是一个渐进式框架,它的核心是高效的双向数据绑定。Vue 的关键组件包括:
- 虚拟 DOM:Vue 使用虚拟 DOM 来提高渲染性能。
- 数据绑定:Vue 实现了双向数据绑定,当数据发生变化时,UI 会自动更新;反之亦然。
- 生命周期钩子:Vue 组件在不同阶段会触发特定的生命周期钩子,开发者可以在这个阶段插入自定义的逻辑。
虚拟 DOM
- 创建虚拟 DOM:Vue 将真实的 DOM 节点转换为虚拟节点(VNode),这样可以减少直接操作真实 DOM 节点的需求。
- 对比 VDOM 和 RDOM:Vue 每次渲染时都会对比当前的虚拟 DOM 和上一次的虚拟 DOM,计算最小的差异,然后通过最小差异来更新真实的 DOM。这样可以极大地减少对真实 DOM 的操作。
双向数据绑定
- 响应式系统:Vue 使用了依赖收集和发布模式来实现数据的实时更新。当数据发生变化时,所有依赖于该数据的视图都会自动更新。
- 计算属性和侦听器:开发者可以使用
computed和watch来实现复杂的响应式逻辑。
生命周期钩子
- 创建阶段:
beforeCreate、created、beforeMount、mounted
- 更新阶段:
beforeUpdate、updated
- 销毁阶段:
beforeDestroy、destroyed
渲染过程
- 预编译:把模板编译成一个
render函数。
- 静态编译:优化生成的
render函数,处理静态内容。
- 动态编译:保留动态内容,确保它们能够响应数据变化。
示例代码
你可以通过以下代码示例来了解 Vue 是如何创建
render 函数的:这段代码会生成一个
render 函数,其中包含对 message 数据的绑定以及按钮的事件处理。你能在 Vue 的文档中找到更多关于 render 函数的详细介绍。Vue 的编译过程
预编译
当你使用模板写法时,Vue 会使用一个专用的 compiler 生成一个
render 函数。这个 render 函数是一个 JavaScript 函数,它直接操作虚拟 DOM(VDOM)。模板会被编译成一个 render 函数,这个函数会被注入到 Vue 组件中,并在组件实例化后执行。静态编译
在
render 函数生成后,Vue 会对其进行优化,处理静态内容。静态内容通常不会随数据变化而变化,所以 Vue 会将这些静态节点转为最精简的 HTML。这样在渲染过程中可以大大减少 DOM 操作的次数,从而提高性能。动态编译
对于动态内容,比如根据数据变化的内容,Vue 会保留这部分节点,确保它们能够响应数据变化。这些动态节点在
render 函数中会用到实际的数据属性和方法。关于编译过程,重点在于 Vue 如何区分静态内容和动态内容,并如何生成对应的
render 函数。你能试着描述一下这些概念吗?或者你有什么疑问的地方我可以详细解释。- Author:Francis
- URL:https://deqiang.wang/article/frontend
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!