专栏名称: 前端从进阶到入院
我是 ssh,只想用最简单的方式把原理讲明白。wx:sshsunlight,分享前端的前沿趋势和一些有趣的事情。
目录
相关文章推荐
参考消息  ·  朔尔茨评价特朗普建议:“丑闻” ·  昨天  
参考消息  ·  福特CEO:这方面,中国领先美国10年 ·  2 天前  
GBA Community  ·  DeepSeek Confuses ... ·  2 天前  
GBA Community  ·  DeepSeek Confuses ... ·  2 天前  
中国日报网  ·  突发!塞尔维亚总统武契奇遇险 ·  2 天前  
参考消息  ·  韩国代总统指示:“动员所有力量” ·  2 天前  
51好读  ›  专栏  ›  前端从进阶到入院

涨见识了!脱离 Vue 项目竟然也可以使用响应式API

前端从进阶到入院  · 公众号  ·  · 2024-07-25 14:00

正文

前言

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 的回调函数重新执行。







请到「今天看啥」查看全文