欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入探索VueJS Scoped CSS 實(shí)現(xiàn)原理

 更新時(shí)間:2019年09月23日 14:39:41   作者:Lionad-Morotar  
這篇文章主要介紹了深入探索VueJS Scoped CSS 實(shí)現(xiàn)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

使用VueJS進(jìn)行應(yīng)用開(kāi)發(fā), 脫離不了對(duì)應(yīng)用間的模塊進(jìn)行拆分, 將大塊界面拆解為組件的過(guò)程. 我們可以很方便的在單文件中使用<template>塊維護(hù)組件的視圖, 使用<script>維護(hù)組件的邏輯部分, 使用<style>維護(hù)組件的樣式. 在我們編寫(xiě) VueJS 組件樣式時(shí), 不得忽略的一點(diǎn)就是樣式污染.

樣式污染產(chǎn)生原因

提及樣式污染, 主要要追溯到Webpack對(duì)CSS文件的打包過(guò)程, 這里我們以Vue-Element-Admin中的Webpack配置項(xiàng)舉例:

const webpackConfig = merge(baseWebpackConfig, {
 plugins: [
 new MiniCssExtractPlugin({
     filename: utils.assetsPath('css/[name].[contenthash:8].css'),
     chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
    }),
 ]
})

Webpack 使用 MiniCssExtractPlugin 插件, 將文件(如Vue單文件組件)中的CSS代碼, 經(jīng)過(guò)處理后, 分離到形如app.hash1234.css的單獨(dú)的CSS文件:

如果沒(méi)有加入防止樣式污染的措施的同時(shí), 項(xiàng)目中存在了大量的同名 ClassName, 那么可能會(huì)產(chǎn)生意想不到的CSS選擇器權(quán)重覆蓋. 這可能使后文件中某部分選擇器權(quán)重更高的類影響整個(gè)應(yīng)用, 而此過(guò)程通常發(fā)生在組件的編寫(xiě)中, 所以一般稱之為組件樣式污染.

Webpack & Vue SFC Object

對(duì)于 Vue 項(xiàng)目而言, 使用 Webpack 將極大的優(yōu)化了工作流程, 因?yàn)橥ㄟ^(guò)Vue Loader, Vue 單文件組件能很好的融合進(jìn) Webpack 工作流中. 通過(guò)跟蹤源碼, 可以發(fā)現(xiàn), 我們寫(xiě)的單文件組件都被處理為了SFC對(duì)象, 即包含了單個(gè)HTML模塊, 單個(gè)腳本模塊, 一個(gè)或多個(gè)樣式模塊, 一個(gè)或多個(gè)自定義模塊的對(duì)象:

// vue-loader/index.js
const descriptor = parse({
  source,
  compiler: options.compiler || loadTemplateCompiler(),
  filename,
  sourceRoot,
  needMap: sourceMap
})

// vuejs/component-compiler-utils/index.js
function parse(options) {
  const { compiler } = options
  output = compiler.parseComponent(source, compilerParseOptions)
  return output
}

// vue.js
function parseComponent(content, options) {
 // ...
  var sfc = {
    template: null,
    script: null,
    styles: [],
    customBlocks: []
  }
  // ...
  return sfc
}

我們可以將SFC結(jié)構(gòu)融合到Webpack進(jìn)行開(kāi)發(fā)的過(guò)程成中, 主要有這幾點(diǎn)影響:

  • 允許為 Vue 組件的每個(gè)部分使用其它的 webpack loader,例如在 <style>的部分使用 Sass Loader , 在 <customBlocks>的部分使用自定義 Loader
  • 使用 webpack loader 將 <style>和 <template> 中引用的資源當(dāng)作模塊依賴來(lái)處理
  • 模擬 Scoped CSS
  • 在開(kāi)發(fā)過(guò)程中使用熱重載來(lái)保持狀態(tài)

以下主要介紹Scoped CSS的原理.

Scoped CSS

大白話版本之 Scoped CSS 原理

通過(guò) Webpack 調(diào)用 VueJS 中相應(yīng) Loader , 給組件HTML模板添加自定義屬性 (Attribute) data-v-x, 以及給組件內(nèi)CSS選擇器添加對(duì)應(yīng)的屬性選擇器 (Attribute Selector) [data-v-x], 達(dá)到組件內(nèi)樣式只能生效與組件內(nèi)HTML的效果, 代碼效果如下:

<div class='lionad' data-v-lionad></div>
<style>
.lionad[data-v-lionad] {
 background: @tiger-orange;
}
</style>

源碼跟蹤

Webpack 使用其它 CSS Loader 處理 VueJS 中對(duì)應(yīng) CSS 代碼之前, Vue Loader 已經(jīng)替我們做了一層簡(jiǎn)單的處理, 如果組件中 style 塊包含了 scoped 屬性:

<!-- 某個(gè)VueJS組件中 -->
<template>
  <div class='lionad'></div>
</template>
<style lang="scss" scoped>
  .lionad {
    background: @tiger-orange;
  }
</style>

下代碼即判斷當(dāng)前SFC對(duì)象樣式塊中是否有scoped屬性, 并插入用于 query 中, 順帶一提, 每個(gè)單文件組件被解析后, 都會(huì)生成對(duì)應(yīng)組件ID, ID主要以生產(chǎn)/開(kāi)發(fā)環(huán)境做區(qū)分, 通過(guò)文件路徑+源碼或是文件路徑的值作為哈希特征值的形式生成, 如下:

// vue-loader/index.js
const id = hash(isProduction (shortFilePath + '\n' + source) : shortFilePath)
const hasScoped = descriptor.styles.some(s => s.scoped)
const query = `? vue&type=template${idQuery}${scopedQuery}`
const request = templateRequest = stringifyRequest(src + query)
templateImport = `import { render, staticRenderFns } from ${request}`

HTML模板處理

在用于處理SFC結(jié)構(gòu)中HTML模板的 templateLoader 中, 我們可以得知, query 中所設(shè)置的參數(shù)將合并為 loader options 經(jīng)由 Webpack 轉(zhuǎn)交 templateLoader 再轉(zhuǎn)交 @vue/component-compiler-utils.compileTemplate 處理:

// vue-loader/templateLoader.js
const query = qs.parse(this.resourceQuery)
const { id } = query
const compilerOptions = Object.assign({}, options.compilerOptions, {
  scopeId: query.scoped ? `data-v-${id}` : null
})
const compiled = compileTemplate({ compilerOptions })

實(shí)際 compileTemplate 函數(shù)在處理內(nèi)容時(shí), 編譯函數(shù)使用的是 query 中的 compiler 或 vue-template-compiler, 后者會(huì)將模板文本轉(zhuǎn)換成為 JavaScript 渲染函數(shù), 大致如下:

  1. 從HTML模版轉(zhuǎn)換為AST(虛擬語(yǔ)法樹(shù))
  2. AST優(yōu)化,處理靜態(tài)模版與動(dòng)態(tài)模板
  3. 生成JS函數(shù),用于在運(yùn)行時(shí)運(yùn)行時(shí)生成純HTML

代碼分別對(duì)應(yīng):

// vue-template-compiler/build.js/createCompilerCreator
var ast = parse(template.trim(), options)
optimize(ast, options)
var code = generate(ast, options)

先前我們的組件ID在 parse 階段解析開(kāi)始標(biāo)簽時(shí)就會(huì)被推入內(nèi)部?jī)?chǔ)存的數(shù)據(jù)結(jié)構(gòu)中:

function elementToOpenTagSegments (el, state) {
 var segments = [{ type: RAW, value: ("<" + (el.tag)) }]
 // _scopedId
 if (state.options.scopeId) {
  segments.push({ type: RAW, value: (" " + (state.options.scopeId)) })
 }
 segments.push({ type: RAW, value: ">" })
 return segments
}

先前我們的HTML模板 <div class='lionad'></div> 中開(kāi)始標(biāo)簽會(huì)被轉(zhuǎn)換成如下數(shù)據(jù)結(jié)構(gòu):

[
  { type: RAW, value: '<div' },
  { type: RAW, value: 'class=lionad' },
  { type: RAW, value: 'data-v-xxxxxx' },
  { type: RAW, value: '>' },
]

樣式模板處理

與 HTML Template 解析的過(guò)程類似, 通過(guò) Webpack 將樣式模板轉(zhuǎn)交 stylePostLoader 進(jìn)行處理, 處理邏輯主要引用了 @vue/component-compiler-utils 中的 compileStyle 部分, 后者對(duì)樣式模板進(jìn)行解析的過(guò)程中, 將會(huì)對(duì)含 scoped 標(biāo)記的模板引入插件 stylePlugins/scoped.js, scoped.js 將 data-v-xxxxxx 添加到選擇器末尾的過(guò)程如下:

selectors.each((selector) => {
  selector.each((n) => {
    if (n.value === '::v-deep' || n.value === '>>>' || n.value === '/deep/') {
      return false;
    }
  });
  selector.insertAfter(node, selectorParser.attribute({
    attribute: id
  }))
})

題外話, 通過(guò)以上代碼, 我們發(fā)現(xiàn)當(dāng)當(dāng)前處理到三種特定類型選擇器會(huì)終止循環(huán), 停止將 data-v-xxx 添加到選擇器末尾:

  1. 偽類 ::v-deep
  2. 選擇器 >>>
  3. 選擇器 /deep/

我們可以利用這個(gè)特征, 在組件中寫(xiě)樣式穿透, 即內(nèi)部組件影響外部組件樣式 (ε=ε=ε=┏(゜ロ゜;)┛ 主動(dòng)樣式污染), 當(dāng)然這在特定的情境下是有用的, 比如當(dāng)我們想主動(dòng)覆蓋第三方UI組件框架的樣式, 卻不想引入新的CSS文件, 或不想寫(xiě)非 Scoped CSS 模板的時(shí)候.

最后

本人前端菜得捉急, 文中不詳盡或有錯(cuò)的地方, 歡迎各位大佬斧正. 如果本文對(duì)你有所幫助, 那是再好不過(guò), 看到這里都是真愛(ài)啊

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue+springboot實(shí)現(xiàn)項(xiàng)目的CORS跨域請(qǐng)求

    vue+springboot實(shí)現(xiàn)項(xiàng)目的CORS跨域請(qǐng)求

    這篇文章主要介紹了vue+springboot實(shí)現(xiàn)項(xiàng)目的CORS跨域請(qǐng)求,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • vue?mounted周期中document.querySelectorAll()獲取不到元素的解決

    vue?mounted周期中document.querySelectorAll()獲取不到元素的解決

    這篇文章主要介紹了vue?mounted周期中document.querySelectorAll()獲取不到元素的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • idea部署RuoYi-Vue分離版的圖文詳解

    idea部署RuoYi-Vue分離版的圖文詳解

    RuoYi-Vue是一款基于SpringBoot+Vue的前后端分離極速后臺(tái)開(kāi)發(fā)框架, 本文主要介紹了idea部署RuoYi-Vue分離版的圖文詳解,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • elementUI表格多選框this.$refs.xxx.toggleRowSelection無(wú)效問(wèn)題

    elementUI表格多選框this.$refs.xxx.toggleRowSelection無(wú)效問(wèn)題

    這篇文章主要介紹了elementUI表格多選框this.$refs.xxx.toggleRowSelection無(wú)效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Vue實(shí)現(xiàn)tab切換的兩種方法示例詳解

    Vue實(shí)現(xiàn)tab切換的兩種方法示例詳解

    這篇文章主要介紹了Vue實(shí)現(xiàn)tab切換的兩種方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-11-11
  • vue elementUI select下拉框設(shè)置默認(rèn)值(賦值)失敗的解決

    vue elementUI select下拉框設(shè)置默認(rèn)值(賦值)失敗的解決

    這篇文章主要介紹了vue elementUI select下拉框設(shè)置默認(rèn)值(賦值)失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 詳解Vue.js 響應(yīng)接口

    詳解Vue.js 響應(yīng)接口

    這篇文章主要介紹了Vue.js 響應(yīng)接口的相關(guān)資料,文中實(shí)例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • VUE 3D輪播圖封裝實(shí)現(xiàn)方法

    VUE 3D輪播圖封裝實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了VUE 3D輪播圖封裝實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • vue動(dòng)態(tài)設(shè)置路由權(quán)限的主要思路

    vue動(dòng)態(tài)設(shè)置路由權(quán)限的主要思路

    這篇文章主要給大家介紹了關(guān)于vue動(dòng)態(tài)設(shè)置路由權(quán)限的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 詳解如何使用Vuex實(shí)現(xiàn)Vue后臺(tái)管理中的角色鑒權(quán)

    詳解如何使用Vuex實(shí)現(xiàn)Vue后臺(tái)管理中的角色鑒權(quán)

    最近參與了公司一個(gè)新的B端項(xiàng)目的研發(fā),從無(wú)到有搭建項(xiàng)目的過(guò)程中,遇到了關(guān)于項(xiàng)目鑒權(quán)的問(wèn)題,這篇文章主要給大家介紹了關(guān)于如何使用Vuex實(shí)現(xiàn)Vue后臺(tái)管理中的角色鑒權(quán)的相關(guān)資料,需要的朋友可以參考下
    2022-05-05

最新評(píng)論