日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

新知識Get,Vue3是如何實現在Style中使用響應式變量?

來源: 責編: 時間:2024-07-09 07:03:49 861觀看
導讀前言vue2的時候想必大家有遇到需要在style模塊中訪問script模塊中的響應式變量,為此我們不得不使用css變量去實現?,F在vue3已經內置了這個功能啦,可以在style中使用v-bind指令綁定script模塊中的響應式變量,這篇文章我

前言

vue2的時候想必大家有遇到需要在style模塊中訪問script模塊中的響應式變量,為此我們不得不使用css變量去實現。現在vue3已經內置了這個功能啦,可以在style中使用v-bind指令綁定script模塊中的響應式變量,這篇文章我們來講講vue是如何實現在style中使用script模塊中的響應式變量。注:本文中使用的vue版本為3.4.19。qeL28資訊網——每日最新資訊28at.com

看個demo

我們來看個簡單的demo,index.vue文件代碼如下:qeL28資訊網——每日最新資訊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樣式上面。qeL28資訊網——每日最新資訊28at.com

我們在瀏覽器的network面板中來看看編譯后的js文件,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到在network面板中編譯后的index.vue文件有兩個,并且第二個里面有一些query參數,其中的type=style就表示當前文件的內容對應的是style模塊。第一個index.vue對應的是template和script模塊中的內容。qeL28資訊網——每日最新資訊28at.com

我們來看看第一個index.vue,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到setup函數是script模塊編譯后的內容,在setup函數中多了一個_useCssVars函數,從名字你應該猜到了,這個函數的作用是和css變量有關系。別著急,我們接下來會詳細去講_useCssVars函數。qeL28資訊網——每日最新資訊28at.com

我們再來看看第二個index.vue,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到這個index.vue確實對應的是style模塊中的內容,并且原本的color: v-bind(primaryColor);已經變成了color: var(--c845efc6-primaryColor);。qeL28資訊網——每日最新資訊28at.com

很明顯瀏覽器是不認識v-bind(primaryColor);指令的,所以經過編譯后就變成了瀏覽器認識的css變量var(--c845efc6-primaryColor);。qeL28資訊網——每日最新資訊28at.com

我們接著在elements面板中來看看此時class值為block的span元素,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到color的值為css變量var(--c845efc6-primaryColor),這個我們前面講過。不同的是這里從父級元素div中繼承過來一個--c845efc6-primaryColor: red;。qeL28資訊網——每日最新資訊28at.com

這個就是聲明一個名為--c845efc6-primaryColor的css變量,變量的值為red。qeL28資訊網——每日最新資訊28at.com

還記得我們在script模塊中定義的響應式變量primaryColor嗎?他的值就是red。qeL28資訊網——每日最新資訊28at.com

所以這個span元素最終color渲染出來的值就是red。qeL28資訊網——每日最新資訊28at.com

接下來我們將通過debug的方式帶你搞清楚在style中是如何將指令v-bind(primaryColor)編譯成css變量var(--c845efc6-primaryColor),以及_useCssVars函數是如何生成聲明值為red的css變量--c845efc6-primaryColor。qeL28資訊網——每日最新資訊28at.com

doCompileStyle函數

在前面的文章中我們講過了style模塊實際是由doCompileStyle函數函數處理的,具體如何調用到doCompileStyle函數可以查看我之前的文章: 掉了兩根頭發后,我悟了!vue3的scoped原來是這樣避免樣式污染。qeL28資訊網——每日最新資訊28at.com

我們需要給doCompileStyle函數打個斷點,doCompileStyle函數的代碼位置在:node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js。qeL28資訊網——每日最新資訊28at.com

還是一樣的套路啟動一個debug終端。這里以vscode舉例,打開終端然后點擊終端中的+號旁邊的下拉箭頭,在下拉中點擊Javascript Debug Terminal就可以啟動一個debug終端。qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

在debug終端執行yarn dev,在瀏覽器中打開對應的頁面,比如:http://localhost:5173/ 。qeL28資訊網——每日最新資訊28at.com

此時斷點將停留在doCompileStyle函數中,在我們這個場景中doCompileStyle函數簡化后的代碼如下:qeL28資訊網——每日最新資訊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。qeL28資訊網——每日最新資訊28at.com

接著就是定義一個plugins插件數組,并且將cssVarsPlugin函數的返回結果push進去。qeL28資訊網——每日最新資訊28at.com

這里cssVarsPlugin函數就是返回了一個自定義的postcss插件。qeL28資訊網——每日最新資訊28at.com

最后就是執行result = postcss(plugins).process(source, postCSSOptions)拿到經過postcss轉換編譯器處理后的css。qeL28資訊網——每日最新資訊28at.com

可能有的小伙伴對postcss不夠熟悉,我們這里來簡單介紹一下。qeL28資訊網——每日最新資訊28at.com

postcss 是 css 的 transpiler(轉換編譯器,簡稱轉譯器),它對于 css 就像 babel 對于 js 一樣,能夠做 css 代碼的分析和轉換。同時,它也提供了插件機制來做自定義的轉換。qeL28資訊網——每日最新資訊28at.com

在我們這里主要就是用到了postcss提供的插件機制來完成css scoped的自定義轉換,調用postcss的時候我們傳入了source,他的值是style模塊中的css代碼。并且傳入的plugins插件數組中有個cssVarsPlugin插件,這個自定義插件就是vue寫的用于處理在css中使用v-bind指令。qeL28資訊網——每日最新資訊28at.com

在執行postcss對css代碼進行轉換之前我們在debug終端來看看此時的css代碼是什么樣的,如下圖:qeL28資訊網——每日最新資訊28at.com

sourcesourceqeL28資訊網——每日最新資訊28at.com

從上圖中可以看到此時的options.source中還是v-bind(primaryColor)指令。qeL28資訊網——每日最新資訊28at.com

cssVarsPlugin插件

cssVarsPlugin插件在我們這個場景中簡化后的代碼如下:qeL28資訊網——每日最新資訊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值都是不同的。qeL28資訊網——每日最新資訊28at.com

這里使用到了Declaration鉤子函數,css中每個具體的樣式都會觸發這個Declaration鉤子函數。qeL28資訊網——每日最新資訊28at.com

給Declaration鉤子函數打個斷點,當post-css處理到color: v-bind(primaryColor);時就會走到這個斷點中。如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

將字符串v-bind(primaryColor)賦值給變量value,接著執行if (vBindRE.test(value))。vBindRE是一個正則表達式,這里的意思是當前css的值是使用了v-bind指令才走到if語句里面。qeL28資訊網——每日最新資訊28at.com

接著就是執行while ((match = vBindRE.exec(value)))進行正則表達式匹配,如果value的值符合vBindRE正則表達式,也就是value的值是v-bind綁定的,那么就走到while循環里面去。qeL28資訊網——每日最新資訊28at.com

看到這里有的小伙伴會問了,這里使用if就可以了,為什么還要使用while循環呢?qeL28資訊網——每日最新資訊28at.com

答案是css的值可能是多個v-bind指令組成的,比如border: v-bind(borderWidth) solid v-bind(primaryColor);。這里的css值就由兩個v-bind組成,分別是v-bind(borderWidth)和v-bind(primaryColor);。qeL28資訊網——每日最新資訊28at.com

為了處理上面這種多個v-bind指令組成的css值,所以就需要使用while循環搭配exec方法。正則表達式使用了global標志位的時候,js的RegExp 對象是有狀態的,它們會將上次成功匹配后的位置記錄在 lastIndex 屬性中。使用此特性,exec() 可用來對單個字符串中的多次匹配結果進行逐條的遍歷。qeL28資訊網——每日最新資訊28at.com

在debug終端來看看此時的match數組是什么樣的,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到match[0]的值是正則表達式匹配的字符串,在我們這里匹配的字符串是v-bind(。match.index的值為匹配到的字符位于原始字符串的基于 0 的索引值。qeL28資訊網——每日最新資訊28at.com

看到這里有的小伙伴可能對match.index的值有點不理解,我舉個簡單的例子你一下就明白了。qeL28資訊網——每日最新資訊28at.com

還是以v-bind(borderWidth) solid v-bind(primaryColor)為例,這個字符串就是原始字符串,第一次在while循環中正則表達式匹配到第一個bind,此時的match.index的值為0,也就是第一個v在原始字符串的位置。第二次在while循環中會基于第一次的位置接著向后找,會匹配到第二個v-bind指令,此時的match.index的值同樣也是基于原始字符串的位置,也就是第二個v-bind中的v的位置,值為26。qeL28資訊網——每日最新資訊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所在的位置。qeL28資訊網——每日最新資訊28at.com

接著就是執行lexBinding函數拿到v-bind(primaryColor)中primaryColor變量的結束位置,賦值給變量end。在我們這個場景中簡化后的lexBinding函數代碼如下:qeL28資訊網——每日最新資訊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變量的結束位置。qeL28資訊網——每日最新資訊28at.com

接著來看拿到end變量后的代碼,會執行const variable = normalizeExpression(value.slice(start, end))。這里先執行了value.slice(start, end)根據start開始位置和end結束位置提取出v-bind指令綁定的變量,接著normalizeExpression函數對其進行trim去除空格。qeL28資訊網——每日最新資訊28at.com

在我們這個場景中簡化后的normalizeExpression函數代碼如下:qeL28資訊網——每日最新資訊28at.com

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

將從v-bind指令中提取出來的變量賦值給variable變量,接著執行字符串拼接拿到由v-bind指令轉換成的css變量,代碼如下:qeL28資訊網——每日最新資訊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)拿到的值也是空字符串。qeL28資訊網——每日最新資訊28at.com

接著來看后面這部分,使用字符串拼接得到:var(--變量)。這個看著就很熟悉了,他就是一個css變量。變量名是調用genVarName函數生成的,genVarName函數代碼如下:qeL28資訊網——每日最新資訊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表示當前是不是生產環境。qeL28資訊網——每日最新資訊28at.com

如果是生產環境就根據id和變量名使用哈希算法生成一個加密的字符串。qeL28資訊網——每日最新資訊28at.com

如果是開發環境就使用字符串拼接將id和變量名primaryColor拼接起來得到一個css變量。getEscapedCssVarName函數的代碼也很簡單,是對變量中的特殊字符進行轉義,以便在 CSS 變量名中使用。代碼如下:qeL28資訊網——每日最新資訊28at.com

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

這也就是為什么不同組件的primaryColor生成的css變量名稱不會沖突的原因了,因為在生成的css變量前面拼接了一個id,每個vue組件生成的id值都不同。qeL28資訊網——每日最新資訊28at.com

拿到轉換成css變量的css值后,并且將其賦值給變量transformed。接著就是執行lastIndex = end + 1,在我們這里lastIndex就指向了字符串的末尾。qeL28資訊網——每日最新資訊28at.com

最后就是執行decl.value = transformed + value.slice(lastIndex);將v-bind指令替換成css變量,由于lastIndex是指向了字符串的末尾,所以value.slice(lastIndex)的值也是一個空字符串。qeL28資訊網——每日最新資訊28at.com

所以在我們這里實際是執行了decl.value = transformed,執行完這句話后color的值就由v-bind(primaryColor)轉換成了var(--c845efc6-primaryColor)。qeL28資訊網——每日最新資訊28at.com

生成useCssVars函數

前面我們講過了編譯后的setup函數中多了一個useCssVars函數,實際在我們的源代碼中是沒有這個useCssVars函數的。接下來我們來看看編譯時處理script模塊時是如何生成useCssVars函數的。qeL28資訊網——每日最新資訊28at.com

在之前的 為什么defineProps宏函數不需要從vue中import導入?文章中我們講過了vue的script模塊中的代碼是由compileScript函數處理的,當然你沒看過那篇文章也不影響這篇文章的閱讀。qeL28資訊網——每日最新資訊28at.com

給compileScript函數打個斷點,在我們這個場景中簡化后的compileScript函數代碼如下:qeL28資訊網——每日最新資訊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。qeL28資訊網——每日最新資訊28at.com

  • ctx.s.toString:返回此時由script模塊編譯成的js代碼。
  • ctx.s.prependLeft:給編譯后的js代碼在指定index的前面插入字符串。

給ctx.s.prependLeft方法打個斷點,在debug終端使用ctx.s.toString方法來看看此時由script模塊編譯成的js代碼是什么樣的,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到此時生成的js代碼code字符串只有一條import語句和定義primaryColor變量。qeL28資訊網——每日最新資訊28at.com

由于篇幅有限我們就不深入到genCssVarsCode函數了,這個genCssVarsCode函數會生成useCssVars函數的調用。我們在debug終端來看看生成的code代碼字符串是什么樣的,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到genCssVarsCode函數生成了一個useCssVars函數。qeL28資訊網——每日最新資訊28at.com

執行ctx.s.prependLeft函數后會將生成的useCssVars函數插入到生成的js code代碼字符串的前面,我們在debug終端來看看,如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到此時的js code代碼字符串中已經有了一個useCssVars函數了。qeL28資訊網——每日最新資訊28at.com

執行useCssVars函數

前面我們講過了編譯時經過cssVarsPlugin這個post-css插件處理后,v-bind(primaryColor)指令就會編譯成了css變量var(--c845efc6-primaryColor)。這里只是使用css變量值的地方,那么這個css變量的值又是在哪里定義的呢?答案是在useCssVars函數中。qeL28資訊網——每日最新資訊28at.com

在開始我們講過了編譯后的setup函數中多了一個useCssVars函數,所以我們給useCssVars函數打個斷點,刷新瀏覽器此時代碼就會走到斷點中了。如下圖:qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

從上圖中可以看到執行useCssVars函數時傳入了一個回調函數作為參數,這個回調函數返回了一個對象。qeL28資訊網——每日最新資訊28at.com

將斷點走進useCssVars函數,在我們這個場景中簡化后的useCssVars函數代碼如下:qeL28資訊網——每日最新資訊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函數。qeL28資訊網——每日最新資訊28at.com

這個watchPostEffect函數大家應該知道,他是watchEffect() 使用 flush: 'post' 選項時的別名。qeL28資訊網——每日最新資訊28at.com

為什么需要使用 flush: 'post'呢?qeL28資訊網——每日最新資訊28at.com

答案是需要在setVars回調函數中需要去操作DOM,所以才需要使用 flush: 'post'讓回調函數在組件渲染完成之后去執行。qeL28資訊網——每日最新資訊28at.com

給setVars函數打個斷點,組件渲染完成后斷點將會走進setVars函數中。qeL28資訊網——每日最新資訊28at.com

首先會執行getter函數,將返回值賦值給變量vars。前面我們講過了這個getter函數是調用useCssVars函數時傳入的回調函數,代碼如下:qeL28資訊網——每日最新資訊28at.com

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

在這個回調函數中會返回一個對象,對象的key為c845efc6-primaryColor,這個key就是css變量var(--c845efc6-primaryColor)括號中的內容。qeL28資訊網——每日最新資訊28at.com

對象的值是ref變量primaryColor的值,由于這個代碼是在watchPostEffect的回調函數中執行的,所以這里的ref變量primaryColor也被作為依賴進行收集了。當primaryColor變量的值變化時,setVars函數也將再次執行。這也就是為什么在style中可以使用v-bind指令綁定一個響應式變量,并且當響應式變量的值變化時樣式也會同步更新。qeL28資訊網——每日最新資訊28at.com

接著就是執行setVarsOnVNode(instance.subTree, vars)函數,傳入的第一個參數為instance.subTree。他的值是當前vue組件根元素的虛擬DOM,也就是根元素div的虛擬DOM。第二個參數為useCssVars傳入的回調函數返回的對象,這是一個css變量組成的對象。qeL28資訊網——每日最新資訊28at.com

接著將斷點走進setVarsOnVNode函數,在我們這個場景中簡化后的代碼如下:qeL28資訊網——每日最新資訊28at.com

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

在setVarsOnVNode函數中是調用了setVarsOnNode函數,不同的是傳入的第一個參數不再是虛擬DOM。而是vnode.el虛擬DOM對應的真實DOM,也就是根節點div。qeL28資訊網——每日最新資訊28at.com

將斷點走進setVarsOnNode函數,在我們這個場景中簡化后的setVarsOnNode函數代碼如下:qeL28資訊網——每日最新資訊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樣式。qeL28資訊網——每日最新資訊28at.com

這里的vars是css變量組成的對象,遍歷這個對象。對象的key為css變量名稱,對象的value為css變量的值。qeL28資訊網——每日最新資訊28at.com

接著就是遍歷css變量組成的對象,使用style.setProperty方法給根節點div增加內聯樣式,也就是--c845efc6-primaryColor: red;。span元素由于是根節點div的子節點,所以他也繼承了樣式--c845efc6-primaryColor: red;。qeL28資訊網——每日最新資訊28at.com

由于span元素的color經過編譯后已經變成了css變量var(--c845efc6-primaryColor),并且從根節點繼承過來css變量--c845efc6-primaryColor的值為red,所以最終span元素的color值為red。qeL28資訊網——每日最新資訊28at.com

總結

下面這個是我總結的流程圖,如下(搭配流程圖后面的文字解釋一起服用效果最佳):qeL28資訊網——每日最新資訊28at.com

圖片圖片qeL28資訊網——每日最新資訊28at.com

編譯階段script模塊是由compileScript函數處理的,compileScript函數會去執行一個genCssVarsCode函數。這個函數會返回一個useCssVars函數的調用。然后在compileScript函數中會調用ctx.s.prependLeft方法將生成的useCssVars函數插入到編譯后的setup函數中。qeL28資訊網——每日最新資訊28at.com

編譯階段style模塊是由doCompileStyle函數處理的,在doCompileStyle函數中會調用postcss對css樣式進行處理。vue自定義了一個名為cssVarsPlugin的postcss插件,插件中有個Declaration鉤子函數,css中每個具體的樣式都會觸發這個Declaration鉤子函數。qeL28資訊網——每日最新資訊28at.com

在Declaration鉤子函數中使用正則表達式去匹配當前css值是不是v-bind綁定的,如果是就將匹配到的v-bind綁定的變量提取出來賦值給變量variable。還有一個id變量,他是根據當前vue組件的路徑生成的加密字符串。使用字符串拼接就可以得到var(--${id}-${variable}),他就是由v-bind編譯后生成的css變量。最終生成的css變量類似這樣:var(--c845efc6-primaryColor)。qeL28資訊網——每日最新資訊28at.com

運行時階段初始化的時候會去執行setup函數,由于在編譯階段setup函數中插入了一個useCssVars函數。使用在運行時階段初始化時useCssVars函數會被執行。qeL28資訊網——每日最新資訊28at.com

在useCssVars函數中執行了watchPostEffect函數,他是watchEffect() 使用 flush: 'post' 選項時的別名。qeL28資訊網——每日最新資訊28at.com

由于我們需要在回調中操作DOM,所以才需要使用flush: 'post',讓回調函數在組件渲染之后去執行。由于在回調函數中會去讀取v-bind綁定的響應式變量,所以每次綁定的響應式變量值變化后都會再次執行調用watchPostEffect傳入的回調函數,以此讓響應式變量綁定的樣式保存更新。qeL28資訊網——每日最新資訊28at.com

在watchPostEffect傳入的回調函數中會通過當前vue組件實例拿到真實DOM的根節點,然后遍歷css變量組成的對象,將這些css變量逐個在根節點上面定義,類似這樣:--c845efc6-primaryColor: red;。由于css可以繼承,所以子節點都繼承了這個css定義。qeL28資訊網——每日最新資訊28at.com

我們的<span>標簽在編譯階段由color: v-bind(primaryColor);編譯成了css變量color: var(--c845efc6-primaryColor)。并且在運行時由于useCssVars函數的作用在根節點生成了css變量的定義--c845efc6-primaryColor: red;。由于css繼承,所以span標簽也繼承了這個css變量的定義,所以span標簽渲染到頁面上的color值最終為red。qeL28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-99649-0.html新知識Get,Vue3是如何實現在Style中使用響應式變量?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 淺談Node.js核心組件

下一篇: 應該立即學習的鮮為人知的 CSS 特性

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
夜夜嗨av一区二区三区网页| 欧美jjzz| 亚洲欧洲日产国码二区| 国产精品女人网站| 欧美成人午夜激情在线| 久久精品一区| 欧美与黑人午夜性猛交久久久| 在线午夜精品| 在线亚洲一区二区| 日韩一级黄色av| 亚洲国产欧美一区二区三区同亚洲 | 欧美吻胸吃奶大尺度电影| 欧美xxxx在线观看| 久久色在线观看| 每日更新成人在线视频| 美国十次成人| 亚洲伊人网站| 9人人澡人人爽人人精品| 亚洲国产一区二区三区在线播| 在线成人小视频| 国产精品美女久久| 欧美色图一区二区三区| 欧美日韩精品国产| 国产精品黄视频| 国产精品久久999| 国产精品爱久久久久久久| 国产精品福利在线| 欧美日韩不卡一区| 欧美精品一区二区在线播放| 欧美日韩1区2区| 欧美日韩免费一区| 国产精品久久久久久久久久久久久 | 国产精品国产三级国产普通话99| 麻豆精品在线视频| 欧美a级在线| 欧美高清成人| 欧美日韩国产综合视频在线观看| 欧美日韩亚洲精品内裤| 国产精品成人在线| 亚洲素人在线| 久久av二区| 麻豆精品视频在线| 欧美精品首页| 国产精品久久午夜夜伦鲁鲁| 国产乱码精品一区二区三区不卡 | 中日韩高清电影网| 小嫩嫩精品导航| 久久久久一本一区二区青青蜜月| 欧美 日韩 国产在线| 老色批av在线精品| 亚洲乱亚洲高清| 亚洲欧美在线免费| 亚洲视频在线看| 亚洲午夜黄色| 亚洲人体一区| 亚洲人成人77777线观看| 一本大道av伊人久久综合| 亚洲制服av| 久久久欧美精品| 欧美国产日本| 国产精品高清免费在线观看| 国产日韩精品一区二区三区| 精品99一区二区三区| 亚洲九九精品| 欧美一区二区高清在线观看| 免费成年人欧美视频| 欧美日韩精品在线| 国产日韩精品在线| 在线观看欧美亚洲| 伊人久久久大香线蕉综合直播 | 久久xxxx精品视频| 日韩一级免费观看| 一区二区三区精品| 亚洲午夜激情网站| 久久久久久尹人网香蕉| 欧美日韩亚洲精品内裤| 国产九九精品视频| 在线看成人片| 亚洲一区二区成人| 久久久亚洲欧洲日产国码αv| 欧美破处大片在线视频| 国产一区亚洲| 亚洲天堂av在线免费观看| 久久高清国产| 欧美日韩另类丝袜其他| 好吊色欧美一区二区三区四区 | 国产在线日韩| 亚洲精品乱码久久久久久按摩观| 欧美一区二粉嫩精品国产一线天| 欧美成人一区二区三区| 欧美日韩一区高清| 亚洲高清在线视频| 99综合电影在线视频| 国产日韩精品视频一区二区三区 | 欧美视频一区二区三区| 国产欧美日韩视频一区二区三区| 亚洲国产精品黑人久久久| 亚洲午夜性刺激影院| 裸体女人亚洲精品一区| 国产精品亚洲综合久久| 国产精品亚洲激情| 国产精品进线69影院| 亚洲欧美日韩视频一区| 国产精品欧美日韩一区二区| 午夜亚洲福利| 红桃视频国产精品| 欧美电影电视剧在线观看| 在线观看一区| 久久影院午夜论| 亚洲欧洲另类国产综合| 欧美精品激情在线| 在线综合亚洲| 国产欧美日韩一区二区三区| 久久香蕉精品| 一区二区日韩免费看| 国产精品视频专区| 麻豆成人在线| 亚洲一区二区3| 黄色国产精品| 欧美日韩国产电影| 先锋影音网一区二区| 亚洲第一主播视频| 欧美午夜视频在线观看| 久久九九国产精品| 日韩亚洲欧美一区| 国产午夜精品视频免费不卡69堂| 噜噜噜噜噜久久久久久91| avtt综合网| 狠狠色狠狠色综合系列| 欧美日韩精品二区第二页| 欧美一级视频精品观看| 亚洲激情一区| 国产精品自拍一区| 欧美国产在线视频| 欧美一区久久| 日韩视频在线一区二区三区| 国产麻豆精品视频| 欧美精品一区二区三区在线看午夜| 亚洲欧美一区二区三区在线| 亚洲二区视频在线| 国产精品日韩久久久久| 欧美大学生性色视频| 欧美亚洲一区在线| 亚洲精选视频在线| 极品少妇一区二区三区| 欧美视频网址| 蜜臀av一级做a爰片久久| 亚洲欧美精品suv| 最新中文字幕亚洲| 国产一区二区三区自拍| 欧美三级中文字幕在线观看| 狂野欧美激情性xxxx欧美| 亚洲欧美视频| 一区二区毛片| 亚洲欧洲日产国产综合网| 国产在线麻豆精品观看| 国产精品乱码久久久久久| 欧美国产极速在线| 91久久精品www人人做人人爽| 欧美体内谢she精2性欧美 | 欧美福利一区| 欧美一区二区大片| 一区二区不卡在线视频 午夜欧美不卡在| 国产欧美日韩一区| 欧美性大战久久久久| 欧美高清自拍一区| 久久人人97超碰国产公开结果| 亚洲欧美国产高清| 一本大道久久精品懂色aⅴ| 18成人免费观看视频| 国产亚洲欧美日韩日本| 国产精品毛片大码女人| 欧美精品一区二区蜜臀亚洲 | 国产日韩精品综合网站| 国产精品久久影院| 欧美日韩在线电影| 欧美—级a级欧美特级ar全黄| 久久人人97超碰国产公开结果| 欧美一区二区私人影院日本| 亚洲主播在线| 亚洲在线电影| 亚洲婷婷综合色高清在线 | 久久国产精品一区二区三区四区 | 亚洲国产精品久久| 加勒比av一区二区| 国产一区二区三区久久| 国产精品久久国产精品99gif | 亚洲电影第1页| 国产综合视频| 国产午夜精品在线观看| 国产精品久久久久久久久久免费 | 亚洲图片在线观看| 亚洲精品久久久久久久久久久久| 精品成人国产| 在线成人av| 在线观看一区欧美| 亚洲第一成人在线| 亚洲成人在线| 亚洲第一狼人社区| 亚洲黄色成人久久久| 91久久在线观看| 亚洲人成在线播放| 亚洲免费黄色| 中文一区字幕|