基于CssVariable的主題切換示例

小編給大家分享一下基于Css Variable的主題切換示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

在泰安等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站制作、成都網(wǎng)站設(shè)計 網(wǎng)站設(shè)計制作定制網(wǎng)站設(shè)計,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站建設(shè),成都營銷網(wǎng)站建設(shè),外貿(mào)營銷網(wǎng)站建設(shè),泰安網(wǎng)站建設(shè)費用合理。

當(dāng)接到這個需求的時候,百度到業(yè)界關(guān)于主題切換的方案還挺多的,css鏈接替換、className更改、less.modifyVars、css in js等等,但每一種方案聽起來都是又累又貴。有沒有那種代碼侵入低,小白無腦又好維護(hù)的方案呢?那自然是有的,確切的說是css它本身就支持。

Css3 Variable

定義一個全局顏色變量,改變這個變量的值頁面內(nèi)所有引用這個變量的元素都會進(jìn)行改變。好簡單是不是?

// base.less
:root {
  --primary: green;
  --warning: yellow;
  --info: white;
  --danger: red;
}

// var.less
@primary: var(--primary)
@danger: var(--danger)
@info: var(--info)

// page.less
.header {
  background-color: @primary;
  color: @info;
}
.content {
  border: 1px solid @danger;
}
// change.js
function changeTheme(themeObj) {
  const vars = Object.keys(themeObj).map(key => `--${key}:${themeObj[key]}`).join(';')
  document.documentElement.setAttribute('style', vars)
}

本文結(jié)束

個P,它不支持 IE啊??!0202年還要兼容IE嗎?是的,就是要兼容IE。

基于Css Variable的主題切換示例 

css vars ponyfill

是的,還真有polyfill能兼容IE: css-vars-ponyfill 。它搞定IE的方式大概是這樣子的

+-------------------------+
|   獲取頁面內(nèi)style標(biāo)簽內(nèi)容  |
|     請求外鏈css內(nèi)容       |
+-------------------------+
  |
  |
  v
+-------------------------+  是   +-------------------------+
|      內(nèi)容是否含有var()    | ----> |        標(biāo)記為src         |
+-------------------------+       +-------------------------+
  |                                 |
  | 否                              |
  v                                 v
+-------------------------+       +-------------------------+
|       標(biāo)記為skip         |       |   將var(*)替換為變量值,  |
|                         |       |  新增style標(biāo)簽添加到head  |
+-------------------------+       +-------------------------+

效果大概是這個樣子的

基于Css Variable的主題切換示例 

簡單粗暴又不失優(yōu)雅,在支持css var的瀏覽器中不會進(jìn)行處理,所以不需要擔(dān)心性能問題( 是IE的問題,不是我的問題

)。 我們來改造一下代碼

// store/theme.js
import cssVars from 'css-vars-ponyfill'

export default {
  state: {
    'primary': 'green',
    'danger': 'white'
  },
  mutations: {
    UPDATE_THEME(state, payload) {
      const variables = {}
      Object.assign(state, payload)
      Object.keys(state).forEach((key) => {
        variables[`--${key}`] = state[key]
      })
      cssVars({
        variables
      })
    }
  },
  actions: {
    changeTheme({ commit }, theme = {}) {
      commit('UPDATE_THEME', theme)
    }
  }
}

// router.js
// 因為路由跳轉(zhuǎn)后的頁面會按需加載新的css資源,重新轉(zhuǎn)換
const convertedPages = new Set()
router.afterEach((to) => {
  if (convertedPages.has(to.path)) return
  convertedPages.add(to.path)
  context.store.dispatch('theme/changeTheme')
})

SSR項目閃屏問題優(yōu)化

在SSR項目中用上述方案你可能會在IE中看到這樣的情況

基于Css Variable的主題切換示例 

因為 css-vars-ponyfill

是依賴dom元素來實現(xiàn)轉(zhuǎn)換的,在node中無法使用,所以從server直出未轉(zhuǎn)換的css代碼到client加載js文件轉(zhuǎn)換css間存在一段樣式空檔。

+- - - - - - - - - - - - - - - - - - - -+
                 ' 樣式空窗期:                             '
                 '                                       '
+----------+     ' +----------------+     +------------+ '     +-------------+
| 發(fā)起請求  | --> ' |  SSR直出頁面     | --> | 加載js依賴  | ' --> |  替換css變量 |
+----------+     ' +----------------+     +------------+ '     +-------------+
                 '                                       '
                 +- - - - - - - - - - - - - - - - - - - -+

解決這個問題也很簡單,只需要在每個用到 css var 的地方加上一個兼容寫法

@_primary: red
@primary: var(--primary)

:root{
  --primary: @_primary
}

.theme {
  color: @primary;
}

// 改為
.theme {
  color: @_primary;
  color: @primary;
}

在不支持css var的瀏覽器上會渲染默認(rèn)顏色 red ,等待js加載完畢后ponyfill替換樣式覆蓋。

Webpack插件開發(fā)

手動在每個用到的地方添加兼容寫法既幸苦又不好維護(hù),這個時候我們需要了解一些 webpack 生命周期以及插件開發(fā)相關(guān)的知識,我們可以通過手寫一個webpack插件,在 normalModuleLoader ( v5版本被廢棄,使用NormalModule.getCompilationHooks(compilation).loader )的hooks中為所有css module添加一個loader來處理兼容代碼。

筆者項目使用了less,注意webpack中l(wèi)oader執(zhí)行順序是 類似棧的先進(jìn)后出,所以我需要把轉(zhuǎn)換loader添加到less-loader之前,確保我們處理的是編譯后的css var寫法而非less變量。

// plugin.js
export default class HackCss {
  constructor (theme = {}) {
    this.themeVars = theme
  }

  apply(compiler) {
        compiler.hooks.thisCompilation.tap('HackCss', (compilation) => {
          compilation.hooks.normalModuleLoader.tap(
            'HackCss',
            (_, moduleContext) => {
              if (/\.vue\?vue&type=style/.test(moduleContext.userRequest)) {
                // ssr項目同構(gòu)會有2次compiler,如果module中存在loader則不繼續(xù)添加
                if (hasLoader(moduleContext.loaders, 'hackcss-loader.js')) {
                  return
                }

                let lessLoaderIndex = 0
                // 項目用了less,找到less-loader的位置
                moduleContext.loaders.forEach((loader, index) => {
                  if (/less-loader/.test(loader.loader)) {
                    lessLoaderIndex = index
                  }
                })
  
                moduleContext.loaders.splice(lessLoaderIndex, 0, {
                  loader: path.resolve(__dirname, 'hackcss-loader.js'),
                  options: this.themeVars
                })
              }
            }
          )
        })
      }
    })
}

// loader.js
const { getOptions } = require('loader-utils')

module.exports = function(source) {
  if (/module\.exports/.test(source)) return source
  const theme = getOptions(this) || {}
  return source.replace(
    /\n(.+)?var\(--(.+)?\)(.+)?;/g,
    (content, before, name, after = '') => {
      const [key, indent] = before.split(':')
      const add = after.split(';')[0]
      return `\n${key}:${indent}${theme[name]}${after}${add};${content}`
    }
  )
}

至此,我們可以愉快自如的切換主題了。

基于Css Variable的主題切換示例 

以上是“基于Css Variable的主題切換示例”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

分享名稱:基于CssVariable的主題切換示例
文章起源:http://bm7419.com/article48/jjssep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)站排名企業(yè)網(wǎng)站制作、全網(wǎng)營銷推廣、App設(shè)計、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)