前言
vue3的响应式API大家应该都特别熟悉,比如
ref
、
watch
、
watchEffect
等。平时大家都是在
vue-cli
或者
vite
创建的vue项目里面使用的这些响应式API,今天欧阳给大家带来一些不一样的。
脱离vue项目,在
node.js
项目中使用vue的响应式API
。
直接上代码
话不多说,直接上代码。这个是我在本地新建的一个最简单的
node.js
项目,如下图:
从上图可以看到我们的
node.js
项目依赖只有一个:
vue
。并且提供了一个名为dev的脚本命令,这个脚本命令实际是在node环境内执行
index.js
文件。
我们来看
index.js
文件,代码如下:
const { ref, watch, watchEffect } = require("vue");
const count = ref(0);
// 模拟count变量的值修改
setInterval(() => {
count.value++;
}, 1000);
watch(count, (newVal) => {
console.log("触发watch", newVal);
});
watchEffect(
() => {
console.log("触发watchEffect", count.value);
},
{
flush: "sync",
}
);
为了标明
index.js
文件是在
node.js
环境中运行的,所以这里我特地使用
require
去导入vue导出的
ref
、
watch
、
watchEffect
这三个响应式API。
并且我们还模拟了修改
count
响应式变量值的操作,使用
setInterval
每隔一秒让
count
的值
+1
。
在vue项目中一样使用
watch
和
watchEffect
去监听
count
变量的值。
在终端执行
yarn dev
,也就是执行
node index.js
,如下图:
从上图中可以看到在
node.js
中的执行结果和预期是一模一样的。
为什么可以这样写呢?
前面的那个例子是一个
node.js
项目,项目中我们并没有像vue项目那样去创建一个vue组件,然后在组件里面去使用响应式API。而是直接在一个普通的
node.js
文件中使用vue暴露出来的响应式API,并且
watch
和
watchEffect
在监听的值改变后同样触发了对应的watch回调,那么这个又是怎么做到的呢?
这得益于vue3优秀的模块化设计,他将核心功能拆分为多个独立的模块,如下图:
比如
reactivity
模块中就是响应式的核心代码、
compiler-core
模块就是编译相关的核心代码。
并且这些模块还被单独当作npm包进行发布,命名规则是
@vue+模块名
。比如
reactivity
模块对应的npm包就是
@vue/reactivity
。如下图:
得益于模块化的设计,响应式相关的API和vue组件并没有强关联的关系,所以我们可以在
node.js
应用中去直接使用响应式API。
这里使用到了三个响应式API,分别是:
ref
、
watch
和
watchEffect
。在vue组件中的响应式的实现原理大家多多少少都有所听闻,其实在
node.js
项目中实现原理也是一样的,接下来我们讲讲是如何实现响应式的。
在我们这个demo中
count
是一个ref的响应式变量,当我们对
count
变量进行读操作时会触发
get
拦截。当我们对
count
变量进行写操作时会触发
set
拦截。
在我们这里使用
watch
和
watchEffect
的代码是下面这样的:
watch(count, (newVal) => {
console.log("触发watch", newVal);
});
watchEffect(
() => {
console.log("触发watchEffect", count.value);
},
{
flush: "sync",
}
);
当代码首次执行到
watch
和
watchEffect
时都会对
count
变量进行读操作,并且
watch
和
watchEffect
都传入了一个回调函数。
由于对
count
变量进行读操作了,所以就会触发
get
拦截。在
get
拦截中会将当前
watch的回调函数
作为依赖收集到
count
变量中。收集的方式也很简单,因为
count
变量是一个对象,所以使用对象的
dep
属性进行依赖收集。因为
dep
属性是一个集合,所以可以收集多个依赖。
在我们这里
watch
和
watchEffect
都触发了
count
变量的get拦截,所以
watch
和
watchEffect
的回调函数都被
count
变量进行了依赖收集。
当修改
count
变量的值时会触发
set
拦截,在
set
拦截中做的事情也很简单。将
count
变量收集到的依赖全部取出来,然后执行一遍。这里收集的依赖是
watch
和
watchEffect
的回调函数,所以当
count
变量的值改变时会导致
watch
和
watchEffect
的回调函数重新执行。