当前位置:首页 > 科技  > 软件

新知识Get,Vue3是如何实现在Style中使用响应式变量?

来源: 责编: 时间:2024-07-09 07:03:49 699观看
导读前言vue2的时候想必大家有遇到需要在style模块中访问script模块中的响应式变量,为此我们不得不使用css变量去实现。现在vue3已经内置了这个功能啦,可以在style中使用v-bind指令绑定script模块中的响应式变量,这篇文章我

前言

vue2的时候想必大家有遇到需要在style模块中访问script模块中的响应式变量,为此我们不得不使用css变量去实现。现在vue3已经内置了这个功能啦,可以在style中使用v-bind指令绑定script模块中的响应式变量,这篇文章我们来讲讲vue是如何实现在style中使用script模块中的响应式变量。注:本文中使用的vue版本为3.4.19。ZLm28资讯网——每日最新资讯28at.com

看个demo

我们来看个简单的demo,index.vue文件代码如下:ZLm28资讯网——每日最新资讯28at.com

<template>  <div>    <p>222</p>    <span class="block">hello world</span>  </div></template><script setup lang="ts">import { ref } from "vue";const primaryColor = ref("red");</script><style scoped>.block {  color: v-bind(primaryColor);}</style>

我们在script模块中定义了一个响应式变量primaryColor,并且在style中使用v-bind指令将primaryColor变量绑定到color样式上面。ZLm28资讯网——每日最新资讯28at.com

我们在浏览器的network面板中来看看编译后的js文件,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到在network面板中编译后的index.vue文件有两个,并且第二个里面有一些query参数,其中的type=style就表示当前文件的内容对应的是style模块。第一个index.vue对应的是template和script模块中的内容。ZLm28资讯网——每日最新资讯28at.com

我们来看看第一个index.vue,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到setup函数是script模块编译后的内容,在setup函数中多了一个_useCssVars函数,从名字你应该猜到了,这个函数的作用是和css变量有关系。别着急,我们接下来会详细去讲_useCssVars函数。ZLm28资讯网——每日最新资讯28at.com

我们再来看看第二个index.vue,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到这个index.vue确实对应的是style模块中的内容,并且原本的color: v-bind(primaryColor);已经变成了color: var(--c845efc6-primaryColor);。ZLm28资讯网——每日最新资讯28at.com

很明显浏览器是不认识v-bind(primaryColor);指令的,所以经过编译后就变成了浏览器认识的css变量var(--c845efc6-primaryColor);。ZLm28资讯网——每日最新资讯28at.com

我们接着在elements面板中来看看此时class值为block的span元素,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到color的值为css变量var(--c845efc6-primaryColor),这个我们前面讲过。不同的是这里从父级元素div中继承过来一个--c845efc6-primaryColor: red;。ZLm28资讯网——每日最新资讯28at.com

这个就是声明一个名为--c845efc6-primaryColor的css变量,变量的值为red。ZLm28资讯网——每日最新资讯28at.com

还记得我们在script模块中定义的响应式变量primaryColor吗?他的值就是red。ZLm28资讯网——每日最新资讯28at.com

所以这个span元素最终color渲染出来的值就是red。ZLm28资讯网——每日最新资讯28at.com

接下来我们将通过debug的方式带你搞清楚在style中是如何将指令v-bind(primaryColor)编译成css变量var(--c845efc6-primaryColor),以及_useCssVars函数是如何生成声明值为red的css变量--c845efc6-primaryColor。ZLm28资讯网——每日最新资讯28at.com

doCompileStyle函数

在前面的文章中我们讲过了style模块实际是由doCompileStyle函数函数处理的,具体如何调用到doCompileStyle函数可以查看我之前的文章: 掉了两根头发后,我悟了!vue3的scoped原来是这样避免样式污染。ZLm28资讯网——每日最新资讯28at.com

我们需要给doCompileStyle函数打个断点,doCompileStyle函数的代码位置在:node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js。ZLm28资讯网——每日最新资讯28at.com

还是一样的套路启动一个debug终端。这里以vscode举例,打开终端然后点击终端中的+号旁边的下拉箭头,在下拉中点击Javascript Debug Terminal就可以启动一个debug终端。ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

在debug终端执行yarn dev,在浏览器中打开对应的页面,比如:http://localhost:5173/ 。ZLm28资讯网——每日最新资讯28at.com

此时断点将停留在doCompileStyle函数中,在我们这个场景中doCompileStyle函数简化后的代码如下:ZLm28资讯网——每日最新资讯28at.com

import postcss from "postcss";function doCompileStyle(options) {  const {    filename,    id,    postcssOptions,    postcssPlugins,  } = options;  const source = options.source;  const shortId = id.replace(/^data-v-/, "");  const plugins = (postcssPlugins || []).slice();  plugins.unshift(cssVarsPlugin({ id: shortId, isProd }));  const postCSSOptions = {    ...postcssOptions,    to: filename,    from: filename,  };  let result;  try {    result = postcss(plugins).process(source, postCSSOptions);    return result.then((result) => ({      code: result.css || "",      // ...省略    }));  } catch (e: any) {    errors.push(e);  }}

在前面的文章掉了两根头发后,我悟了!vue3的scoped原来是这样避免样式污染中我们讲过了,这里id的值为使用了scoped后给html增加的自定义属性data-v-x,每个vue文件生成的x都是不一样的。在doCompileStyle函数中使用id.replace方法拿到x赋值给变量shortId。ZLm28资讯网——每日最新资讯28at.com

接着就是定义一个plugins插件数组,并且将cssVarsPlugin函数的返回结果push进去。ZLm28资讯网——每日最新资讯28at.com

这里cssVarsPlugin函数就是返回了一个自定义的postcss插件。ZLm28资讯网——每日最新资讯28at.com

最后就是执行result = postcss(plugins).process(source, postCSSOptions)拿到经过postcss转换编译器处理后的css。ZLm28资讯网——每日最新资讯28at.com

可能有的小伙伴对postcss不够熟悉,我们这里来简单介绍一下。ZLm28资讯网——每日最新资讯28at.com

postcss 是 css 的 transpiler(转换编译器,简称转译器),它对于 css 就像 babel 对于 js 一样,能够做 css 代码的分析和转换。同时,它也提供了插件机制来做自定义的转换。ZLm28资讯网——每日最新资讯28at.com

在我们这里主要就是用到了postcss提供的插件机制来完成css scoped的自定义转换,调用postcss的时候我们传入了source,他的值是style模块中的css代码。并且传入的plugins插件数组中有个cssVarsPlugin插件,这个自定义插件就是vue写的用于处理在css中使用v-bind指令。ZLm28资讯网——每日最新资讯28at.com

在执行postcss对css代码进行转换之前我们在debug终端来看看此时的css代码是什么样的,如下图:ZLm28资讯网——每日最新资讯28at.com

sourcesourceZLm28资讯网——每日最新资讯28at.com

从上图中可以看到此时的options.source中还是v-bind(primaryColor)指令。ZLm28资讯网——每日最新资讯28at.com

cssVarsPlugin插件

cssVarsPlugin插件在我们这个场景中简化后的代码如下:ZLm28资讯网——每日最新资讯28at.com

const vBindRE = /v-bind/s*/(/g;const cssVarsPlugin = (opts) => {  const { id, isProd } = opts;  return {    postcssPlugin: "vue-sfc-vars",    Declaration(decl) {      const value = decl.value;      if (vBindRE.test(value)) {        vBindRE.lastIndex = 0;        let transformed = "";        let lastIndex = 0;        let match;        while ((match = vBindRE.exec(value))) {          const start = match.index + match[0].length;          const end = lexBinding(value, start);          if (end !== null) {            const variable = normalizeExpression(value.slice(start, end));            transformed +=              value.slice(lastIndex, match.index) +              `var(--${genVarName(id, variable, isProd)})`;            lastIndex = end + 1;          }        }        decl.value = transformed + value.slice(lastIndex);      }    },  };};

这里的id就是我们在doCompileStyle函数中传过来的shortId,每个vue文件对应的shortId值都是不同的。ZLm28资讯网——每日最新资讯28at.com

这里使用到了Declaration钩子函数,css中每个具体的样式都会触发这个Declaration钩子函数。ZLm28资讯网——每日最新资讯28at.com

给Declaration钩子函数打个断点,当post-css处理到color: v-bind(primaryColor);时就会走到这个断点中。如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

将字符串v-bind(primaryColor)赋值给变量value,接着执行if (vBindRE.test(value))。vBindRE是一个正则表达式,这里的意思是当前css的值是使用了v-bind指令才走到if语句里面。ZLm28资讯网——每日最新资讯28at.com

接着就是执行while ((match = vBindRE.exec(value)))进行正则表达式匹配,如果value的值符合vBindRE正则表达式,也就是value的值是v-bind绑定的,那么就走到while循环里面去。ZLm28资讯网——每日最新资讯28at.com

看到这里有的小伙伴会问了,这里使用if就可以了,为什么还要使用while循环呢?ZLm28资讯网——每日最新资讯28at.com

答案是css的值可能是多个v-bind指令组成的,比如border: v-bind(borderWidth) solid v-bind(primaryColor);。这里的css值就由两个v-bind组成,分别是v-bind(borderWidth)和v-bind(primaryColor);。ZLm28资讯网——每日最新资讯28at.com

为了处理上面这种多个v-bind指令组成的css值,所以就需要使用while循环搭配exec方法。正则表达式使用了global标志位的时候,js的RegExp 对象是有状态的,它们会将上次成功匹配后的位置记录在 lastIndex 属性中。使用此特性,exec() 可用来对单个字符串中的多次匹配结果进行逐条的遍历。ZLm28资讯网——每日最新资讯28at.com

在debug终端来看看此时的match数组是什么样的,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到match[0]的值是正则表达式匹配的字符串,在我们这里匹配的字符串是v-bind(。match.index的值为匹配到的字符位于原始字符串的基于 0 的索引值。ZLm28资讯网——每日最新资讯28at.com

看到这里有的小伙伴可能对match.index的值有点不理解,我举个简单的例子你一下就明白了。ZLm28资讯网——每日最新资讯28at.com

还是以v-bind(borderWidth) solid v-bind(primaryColor)为例,这个字符串就是原始字符串,第一次在while循环中正则表达式匹配到第一个bind,此时的match.index的值为0,也就是第一个v在原始字符串的位置。第二次在while循环中会基于第一次的位置接着向后找,会匹配到第二个v-bind指令,此时的match.index的值同样也是基于原始字符串的位置,也就是第二个v-bind中的v的位置,值为26。ZLm28资讯网——每日最新资讯28at.com

在while循环中使用const start = match.index + match[0].length给start变量赋值,match.index的值是v-bind中的v的位置。match[0]是正则匹配到的字符串 v-bind(。所以这个start的位置就是v-bind(primaryColor)中primaryColor变量的开始位置,也就是p所在的位置。ZLm28资讯网——每日最新资讯28at.com

接着就是执行lexBinding函数拿到v-bind(primaryColor)中primaryColor变量的结束位置,赋值给变量end。在我们这个场景中简化后的lexBinding函数代码如下:ZLm28资讯网——每日最新资讯28at.com

function lexBinding(content: string, start: number) {  for (let i = start; i < content.length; i++) {    const char = content.charAt(i);    if (char === `)`) {      return i;    }  }  return null;}

简化后的lexBinding函数也很简单,使用for循环遍历v-bind(primaryColor)字符串,如果发现字符串)就说明找到了primaryColor变量的结束位置。ZLm28资讯网——每日最新资讯28at.com

接着来看拿到end变量后的代码,会执行const variable = normalizeExpression(value.slice(start, end))。这里先执行了value.slice(start, end)根据start开始位置和end结束位置提取出v-bind指令绑定的变量,接着normalizeExpression函数对其进行trim去除空格。ZLm28资讯网——每日最新资讯28at.com

在我们这个场景中简化后的normalizeExpression函数代码如下:ZLm28资讯网——每日最新资讯28at.com

function normalizeExpression(exp) {  exp = exp.trim();  return exp;}

将从v-bind指令中提取出来的变量赋值给variable变量,接着执行字符串拼接拿到由v-bind指令转换成的css变量,代码如下:ZLm28资讯网——每日最新资讯28at.com

transformed +=  value.slice(lastIndex, match.index) +  `var(--${genVarName(id, variable, isProd)})`;

这里的value是css变量值v-bind(primaryColor),在我们这里lastIndex的值为0,match.index的值也是0,所以value.slice(lastIndex, match.index)拿到的值也是空字符串。ZLm28资讯网——每日最新资讯28at.com

接着来看后面这部分,使用字符串拼接得到:var(--变量)。这个看着就很熟悉了,他就是一个css变量。变量名是调用genVarName函数生成的,genVarName函数代码如下:ZLm28资讯网——每日最新资讯28at.com

import hash from "hash-sum";function genVarName(id, raw, isProd) {  if (isProd) {    return hash(id + raw);  } else {    return `${id}-${getEscapedCssVarName(raw)}`;  }}

这个id是根据当前vue组件路径生成的,每个vue组件生成的id都不同。这个raw也就是绑定的响应式变量,在这里是primaryColor。isProd表示当前是不是生产环境。ZLm28资讯网——每日最新资讯28at.com

如果是生产环境就根据id和变量名使用哈希算法生成一个加密的字符串。ZLm28资讯网——每日最新资讯28at.com

如果是开发环境就使用字符串拼接将id和变量名primaryColor拼接起来得到一个css变量。getEscapedCssVarName函数的代码也很简单,是对变量中的特殊字符进行转义,以便在 CSS 变量名中使用。代码如下:ZLm28资讯网——每日最新资讯28at.com

const cssVarNameEscapeSymbolsRE = /[ !"#$%&'()*+,./:;<=>?@[///]^`{|}~]/g;function getEscapedCssVarName(key: string) {  return key.replace(cssVarNameEscapeSymbolsRE, (s) => `//${s}`);}

这也就是为什么不同组件的primaryColor生成的css变量名称不会冲突的原因了,因为在生成的css变量前面拼接了一个id,每个vue组件生成的id值都不同。ZLm28资讯网——每日最新资讯28at.com

拿到转换成css变量的css值后,并且将其赋值给变量transformed。接着就是执行lastIndex = end + 1,在我们这里lastIndex就指向了字符串的末尾。ZLm28资讯网——每日最新资讯28at.com

最后就是执行decl.value = transformed + value.slice(lastIndex);将v-bind指令替换成css变量,由于lastIndex是指向了字符串的末尾,所以value.slice(lastIndex)的值也是一个空字符串。ZLm28资讯网——每日最新资讯28at.com

所以在我们这里实际是执行了decl.value = transformed,执行完这句话后color的值就由v-bind(primaryColor)转换成了var(--c845efc6-primaryColor)。ZLm28资讯网——每日最新资讯28at.com

生成useCssVars函数

前面我们讲过了编译后的setup函数中多了一个useCssVars函数,实际在我们的源代码中是没有这个useCssVars函数的。接下来我们来看看编译时处理script模块时是如何生成useCssVars函数的。ZLm28资讯网——每日最新资讯28at.com

在之前的 为什么defineProps宏函数不需要从vue中import导入?文章中我们讲过了vue的script模块中的代码是由compileScript函数处理的,当然你没看过那篇文章也不影响这篇文章的阅读。ZLm28资讯网——每日最新资讯28at.com

给compileScript函数打个断点,在我们这个场景中简化后的compileScript函数代码如下:ZLm28资讯网——每日最新资讯28at.com

function compileScript(sfc, options) {  const ctx = new ScriptCompileContext(sfc, options);  const startOffset = ctx.startOffset;  ctx.s.prependLeft(    startOffset,    `${genCssVarsCode(sfc.cssVars, ctx.bindingMetadata, scopeId, !!options.isProd)}`  );}

首先调用ScriptCompileContext类new了一个ctx上下文对象,我们这里来介绍一下需要使用到的ctx上下文对象中的两个方法:ctx.s.toString、ctx.s.prependLeft。ZLm28资讯网——每日最新资讯28at.com

  • ctx.s.toString:返回此时由script模块编译成的js代码。
  • ctx.s.prependLeft:给编译后的js代码在指定index的前面插入字符串。

给ctx.s.prependLeft方法打个断点,在debug终端使用ctx.s.toString方法来看看此时由script模块编译成的js代码是什么样的,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到此时生成的js代码code字符串只有一条import语句和定义primaryColor变量。ZLm28资讯网——每日最新资讯28at.com

由于篇幅有限我们就不深入到genCssVarsCode函数了,这个genCssVarsCode函数会生成useCssVars函数的调用。我们在debug终端来看看生成的code代码字符串是什么样的,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到genCssVarsCode函数生成了一个useCssVars函数。ZLm28资讯网——每日最新资讯28at.com

执行ctx.s.prependLeft函数后会将生成的useCssVars函数插入到生成的js code代码字符串的前面,我们在debug终端来看看,如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到此时的js code代码字符串中已经有了一个useCssVars函数了。ZLm28资讯网——每日最新资讯28at.com

执行useCssVars函数

前面我们讲过了编译时经过cssVarsPlugin这个post-css插件处理后,v-bind(primaryColor)指令就会编译成了css变量var(--c845efc6-primaryColor)。这里只是使用css变量值的地方,那么这个css变量的值又是在哪里定义的呢?答案是在useCssVars函数中。ZLm28资讯网——每日最新资讯28at.com

在开始我们讲过了编译后的setup函数中多了一个useCssVars函数,所以我们给useCssVars函数打个断点,刷新浏览器此时代码就会走到断点中了。如下图:ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

从上图中可以看到执行useCssVars函数时传入了一个回调函数作为参数,这个回调函数返回了一个对象。ZLm28资讯网——每日最新资讯28at.com

将断点走进useCssVars函数,在我们这个场景中简化后的useCssVars函数代码如下:ZLm28资讯网——每日最新资讯28at.com

function useCssVars(getter) {  const instance = getCurrentInstance();  const setVars = () => {    const vars = getter(instance.proxy);    setVarsOnVNode(instance.subTree, vars);  };  watchPostEffect(setVars);}

在useCssVars函数中先调用getCurrentInstance函数拿到当前的vue实例,然后将setVars函数作为参数传入去执行watchPostEffect函数。ZLm28资讯网——每日最新资讯28at.com

这个watchPostEffect函数大家应该知道,他是watchEffect() 使用 flush: 'post' 选项时的别名。ZLm28资讯网——每日最新资讯28at.com

为什么需要使用 flush: 'post'呢?ZLm28资讯网——每日最新资讯28at.com

答案是需要在setVars回调函数中需要去操作DOM,所以才需要使用 flush: 'post'让回调函数在组件渲染完成之后去执行。ZLm28资讯网——每日最新资讯28at.com

给setVars函数打个断点,组件渲染完成后断点将会走进setVars函数中。ZLm28资讯网——每日最新资讯28at.com

首先会执行getter函数,将返回值赋值给变量vars。前面我们讲过了这个getter函数是调用useCssVars函数时传入的回调函数,代码如下:ZLm28资讯网——每日最新资讯28at.com

_useCssVars((_ctx) => ({  "c845efc6-primaryColor": primaryColor.value}))

在这个回调函数中会返回一个对象,对象的key为c845efc6-primaryColor,这个key就是css变量var(--c845efc6-primaryColor)括号中的内容。ZLm28资讯网——每日最新资讯28at.com

对象的值是ref变量primaryColor的值,由于这个代码是在watchPostEffect的回调函数中执行的,所以这里的ref变量primaryColor也被作为依赖进行收集了。当primaryColor变量的值变化时,setVars函数也将再次执行。这也就是为什么在style中可以使用v-bind指令绑定一个响应式变量,并且当响应式变量的值变化时样式也会同步更新。ZLm28资讯网——每日最新资讯28at.com

接着就是执行setVarsOnVNode(instance.subTree, vars)函数,传入的第一个参数为instance.subTree。他的值是当前vue组件根元素的虚拟DOM,也就是根元素div的虚拟DOM。第二个参数为useCssVars传入的回调函数返回的对象,这是一个css变量组成的对象。ZLm28资讯网——每日最新资讯28at.com

接着将断点走进setVarsOnVNode函数,在我们这个场景中简化后的代码如下:ZLm28资讯网——每日最新资讯28at.com

function setVarsOnVNode(vnode: VNode, vars) {  setVarsOnNode(vnode.el, vars);}

在setVarsOnVNode函数中是调用了setVarsOnNode函数,不同的是传入的第一个参数不再是虚拟DOM。而是vnode.el虚拟DOM对应的真实DOM,也就是根节点div。ZLm28资讯网——每日最新资讯28at.com

将断点走进setVarsOnNode函数,在我们这个场景中简化后的setVarsOnNode函数代码如下:ZLm28资讯网——每日最新资讯28at.com

function setVarsOnNode(el: Node, vars) {  if (el.nodeType === 1) {    const style = el.style;    for (const key in vars) {      style.setProperty(`--${key}`, vars[key]);    }  }}

在setVarsOnNode函数中先使用if语句判断el.nodeType === 1,这个的意思是判断当前节点类型是不是一个元素节点,比如<p>和<div>。如果是就走进if语句里面,使用el.style拿到根节点的style样式。ZLm28资讯网——每日最新资讯28at.com

这里的vars是css变量组成的对象,遍历这个对象。对象的key为css变量名称,对象的value为css变量的值。ZLm28资讯网——每日最新资讯28at.com

接着就是遍历css变量组成的对象,使用style.setProperty方法给根节点div增加内联样式,也就是--c845efc6-primaryColor: red;。span元素由于是根节点div的子节点,所以他也继承了样式--c845efc6-primaryColor: red;。ZLm28资讯网——每日最新资讯28at.com

由于span元素的color经过编译后已经变成了css变量var(--c845efc6-primaryColor),并且从根节点继承过来css变量--c845efc6-primaryColor的值为red,所以最终span元素的color值为red。ZLm28资讯网——每日最新资讯28at.com

总结

下面这个是我总结的流程图,如下(搭配流程图后面的文字解释一起服用效果最佳):ZLm28资讯网——每日最新资讯28at.com

图片图片ZLm28资讯网——每日最新资讯28at.com

编译阶段script模块是由compileScript函数处理的,compileScript函数会去执行一个genCssVarsCode函数。这个函数会返回一个useCssVars函数的调用。然后在compileScript函数中会调用ctx.s.prependLeft方法将生成的useCssVars函数插入到编译后的setup函数中。ZLm28资讯网——每日最新资讯28at.com

编译阶段style模块是由doCompileStyle函数处理的,在doCompileStyle函数中会调用postcss对css样式进行处理。vue自定义了一个名为cssVarsPlugin的postcss插件,插件中有个Declaration钩子函数,css中每个具体的样式都会触发这个Declaration钩子函数。ZLm28资讯网——每日最新资讯28at.com

在Declaration钩子函数中使用正则表达式去匹配当前css值是不是v-bind绑定的,如果是就将匹配到的v-bind绑定的变量提取出来赋值给变量variable。还有一个id变量,他是根据当前vue组件的路径生成的加密字符串。使用字符串拼接就可以得到var(--${id}-${variable}),他就是由v-bind编译后生成的css变量。最终生成的css变量类似这样:var(--c845efc6-primaryColor)。ZLm28资讯网——每日最新资讯28at.com

运行时阶段初始化的时候会去执行setup函数,由于在编译阶段setup函数中插入了一个useCssVars函数。使用在运行时阶段初始化时useCssVars函数会被执行。ZLm28资讯网——每日最新资讯28at.com

在useCssVars函数中执行了watchPostEffect函数,他是watchEffect() 使用 flush: 'post' 选项时的别名。ZLm28资讯网——每日最新资讯28at.com

由于我们需要在回调中操作DOM,所以才需要使用flush: 'post',让回调函数在组件渲染之后去执行。由于在回调函数中会去读取v-bind绑定的响应式变量,所以每次绑定的响应式变量值变化后都会再次执行调用watchPostEffect传入的回调函数,以此让响应式变量绑定的样式保存更新。ZLm28资讯网——每日最新资讯28at.com

在watchPostEffect传入的回调函数中会通过当前vue组件实例拿到真实DOM的根节点,然后遍历css变量组成的对象,将这些css变量逐个在根节点上面定义,类似这样:--c845efc6-primaryColor: red;。由于css可以继承,所以子节点都继承了这个css定义。ZLm28资讯网——每日最新资讯28at.com

我们的<span>标签在编译阶段由color: v-bind(primaryColor);编译成了css变量color: var(--c845efc6-primaryColor)。并且在运行时由于useCssVars函数的作用在根节点生成了css变量的定义--c845efc6-primaryColor: red;。由于css继承,所以span标签也继承了这个css变量的定义,所以span标签渲染到页面上的color值最终为red。ZLm28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-99649-0.html新知识Get,Vue3是如何实现在Style中使用响应式变量?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 浅谈Node.js核心组件

下一篇: 应该立即学习的鲜为人知的 CSS 特性

标签:
  • 热门焦点
  • K60 Pro官方停产 第三方瞬间涨价

    K60 Pro官方停产 第三方瞬间涨价

    虽然没有官方宣布,但Redmi的一些高管也已经透露了,Redmi K60 Pro已经停产且不会补货,这一切都是为了即将到来的K60 Ultra铺路,属于厂家的正常操作。但有意思的是该机在停产之后
  • 天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    这几年除了手机作为智能生活终端最主要的核心之外,第二个可以成为中心点的产品是什么?——是智能音箱。 手机在执行命令的时候有两种操作方式,手和智能语音助手,而智能音箱只
  • K8S | Service服务发现

    K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 只需五步,使用start.spring.io快速入门Spring编程

    只需五步,使用start.spring.io快速入门Spring编程

    步骤1打开https://start.spring.io/,按照屏幕截图中的内容创建项目,添加 Spring Web 依赖项,并单击“生成”按钮下载 .zip 文件,为下一步做准备。请在进入步骤2之前进行解压。图
  • 2023年,我眼中的字节跳动

    2023年,我眼中的字节跳动

    此时此刻(2023年7月),字节跳动从未上市,也从未公布过任何官方的上市计划;但是这并不妨碍它成为中国最受关注的互联网公司之一。从2016-17年的抖音强势崛起,到2018年的&ldquo;头腾
  • 最“俊美”淘宝卖家,靠直播和短视频圈粉,上架秒光,年销3000万

    最“俊美”淘宝卖家,靠直播和短视频圈粉,上架秒光,年销3000万

    来源 | 电商在线文|易琬玉编辑|斯问受访店铺:Ringdoll戒之人形图源:微博@御座的黄山、&ldquo;Ringdoll戒之人形&rdquo;淘宝店铺有关外貌的评价,黄山已经听累了。生于1985年的他,哪
  • 自律,给不了Keep自由!

    自律,给不了Keep自由!

    来源 | 互联网品牌官作者 | 李大为编排 | 又耳 审核 | 谷晓辉自律能不能给用户自由暂时不好说,但大概率不能给Keep自由。近日,全球最大的在线健身平台Keep正式登陆港交所,努力
  • 携众多高端产品亮相ChinaJoy,小米带来一场科技与人文的视听盛宴

    携众多高端产品亮相ChinaJoy,小米带来一场科技与人文的视听盛宴

    7月28日,全球数字娱乐领域最具知名度与影响力的年度盛会中国国际数码互动娱乐展览会(简称ChinaJoy)在上海新国际博览中心盛大开幕。作为全球领先的科
  • SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘是西部数据发布的最新一代WD Blue系列的固态硬盘,不仅闪存技术更为精进,性能也得到了进一步的跃升。WD Blue SN570 NVMe SSD的包装外
Top