vue3如何實現(xiàn)在style中使用響應式變量
前言
vue2的時候想必大家有遇到需要在style模塊中訪問script模塊中的響應式變量,為此我們不得不使用css變量去實現(xiàn)?,F(xiàn)在vue3已經(jīng)內置了這個功能啦,可以在style中使用v-bind
指令綁定script模塊中的響應式變量,這篇文章我們來講講vue是如何實現(xiàn)在style中使用script模塊中的響應式變量。注:本文中使用的vue版本為3.4.19
。
看個demo
我們來看個簡單的demo,index.vue文件代碼如下:
<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樣式上面。
我們在瀏覽器的network面板中來看看編譯后的js文件,如下圖:
從上圖中可以看到在network面板中編譯后的index.vue文件有兩個,并且第二個里面有一些query參數(shù),其中的type=style
就表示當前文件的內容對應的是style模塊。第一個index.vue對應的是template和script模塊中的內容。
我們來看看第一個index.vue,如下圖:
從上圖中可以看到setup函數(shù)是script模塊編譯后的內容,在setup
函數(shù)中多了一個_useCssVars
函數(shù),從名字你應該猜到了,這個函數(shù)的作用是和css變量有關系。別著急,我們接下來會詳細去講_useCssVars
函數(shù)。
我們再來看看第二個index.vue,如下圖:
從上圖中可以看到這個index.vue確實對應的是style模塊中的內容,并且原本的color: v-bind(primaryColor);
已經(jīng)變成了color: var(--c845efc6-primaryColor);
。
很明顯瀏覽器是不認識v-bind(primaryColor);
指令的,所以經(jīng)過編譯后就變成了瀏覽器認識的css變量var(--c845efc6-primaryColor);
。
我們接著在elements面板中來看看此時class值為block的span元素,如下圖:
從上圖中可以看到color的值為css變量var(--c845efc6-primaryColor)
,這個我們前面講過。不同的是這里從父級元素div中繼承過來一個--c845efc6-primaryColor: red;
。
這個就是聲明一個名為--c845efc6-primaryColor
的css變量,變量的值為red
。
還記得我們在script模塊中定義的響應式變量primaryColor
嗎?他的值就是red
。
所以這個span元素最終color渲染出來的值就是red
。
接下來我們將通過debug的方式帶你搞清楚在style中是如何將指令v-bind(primaryColor)
編譯成css變量var(--c845efc6-primaryColor)
,以及_useCssVars
函數(shù)是如何生成聲明值為red
的css變量--c845efc6-primaryColor
。
doCompileStyle
函數(shù)
在前面的文章中我們講過了style模塊實際是由doCompileStyle
函數(shù)函數(shù)處理的,具體如何調用到doCompileStyle
函數(shù)可以查看我之前的文章: 掉了兩根頭發(fā)后,我悟了!vue3的scoped原來是這樣避免樣式污染。
我們需要給doCompileStyle
函數(shù)打個斷點,doCompileStyle
函數(shù)的代碼位置在:node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js
。
還是一樣的套路啟動一個debug終端。這里以vscode
舉例,打開終端然后點擊終端中的+
號旁邊的下拉箭頭,在下拉中點擊Javascript Debug Terminal
就可以啟動一個debug
終端。
在debug終端執(zhí)行yarn dev
,在瀏覽器中打開對應的頁面,比如:http://localhost:5173/ 。
此時斷點將停留在doCompileStyle
函數(shù)中,在我們這個場景中doCompileStyle
函數(shù)簡化后的代碼如下:
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); } }
在前面的文章掉了兩根頭發(fā)后,我悟了!vue3的scoped原來是這樣避免樣式污染中我們講過了,這里id
的值為使用了scoped
后給html增加的自定義屬性data-v-x
,每個vue文件生成的x
都是不一樣的。在doCompileStyle
函數(shù)中使用id.replace
方法拿到x
賦值給變量shortId
。
接著就是定義一個plugins
插件數(shù)組,并且將cssVarsPlugin
函數(shù)的返回結果push進去。
這里cssVarsPlugin
函數(shù)就是返回了一個自定義的postcss
插件。
最后就是執(zhí)行result = postcss(plugins).process(source, postCSSOptions)
拿到經(jīng)過postcss
轉換編譯器處理后的css。
可能有的小伙伴對postcss
不夠熟悉,我們這里來簡單介紹一下。
postcss
是 css 的 transpiler(轉換編譯器,簡稱轉譯器),它對于 css 就像 babel 對于 js 一樣,能夠做 css 代碼的分析和轉換。同時,它也提供了插件機制來做自定義的轉換。
在我們這里主要就是用到了postcss
提供的插件機制來完成css scoped的自定義轉換,調用postcss
的時候我們傳入了source
,他的值是style模塊中的css代碼。并且傳入的plugins
插件數(shù)組中有個cssVarsPlugin
插件,這個自定義插件就是vue寫的用于處理在css中使用v-bind指令。
在執(zhí)行postcss
對css代碼進行轉換之前我們在debug終端來看看此時的css代碼是什么樣的,如下圖:
從上圖中可以看到此時的options.source
中還是v-bind(primaryColor)
指令。
cssVarsPlugin
插件
cssVarsPlugin
插件在我們這個場景中簡化后的代碼如下:
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
函數(shù)中傳過來的shortId
,每個vue文件對應的shortId
值都是不同的。
這里使用到了Declaration
鉤子函數(shù),css中每個具體的樣式都會觸發(fā)這個Declaration
鉤子函數(shù)。
給Declaration
鉤子函數(shù)打個斷點,當post-css
處理到color: v-bind(primaryColor);
時就會走到這個斷點中。如下圖:
將字符串v-bind(primaryColor)
賦值給變量value
,接著執(zhí)行if (vBindRE.test(value))
。vBindRE
是一個正則表達式,這里的意思是當前css的值是使用了v-bind指令才走到if語句里面。
接著就是執(zhí)行while ((match = vBindRE.exec(value)))
進行正則表達式匹配,如果value
的值符合vBindRE
正則表達式,也就是value
的值是v-bind
綁定的,那么就走到while循環(huán)里面去。
看到這里有的小伙伴會問了,這里使用if就可以了,為什么還要使用while
循環(huán)呢?
答案是css的值可能是多個v-bind指令組成的,比如border: v-bind(borderWidth) solid v-bind(primaryColor);
。這里的css值就由兩個v-bind組成,分別是v-bind(borderWidth)
和v-bind(primaryColor);
。
為了處理上面這種多個v-bind
指令組成的css值,所以就需要使用while循環(huán)搭配exec
方法。正則表達式使用了global標志位的時候,js的RegExp 對象是有狀態(tài)的,它們會將上次成功匹配后的位置記錄在 lastIndex 屬性中。使用此特性,exec()
可用來對單個字符串中的多次匹配結果進行逐條的遍歷。
在debug終端來看看此時的match
數(shù)組是什么樣的,如下圖:
從上圖中可以看到match[0]
的值是正則表達式匹配的字符串,在我們這里匹配的字符串是v-bind(
。match.index
的值為匹配到的字符位于原始字符串的基于 0 的索引值。
看到這里有的小伙伴可能對match.index
的值有點不理解,我舉個簡單的例子你一下就明白了。
還是以v-bind(borderWidth) solid v-bind(primaryColor)
為例,這個字符串就是原始字符串,第一次在while循環(huán)中正則表達式匹配到第一個bind,此時的match.index
的值為0,也就是第一個v
在原始字符串的位置。第二次在while循環(huán)中會基于第一次的位置接著向后找,會匹配到第二個v-bind指令,此時的match.index
的值同樣也是基于原始字符串的位置,也就是第二個v-bind
中的v
的位置,值為26。
在while循環(huán)中使用const start = match.index + match[0].length
給start
變量賦值,match.index
的值是v-bind
中的v
的位置。match[0]
是正則匹配到的字符串 v-bind(
。所以這個start
的位置就是v-bind(primaryColor)
中primaryColor
變量的開始位置,也就是p
所在的位置。
接著就是執(zhí)行lexBinding
函數(shù)拿到v-bind(primaryColor)
中primaryColor
變量的結束位置,賦值給變量end
。在我們這個場景中簡化后的lexBinding
函數(shù)代碼如下:
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
函數(shù)也很簡單,使用for循環(huán)遍歷v-bind(primaryColor)
字符串,如果發(fā)現(xiàn)字符串)
就說明找到了primaryColor
變量的結束位置。
接著來看拿到end
變量后的代碼,會執(zhí)行const variable = normalizeExpression(value.slice(start, end))
。這里先執(zhí)行了value.slice(start, end)
根據(jù)start
開始位置和end
結束位置提取出v-bind
指令綁定的變量,接著normalizeExpression
函數(shù)對其進行trim
去除空格。
在我們這個場景中簡化后的normalizeExpression
函數(shù)代碼如下:
function normalizeExpression(exp) { exp = exp.trim(); return exp; }
將從v-bind
指令中提取出來的變量賦值給variable
變量,接著執(zhí)行字符串拼接拿到由v-bind
指令轉換成的css變量,代碼如下:
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)
拿到的值也是空字符串。
接著來看后面這部分,使用字符串拼接得到:var(--變量)
。這個看著就很熟悉了,他就是一個css變量。變量名是調用genVarName
函數(shù)生成的,genVarName
函數(shù)代碼如下:
import hash from "hash-sum"; function genVarName(id, raw, isProd) { if (isProd) { return hash(id + raw); } else { return `${id}-${getEscapedCssVarName(raw)}`; } }
這個id是根據(jù)當前vue組件路徑生成的,每個vue組件生成的id都不同。這個raw
也就是綁定的響應式變量,在這里是primaryColor
。isProd
表示當前是不是生產(chǎn)環(huán)境。
如果是生產(chǎn)環(huán)境就根據(jù)id和變量名使用哈希算法生成一個加密的字符串。
如果是開發(fā)環(huán)境就使用字符串拼接將id
和變量名primaryColor
拼接起來得到一個css變量。getEscapedCssVarName
函數(shù)的代碼也很簡單,是對變量中的特殊字符進行轉義,以便在 CSS 變量名中使用。代碼如下:
const cssVarNameEscapeSymbolsRE = /[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g; function getEscapedCssVarName(key: string) { return key.replace(cssVarNameEscapeSymbolsRE, (s) => `\\${s}`); }
這也就是為什么不同組件的primaryColor
生成的css變量名稱不會沖突的原因了,因為在生成的css變量前面拼接了一個id
,每個vue組件生成的id
值都不同。
拿到轉換成css變量的css值后,并且將其賦值給變量transformed
。接著就是執(zhí)行lastIndex = end + 1
,在我們這里lastIndex
就指向了字符串的末尾。
最后就是執(zhí)行decl.value = transformed + value.slice(lastIndex);
將v-bind
指令替換成css變量,由于lastIndex
是指向了字符串的末尾,所以value.slice(lastIndex)
的值也是一個空字符串。
所以在我們這里實際是執(zhí)行了decl.value = transformed
,執(zhí)行完這句話后color的值就由v-bind(primaryColor)
轉換成了var(--c845efc6-primaryColor)
。
生成useCssVars
函數(shù)
前面我們講過了編譯后的setup函數(shù)中多了一個useCssVars
函數(shù),實際在我們的源代碼中是沒有這個useCssVars
函數(shù)的。接下來我們來看看編譯時處理script模塊時是如何生成useCssVars
函數(shù)的。
在之前的 為什么defineProps宏函數(shù)不需要從vue中import導入?文章中我們講過了vue的script模塊中的代碼是由compileScript
函數(shù)處理的,當然你沒看過那篇文章也不影響這篇文章的閱讀。
給compileScript
函數(shù)打個斷點,在我們這個場景中簡化后的compileScript
函數(shù)代碼如下:
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
。
ctx.s.toString
:返回此時由script模塊編譯成的js代碼。ctx.s.prependLeft
:給編譯后的js代碼在指定index
的前面插入字符串。
給ctx.s.prependLeft
方法打個斷點,在debug終端使用ctx.s.toString
方法來看看此時由script模塊編譯成的js代碼是什么樣的,如下圖:
從上圖中可以看到此時生成的js代碼code字符串只有一條import
語句和定義primaryColor
變量。
由于篇幅有限我們就不深入到genCssVarsCode
函數(shù)了,這個genCssVarsCode
函數(shù)會生成useCssVars
函數(shù)的調用。我們在debug終端來看看生成的code代碼字符串是什么樣的,如下圖:
從上圖中可以看到genCssVarsCode
函數(shù)生成了一個useCssVars
函數(shù)。
執(zhí)行ctx.s.prependLeft
函數(shù)后會將生成的useCssVars
函數(shù)插入到生成的js code代碼字符串的前面,我們在debug終端來看看,如下圖:
從上圖中可以看到此時的js code代碼字符串中已經(jīng)有了一個useCssVars
函數(shù)了。
執(zhí)行useCssVars
函數(shù)
前面我們講過了編譯時經(jīng)過cssVarsPlugin
這個post-css
插件處理后,v-bind(primaryColor)
指令就會編譯成了css變量var(--c845efc6-primaryColor)
。這里只是使用css變量值的地方,那么這個css變量的值又是在哪里定義的呢?答案是在useCssVars
函數(shù)中。
在開始我們講過了編譯后的setup函數(shù)中多了一個useCssVars
函數(shù),所以我們給useCssVars
函數(shù)打個斷點,刷新瀏覽器此時代碼就會走到斷點中了。如下圖:
從上圖中可以看到執(zhí)行useCssVars
函數(shù)時傳入了一個回調函數(shù)作為參數(shù),這個回調函數(shù)返回了一個對象。
將斷點走進useCssVars
函數(shù),在我們這個場景中簡化后的useCssVars
函數(shù)代碼如下:
function useCssVars(getter) { const instance = getCurrentInstance(); const setVars = () => { const vars = getter(instance.proxy); setVarsOnVNode(instance.subTree, vars); }; watchPostEffect(setVars); }
在useCssVars
函數(shù)中先調用getCurrentInstance
函數(shù)拿到當前的vue實例,然后將setVars
函數(shù)作為參數(shù)傳入去執(zhí)行watchPostEffect
函數(shù)。
這個watchPostEffect
函數(shù)大家應該知道,他是watchEffect() 使用 flush: 'post'
選項時的別名。
為什么需要使用 flush: 'post'
呢?
答案是需要在setVars
回調函數(shù)中需要去操作DOM,所以才需要使用 flush: 'post'
讓回調函數(shù)在組件渲染完成之后去執(zhí)行。
給setVars
函數(shù)打個斷點,組件渲染完成后斷點將會走進setVars
函數(shù)中。
首先會執(zhí)行getter
函數(shù),將返回值賦值給變量vars
。前面我們講過了這個getter
函數(shù)是調用useCssVars
函數(shù)時傳入的回調函數(shù),代碼如下:
_useCssVars((_ctx) => ({ "c845efc6-primaryColor": primaryColor.value }))
在這個回調函數(shù)中會返回一個對象,對象的key為c845efc6-primaryColor
,這個key就是css變量var(--c845efc6-primaryColor)
括號中的內容。
對象的值是ref變量primaryColor
的值,由于這個代碼是在watchPostEffect
的回調函數(shù)中執(zhí)行的,所以這里的ref變量primaryColor
也被作為依賴進行收集了。當primaryColor
變量的值變化時,setVars
函數(shù)也將再次執(zhí)行。這也就是為什么在style中可以使用v-bind指令綁定一個響應式變量,并且當響應式變量的值變化時樣式也會同步更新。
接著就是執(zhí)行setVarsOnVNode(instance.subTree, vars)
函數(shù),傳入的第一個參數(shù)為instance.subTree
。他的值是當前vue組件根元素的虛擬DOM,也就是根元素div的虛擬DOM。第二個參數(shù)為useCssVars
傳入的回調函數(shù)返回的對象,這是一個css變量組成的對象。
接著將斷點走進setVarsOnVNode
函數(shù),在我們這個場景中簡化后的代碼如下:
function setVarsOnVNode(vnode: VNode, vars) { setVarsOnNode(vnode.el, vars); }
在setVarsOnVNode
函數(shù)中是調用了setVarsOnNode
函數(shù),不同的是傳入的第一個參數(shù)不再是虛擬DOM。而是vnode.el
虛擬DOM對應的真實DOM,也就是根節(jié)點div。
將斷點走進setVarsOnNode
函數(shù),在我們這個場景中簡化后的setVarsOnNode
函數(shù)代碼如下:
function setVarsOnNode(el: Node, vars) { if (el.nodeType === 1) { const style = el.style; for (const key in vars) { style.setProperty(`--${key}`, vars[key]); } } }
在setVarsOnNode
函數(shù)中先使用if語句判斷el.nodeType === 1
,這個的意思是判斷當前節(jié)點類型是不是一個元素節(jié)點,比如<p>
和<div>
。如果是就走進if語句里面,使用el.style
拿到根節(jié)點的style樣式。
這里的vars
是css變量組成的對象,遍歷這個對象。對象的key為css變量名稱,對象的value為css變量的值。
接著就是遍歷css變量組成的對象,使用style.setProperty
方法給根節(jié)點div增加內聯(lián)樣式,也就是--c845efc6-primaryColor: red;
。span
元素由于是根節(jié)點div的子節(jié)點,所以他也繼承了樣式--c845efc6-primaryColor: red;
。
由于span元素的color經(jīng)過編譯后已經(jīng)變成了css變量var(--c845efc6-primaryColor)
,并且從根節(jié)點繼承過來css變量--c845efc6-primaryColor
的值為red
,所以最終span元素的color值為red
。
總結
下面這個是我總結的流程圖,如下(搭配流程圖后面的文字解釋一起服用效果最佳):
編譯階段script模塊是由compileScript
函數(shù)處理的,compileScript
函數(shù)會去執(zhí)行一個genCssVarsCode
函數(shù)。這個函數(shù)會返回一個useCssVars
函數(shù)的調用。然后在compileScript
函數(shù)中會調用ctx.s.prependLeft
方法將生成的useCssVars
函數(shù)插入到編譯后的setup函數(shù)中。
編譯階段style模塊是由doCompileStyle
函數(shù)處理的,在doCompileStyle
函數(shù)中會調用postcss
對css樣式進行處理。vue自定義了一個名為cssVarsPlugin
的postcss
插件,插件中有個Declaration
鉤子函數(shù),css中每個具體的樣式都會觸發(fā)這個Declaration
鉤子函數(shù)。
在Declaration
鉤子函數(shù)中使用正則表達式去匹配當前css值是不是v-bind
綁定的,如果是就將匹配到的v-bind
綁定的變量提取出來賦值給變量variable
。還有一個id
變量,他是根據(jù)當前vue組件的路徑生成的加密字符串。使用字符串拼接就可以得到var(--${id}-${variable})
,他就是由v-bind
編譯后生成的css變量。最終生成的css變量類似這樣:var(--c845efc6-primaryColor)
。
運行時階段初始化的時候會去執(zhí)行setup函數(shù),由于在編譯階段setup函數(shù)中插入了一個useCssVars
函數(shù)。使用在運行時階段初始化時useCssVars
函數(shù)會被執(zhí)行。
在useCssVars
函數(shù)中執(zhí)行了watchPostEffect
函數(shù),他是watchEffect() 使用 flush: 'post'
選項時的別名。
由于我們需要在回調中操作DOM,所以才需要使用flush: 'post'
,讓回調函數(shù)在組件渲染之后去執(zhí)行。由于在回調函數(shù)中會去讀取v-bind
綁定的響應式變量,所以每次綁定的響應式變量值變化后都會再次執(zhí)行調用watchPostEffect
傳入的回調函數(shù),以此讓響應式變量綁定的樣式保存更新。
在watchPostEffect
傳入的回調函數(shù)中會通過當前vue組件實例拿到真實DOM的根節(jié)點,然后遍歷css變量組成的對象,將這些css變量逐個在根節(jié)點上面定義,類似這樣:--c845efc6-primaryColor: red;
。由于css可以繼承,所以子節(jié)點都繼承了這個css定義。
我們的<span>
標簽在編譯階段由color: v-bind(primaryColor);
編譯成了css變量color: var(--c845efc6-primaryColor)
。并且在運行時由于useCssVars
函數(shù)的作用在根節(jié)點生成了css變量的定義--c845efc6-primaryColor: red;
。由于css繼承,所以span標簽也繼承了這個css變量的定義,所以span標簽渲染到頁面上的color值最終為red
。
到此這篇關于vue3實現(xiàn)在style中使用響應式變量的文章就介紹到這了,更多相關vue3 style響應式變量內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Vue3如何利用xlsx、xlsx-js-style導出Excel表格使用(適合新手)
- Vue3中使用styled-components的實現(xiàn)
- 在 Vue3 中如何使用 styled-components
- Vue使用xlsx和xlsx-style導出表格出現(xiàn)部分樣式缺失的問題解決
- vue使用xlsx庫和xlsx-style庫導入導出excel、設置單元格背景色、文字居中、合并單元格、設置列寬
- 使用Vue綁定class和style樣式的幾種寫法總結
- vue如何在style標簽中使用變量(數(shù)據(jù))詳解
- 在VUE style中使用data中的變量的方法
- 在vue中:style 的使用方式匯總
相關文章
Vue項目從webpack3.x升級webpack4不完全指南
前段時間,泡面將自己的一個Vue-cli構建的前端框架從webpack3.x升級到了4.x版本,現(xiàn)在才拉出來記錄一下,已備忘之用,也和大家分享一下,需要的朋友可以參考下2019-04-04vue2項目實現(xiàn)自定義右鍵菜單,可添加圖標、事件等方式
這篇文章主要介紹了vue2項目實現(xiàn)自定義右鍵菜單,可添加圖標、事件等方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04基于Vue2.0和Typescript實現(xiàn)多主題切換的示例
本文主要介紹了基于Vue2.0和Typescript實現(xiàn)多主題切換的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04Vue3中數(shù)據(jù)響應式原理與高效數(shù)據(jù)操作全解析
這篇文章主要為大家詳細介紹了Vue3中數(shù)據(jù)響應式原理與高效數(shù)據(jù)操作的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2025-02-02