Vue3 style CSS 變量注入的實(shí)現(xiàn)
摘要
在單文件組件樣式中支持使用組件狀態(tài)驅(qū)動的 CSS 變量( CSS 自定義屬性)。
基礎(chǔ)示例
<template> <div class="text">hello</div> </template> <script> export default { data() { return { color: 'red', font: { size: '2em', }, } }, } </script> <style> .text { color: v-bind (color); /* expressions (wrap in quotes) */ font-size: v-bind ('font.size'); } </style>
動機(jī)
Vue SFC 樣式提供了直接的 CSS 搭配和封裝,但它是純粹的靜態(tài)的 —— 這意味著到目前為止,我們沒有能力在運(yùn)行時根據(jù)組件的狀態(tài)動態(tài)更新樣式。
現(xiàn)在,隨著大多數(shù)現(xiàn)代瀏覽器支持原生 CSS 變量,我們可以利用它來輕松連接組件的狀態(tài)和樣式。
設(shè)計細(xì)節(jié)
SFC 中的標(biāo)簽現(xiàn)在支持一個自定義 CSS 函數(shù) v-bind:
<!-- in Vue SFC --> <style> .text { color: v-bind (color); } </style>
正如預(yù)期的那樣,這將把聲明的值綁定到組件狀態(tài)的屬性上,reactively.color color
該函數(shù)內(nèi)部可以支持任意的 JavaScript 表達(dá)式,但由于 JavaScript 表達(dá)式可能包含在 CSS 標(biāo)識符中無效的字符,因此在大多數(shù)情況下需要用引號來包裹它們:v-bind
.text { font-size: v-bind ('theme.font.size'); }
當(dāng)檢測到這種 CSS 變量時,SFC 編譯器將執(zhí)行以下操作:
重寫到一個帶有哈希變量名稱的本機(jī)。上面的內(nèi)容將被改寫為:v-bind () var ()
.text { color: var (--6b53742-color); font-size: var (--6b53742-theme_font_size); }
請注意,hash 將應(yīng)用于所有情況,無論標(biāo)簽是否有范圍。這意味著注入的 CSS 變量不會意外地泄漏到子組件中。
相應(yīng)的變量將作為內(nèi)聯(lián)樣式被注入到組件的根元素中。對于上面的例子,最終渲染的 DOM 將看起來像這樣:
<div style="--6b53742-color:red;--6b53742-theme_font_size:2em;" class="text"> hello </div>
注入是響應(yīng)式的 ——所以如果組件的屬性發(fā)生變化,注入的 CSS 變量將被相應(yīng)地更新。這種更新是獨(dú)立于組件的模板更新的,所以對一個純 CSS 的響應(yīng)式屬性的改變不會觸發(fā)模板的重新渲染。
編譯細(xì)節(jié)
為了注入 CSS 變量,編譯器需要生成并注入如下代碼到組件的 setup ()
import { useCssVars } from 'vue' export default { setup() { //... useCssVars(_ctx => ({ color: _ctx.color, theme_font_size: _ctx.theme.font.size, })) }, }
... 這里,運(yùn)行時幫助器設(shè)置了一個將變量響應(yīng)性地應(yīng)用到 DOM.useCssVars watchEffect 上。
該編譯策略要求腳本編譯時首先對標(biāo)簽內(nèi)容進(jìn)行簡單的重碼解析,以確定要暴露的變量列表。然而,這個解析階段不會像基于 AST 的完整解析 <style> 那樣耗費(fèi)開銷。
在生產(chǎn)中,變量名可以被進(jìn)一步 hash,以減少 CSS 的占用。
.text { color: var (--x3b2fs2); font-size: var (--29fh29g); }
相應(yīng)的生成的 JavaScript 代碼將相應(yīng)地使用相同的哈希值。
采用策略
這是一個完全向后兼容的新功能。然而,我們應(yīng)該明確指出,它依賴于本地的 CSS 變量,所以用戶需要了解瀏覽器的支持范圍。
實(shí)踐
在 script 中聲明兩個響應(yīng)式的屬性,分別是 wallpaperBlur 和 wallpaperMask。wallpaperBlur 表示壁紙的模糊程度, wallpaperMask 表示遮罩的透明度。通過 v-bind 將它們應(yīng)用到 style,這意味著當(dāng)我們在 script 中改變這兩個值時,樣式會響應(yīng)更改。
// script const wallpaperBlur = ref('0px') const wallpaperMask = ref('rgba(0, 0, 0, 0)')
// style .wallpaper { filter: blur(v-bind(wallpaperBlur)); bottom: calc(v-bind(wallpaperBlur) * -2); left: calc(v-bind(wallpaperBlur) * -2); right: calc(v-bind(wallpaperBlur) * -2); top: calc(v-bind(wallpaperBlur) * -2); .wallpaper-image { transition: background-image 0.6s, background-color 0.4s; } .wallpaper-mask { background-color: v-bind(wallpaperMask); } }
提示
綁定恰當(dāng)?shù)膶傩?br />
在上面的例子中,你可能想到到更改遮罩的透明度僅需要聲明一個 0-1 的數(shù)字,之后在 style 中這樣寫:
.wallpaper-mask { background-color: rgba(0, 0, 0, v-bind(wallpaperMask)); }
上文已經(jīng)提到在編譯階段會將 style 中的 v-bind 改寫為 CSS 變量的形式,上面的代碼會被改寫為這樣:
.wallpaper-mask { background-color: rgba(0, 0, 0, var (--[hash]-wallpaper_mask)); }
rgba(0, 0, 0, var (--[hash]-wallpaper_mask)) 在 CSS 中是無法被解析的。所以這就是為什么將 wallpaperMask 的初始值聲明為 rgba(0, 0, 0, 0) 的原因。這是需要十分注意的一點(diǎn),CSS 中還有許多類似的情況。
注意 style 的更新
在設(shè)計細(xì)節(jié)中提到相應(yīng)的變量將作為內(nèi)聯(lián)樣式被注入到組件的根元素中。最終渲染的 DOM 將看起來像這樣:
<div style="--6b53742-color:red;--6b53742-theme_font_size:2em;"></div>
當(dāng)你在 <script> 中改變 <style> 中綁定的屬性時,內(nèi)斂樣式中的 CSS 變量將會響應(yīng)更改。但是,并不能單獨(dú)更新內(nèi)斂樣式其中的一個 CSS 變量,這意味著更新一個組件中的任意一個“動態(tài)樣式”,都將引起根組件中的內(nèi)斂樣式全部更新。當(dāng) style 屬性的值包含大量 CSS 變量時,你需要考慮重新組織組件。因?yàn)榫幾g生成的 CSS 變量都將作為內(nèi)聯(lián)樣式被注入到組件的根元素中,我們無法控制這種行為,將一個引起更新的 CSS 變量和其他 CSS 變量解耦。
試想這種情況, style 中編譯生成的 CSS 變量中包含一個其值為龐大的 base64 的 CSS 變量。當(dāng)更新該組件中其他 CSS 變量時,整個 style 都將更新,這將帶來額外的硬件開銷。我們需要將這個生成 base64 CSS 變量的組件單獨(dú)抽離,以使該 CSS 變量注入到該組件的根元素,不受其他 CSS 變量更新影響。
參考資料
https://github.com/vuejs/rfcs/pull/231
到此這篇關(guān)于Vue3 style CSS 變量注入的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Vue3 style CSS變量注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何解決Vue3組合式API模式下動態(tài)組件不渲染問題
這篇文章主要介紹了如何解決Vue3組合式API模式下動態(tài)組件不渲染問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教<BR>2024-03-03Vue源碼學(xué)習(xí)記錄之手寫vm.$mount方法
在我們開發(fā)中,經(jīng)常要用到Vue.extend創(chuàng)建出Vue的子類來構(gòu)造函數(shù),通過new 得到子類的實(shí)例,然后通過$mount掛載到節(jié)點(diǎn),今天通過本文給大家講解手寫vm.$mount方法 ,感興趣的朋友一起看看吧2022-11-11vant/vue手機(jī)端長按事件以及禁止長按彈出菜單實(shí)現(xiàn)方法詳解
這篇文章主要介紹了vant/vue手機(jī)端長按事件以及禁止長按彈出菜單實(shí)現(xiàn)方法詳解,需要的朋友可以參考下2022-12-12element ui loading加載開啟與關(guān)閉方式
這篇文章主要介紹了element ui loading加載開啟與關(guān)閉方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08vue動態(tài)路由:路由參數(shù)改變,視圖不更新問題的解決
今天小編就為大家分享一篇vue動態(tài)路由:路由參數(shù)改變,視圖不更新問題的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11Vue 動態(tài)生成數(shù)據(jù)字段的實(shí)例
這篇文章主要介紹了Vue 動態(tài)生成數(shù)據(jù)字段的實(shí)例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04