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

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

掉了兩根頭發(fā)后,我悟了!Vue3的Scoped原來是這樣避免樣式污染

來源: 責編: 時間:2024-06-27 17:19:34 249觀看
導(dǎo)讀前言眾所周知,在vue中使用scoped可以避免父組件的樣式滲透到子組件中。使用了scoped后會給html增加自定義屬性data-v-x,同時會給組件內(nèi)CSS選擇器添加對應(yīng)的屬性選擇器[data-v-x]。這篇我們來講講vue是如何給CSS選擇器添

前言

眾所周知,在vue中使用scoped可以避免父組件的樣式滲透到子組件中。使用了scoped后會給html增加自定義屬性data-v-x,同時會給組件內(nèi)CSS選擇器添加對應(yīng)的屬性選擇器[data-v-x]。這篇我們來講講vue是如何給CSS選擇器添加對應(yīng)的屬性選擇器[data-v-x]。注:本文中使用的vue版本為3.4.19,@vitejs/plugin-vue的版本為5.0.4。iMq28資訊網(wǎng)——每日最新資訊28at.com

看個demo

我們先來看個demo,代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

<template>  <div class="block">hello world</div></template><style scoped>.block {  color: red;}</style>

經(jīng)過編譯后,上面的demo代碼就會變成下面這樣:iMq28資訊網(wǎng)——每日最新資訊28at.com

<template>  <div data-v-c1c19b25 class="block">hello world</div></template><style>.block[data-v-c1c19b25] {  color: red;}</style>

從上面的代碼可以看到在div上多了一個data-v-c1c19b25自定義屬性,并且css的屬性選擇器上面也多了一個[data-v-c1c19b25]。iMq28資訊網(wǎng)——每日最新資訊28at.com

可能有的小伙伴有疑問,為什么生成這樣的代碼就可以避免樣式污染呢?iMq28資訊網(wǎng)——每日最新資訊28at.com

.block[data-v-c1c19b25]:這里面包含兩個選擇器。.block是一個類選擇器,表示class的值包含block。[data-v-c1c19b25]是一個屬性選擇器,表示存在data-v-c1c19b25自定義屬性的元素。iMq28資訊網(wǎng)——每日最新資訊28at.com

所以只有class包含block,并且存在data-v-c1c19b25自定義屬性的元素才能命中這個樣式,這樣就能避免樣式污染。iMq28資訊網(wǎng)——每日最新資訊28at.com

并且由于在同一個組件里面生成的data-v-x值是一樣的,所以在同一組件內(nèi)多個html元素只要class的值包含block,就可以命中color: red的樣式。iMq28資訊網(wǎng)——每日最新資訊28at.com

接下來我將通過debug的方式帶你了解,vue是如何在css中生成.block[data-v-c1c19b25]這樣的屬性選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

@vitejs/plugin-vue

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

圖片圖片iMq28資訊網(wǎng)——每日最新資訊28at.com

假如vue文件編譯為js文件是一個毛線團,那么他的線頭一定是vite.config.ts文件中使用@vitejs/plugin-vue的地方。通過這個線頭開始debug我們就能夠梳理清楚完整的工作流程。iMq28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片iMq28資訊網(wǎng)——每日最新資訊28at.com

vuePlugin函數(shù)

我們給上方圖片的vue函數(shù)打了一個斷點,然后在debug終端上面執(zhí)行yarn dev,我們看到斷點已經(jīng)停留在了vue函數(shù)這里。然后點擊step into,斷點走到了@vitejs/plugin-vue庫中的一個vuePlugin函數(shù)中。我們看到簡化后的vuePlugin函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function vuePlugin(rawOptions = {}) {  return {    name: "vite:vue",    // ...省略其他插件鉤子函數(shù)    transform(code, id, opt) {      // ..    }  };}

@vitejs/plugin-vue是作為一個plugins插件在vite中使用,vuePlugin函數(shù)返回的對象中的transform方法就是對應(yīng)的插件鉤子函數(shù)。vite會在對應(yīng)的時候調(diào)用這些插件的鉤子函數(shù),vite每解析一個模塊都會執(zhí)行一次transform鉤子函數(shù)。更多vite鉤子相關(guān)內(nèi)容查看官網(wǎng)。iMq28資訊網(wǎng)——每日最新資訊28at.com

我們這里只需要看transform鉤子函數(shù),解析每個模塊時調(diào)用。iMq28資訊網(wǎng)——每日最新資訊28at.com

由于解析每個文件都會走到transform鉤子函數(shù)中,但是我們只關(guān)注index.vue文件是如何解析的,所以我們給transform鉤子函數(shù)打一個條件斷點。如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片iMq28資訊網(wǎng)——每日最新資訊28at.com

然后點擊Continue(F5),vite服務(wù)啟動后就會走到transform鉤子函數(shù)中打的斷點。我們可以看到簡化后的transform鉤子函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function transform(code, id, opt) {  const { filename, query } = parseVueRequest(id);  if (!query.vue) {    return transformMain(      code,      filename,      options.value,      this,      ssr,      customElementFilter.value(filename)    );  } else {    const descriptor = getDescriptor(filename);    if (query.type === "style") {      return transformStyle(        code,        descriptor,        Number(query.index || 0),        options.value      );    }  }}

首先調(diào)用parseVueRequest函數(shù)解析出當前要處理的文件的filename和query,在debug終端來看看此時這兩個的值。如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片iMq28資訊網(wǎng)——每日最新資訊28at.com

從上圖中可以看到filename為當前處理的vue文件路徑,query的值為空數(shù)組。所以此時代碼會走到transformMain函數(shù)中。iMq28資訊網(wǎng)——每日最新資訊28at.com

transformMain函數(shù)

將斷點走進transformMain函數(shù),在我們這個場景中簡化后的transformMain函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

async function transformMain(code, filename, options) {  const { descriptor } = createDescriptor(filename, code, options);  const { code: templateCode } = await genTemplateCode(    descriptor    // ...省略  );  const { code: scriptCode } = await genScriptCode(    descriptor    // ...省略  );  const stylesCode = await genStyleCode(    descriptor    // ...省略  );  const output = [scriptCode, templateCode, stylesCode];  let resolvedCode = output.join("/n");  return {    code: resolvedCode,  };}

我們在 通過debug搞清楚.vue文件怎么變成.js文件文章中已經(jīng)深入講解過transformMain函數(shù)了,所以這篇文章我們不會深入到transformMain函數(shù)中使用到的每個函數(shù)中。iMq28資訊網(wǎng)——每日最新資訊28at.com

首先調(diào)用createDescriptor函數(shù)根據(jù)當前vue文件的code代碼字符串生成一個descriptor對象,簡化后的createDescriptor函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

const cache = new Map();function createDescriptor(  filename,  source,  { root, isProduction, sourceMap, compiler, template }) {  const { descriptor, errors } = compiler.parse(source, {    filename,    sourceMap,    templateParseOptions: template?.compilerOptions,  });  const normalizedPath = slash(path.normalize(path.relative(root, filename)));  descriptor.id = getHash(normalizedPath + (isProduction ? source : ""));  cache.set(filename, descriptor);  return { descriptor, errors };}

首先調(diào)用compiler.parse方法根據(jù)當前vue文件的code代碼字符串生成一個descriptor對象,此時的descriptor對象主要有三個屬性template、scriptSetup、style,分別對應(yīng)的是vue文件中的<template>模塊、<template setup>模塊、<style>模塊。iMq28資訊網(wǎng)——每日最新資訊28at.com

然后調(diào)用getHash函數(shù)給descriptor對象生成一個id屬性,getHash函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

import { createHash } from "node:crypto";function getHash(text) {  return createHash("sha256").update(text).digest("hex").substring(0, 8);}

從上面的代碼可以看出id是根據(jù)vue文件的路徑調(diào)用node的createHash加密函數(shù)生成的,這里生成的id就是scoped生成的自定義屬性data-v-x中的x部分。iMq28資訊網(wǎng)——每日最新資訊28at.com

然后在createDescriptor函數(shù)中將生成的descriptor對象緩存起來,關(guān)于descriptor對象的處理就這么多了。iMq28資訊網(wǎng)——每日最新資訊28at.com

接著在transformMain函數(shù)中會分別以descriptor對象為參數(shù)執(zhí)行g(shù)enTemplateCode、genScriptCode、genStyleCode函數(shù),分別得到編譯后的render函數(shù)、編譯后的js代碼、編譯后的style代碼。iMq28資訊網(wǎng)——每日最新資訊28at.com

編譯后的render函數(shù)如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

從上圖中可以看到template模塊已經(jīng)編譯成了render函數(shù)iMq28資訊網(wǎng)——每日最新資訊28at.com

編譯后的js代碼如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

從上圖中可以看到script模塊已經(jīng)編譯成了一個名為_sfc_main的對象,因為我們這個demo中script模塊沒有代碼,所以這個對象是一個空對象。iMq28資訊網(wǎng)——每日最新資訊28at.com

編譯后的style代碼如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

從上圖中可以看到style模塊已經(jīng)編譯成了一個import語句。iMq28資訊網(wǎng)——每日最新資訊28at.com

最后就是使用換行符/n將templateCode、scriptCode、stylesCode拼接起來就是vue文件編譯后的js文件啦,如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

想必細心的同學已經(jīng)發(fā)現(xiàn)有地方不對啦,這里的style模塊編譯后是一條import語句,并不是真正的css代碼。這條import語句依然還是import導(dǎo)入的index.vue文件,只是加了一些額外的query參數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

?vue&type=style&index=0&lang.css:這個query參數(shù)表明當前import導(dǎo)入的是vue文件的css部分。iMq28資訊網(wǎng)——每日最新資訊28at.com

還記得我們前面講過的transform鉤子函數(shù)嗎?vite每解析一個模塊都會執(zhí)行一次transform鉤子函數(shù),這個import導(dǎo)入vue文件的css部分,當然也會觸發(fā)transform鉤子函數(shù)的執(zhí)行。iMq28資訊網(wǎng)——每日最新資訊28at.com

第二次執(zhí)行transform鉤子函數(shù)

當在瀏覽器中執(zhí)行vue文件編譯后的js文件時會觸發(fā)import "/Users/xxx/index.vue?vue&type=style&index=0&lang.css"語句的執(zhí)行,導(dǎo)致再次執(zhí)行transform鉤子函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

transform鉤子函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function transform(code, id, opt) {  const { filename, query } = parseVueRequest(id);  if (!query.vue) {    return transformMain(      code,      filename,      options.value,      this,      ssr,      customElementFilter.value(filename)    );  } else {    const descriptor = getDescriptor(filename);    if (query.type === "style") {      return transformStyle(        code,        descriptor,        Number(query.index || 0),        options.value      );    }  }}

由于此時的query中是有vue字段,所以!query.vue的值為false,這次代碼就不會走進transformMain函數(shù)中了。在else代碼在先執(zhí)行g(shù)etDescriptor函數(shù)拿到descriptor對象,getDescriptor函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function getDescriptor(filename) {  const _cache = cache;  if (_cache.has(filename)) {    return _cache.get(filename);  }}

我們在第一次執(zhí)行transformMain函數(shù)的時候會去執(zhí)行createDescriptor函數(shù),他的作用是根據(jù)當前vue文件的code代碼字符串生成一個descriptor對象,并且將這個descriptor對象緩存起來了。在getDescriptor函數(shù)中就是將緩存的descriptor對象取出來。iMq28資訊網(wǎng)——每日最新資訊28at.com

由于query中有type=style,所以代碼會走到transformStyle函數(shù)中。iMq28資訊網(wǎng)——每日最新資訊28at.com

transformStyle函數(shù)

接著將斷點走進transformStyle函數(shù),代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

async function transformStyle(code, descriptor, index, options) {  const block = descriptor.styles[index];  const result = await options.compiler.compileStyleAsync({    ...options.style,    filename: descriptor.filename,    id: `data-v-${descriptor.id}`,    source: code,    scoped: block.scoped,  });  return {    code: result.code,  };}

從上面的代碼可以看到transformStyle函數(shù)依然不是干活的地方,而是調(diào)用的@vue/compiler-sfc包暴露出的compileStyleAsync函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

在調(diào)用compileStyleAsync函數(shù)的時候有三個參數(shù)需要注意:source、id和scoped。iMq28資訊網(wǎng)——每日最新資訊28at.com

source字段的值為code,值是當前css代碼字符串。iMq28資訊網(wǎng)——每日最新資訊28at.com

id字段的值為data-v-${descriptor.id},是不是覺得看著很熟悉?沒錯他就是使用scoped后vue幫我們自動生成的html自定義屬性data-v-x和css選擇屬性選擇器[data-v-x]。iMq28資訊網(wǎng)——每日最新資訊28at.com

其中的descriptor.id就是在生成descriptor對象時根據(jù)vue文件路徑加密生成的id。iMq28資訊網(wǎng)——每日最新資訊28at.com

scoped字段的值為block.scoped,而block的值為descriptor.styles[index]。由于一個vue文件可以寫多個style標簽,所以descriptor對象的styles屬性是一個數(shù)組,分包對應(yīng)多個style標簽。我們這里只有一個style標簽,所以此時的index值為0。block.scoped的值為style標簽上面是否有使用scoped。iMq28資訊網(wǎng)——每日最新資訊28at.com

直到進入compileStyleAsync函數(shù)之前代碼其實一直都還在@vitejs/plugin-vue包中執(zhí)行,真正干活的地方是在@vue/compiler-sfc包中。iMq28資訊網(wǎng)——每日最新資訊28at.com

@vue/compiler-sfc

接著將斷點走進compileStyleAsync函數(shù),代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function compileStyleAsync(options) {  return doCompileStyle({    ...options,    isAsync: true,  });}

從上面的代碼可以看到實際干活的是doCompileStyle函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

doCompileStyle函數(shù)

接著將斷點走進doCompileStyle函數(shù),在我們這個場景中簡化后的doCompileStyle函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

import postcss from "postcss";function doCompileStyle(options) {  const {    filename,    id,    scoped = false,    postcssOptions,    postcssPlugins,  } = options;  const source = options.source;  const shortId = id.replace(/^data-v-/, "");  const longId = `data-v-${shortId}`;  const plugins = (postcssPlugins || []).slice();  if (scoped) {    plugins.push(scopedPlugin(longId));  }  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);  }}

在doCompileStyle函數(shù)中首先使用const定義了一堆變量,我們主要關(guān)注source和longId。iMq28資訊網(wǎng)——每日最新資訊28at.com

其中的source為當前css代碼字符串,longId為根據(jù)vue文件路徑加密生成的id,值的格式為data-v-x。他就是使用scoped后vue幫我們自動生成的html自定義屬性data-v-x和css選擇屬性選擇器[data-v-x]。iMq28資訊網(wǎng)——每日最新資訊28at.com

接著就是判斷scoped是否為true,也就是style中使用有使用scoped。如果為true,就將scopedPlugin插件push到plugins數(shù)組中。從名字你應(yīng)該猜到了這個plugin插件就是用于處理css scoped的。iMq28資訊網(wǎng)——每日最新資訊28at.com

最后就是執(zhí)行result = postcss(plugins).process(source, postCSSOptions)拿到經(jīng)過postcss轉(zhuǎn)換編譯器處理后的css。iMq28資訊網(wǎng)——每日最新資訊28at.com

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

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

在我們這里主要就是用到了postcss提供的插件機制來完成css scoped的自定義轉(zhuǎn)換,調(diào)用postcss的時候我們傳入了source,他的值是style模塊中的css代碼。并且傳入的plugins插件數(shù)組中有個scopedPlugin插件,這個自定義插件就是vue寫的用于處理css scoped的插件。iMq28資訊網(wǎng)——每日最新資訊28at.com

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

從上圖可以看到此時的css代碼還是和我們源代碼是一樣的,并沒有css選擇屬性選擇器[data-v-x]iMq28資訊網(wǎng)——每日最新資訊28at.com

scopedPlugin插件

scopedPlugin插件在我們這個場景中簡化后的代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

const scopedPlugin = (id = "") => {  return {    postcssPlugin: "vue-sfc-scoped",    Rule(rule) {      processRule(id, rule);    },    // ...省略  };};

這里的id就是我們在doCompileStyle函數(shù)中傳過來的longId,也就是生成的css選擇屬性選擇器[data-v-x]中的data-v-x。iMq28資訊網(wǎng)——每日最新資訊28at.com

在我們這個場景中只需要關(guān)注Rule鉤子函數(shù),當postcss處理到選擇器開頭的規(guī)則就會走到Rule鉤子函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

我們這里需要在使用了scoped后給css選擇器添加對應(yīng)的屬性選擇器[data-v-x],所以我們需要在插件中使用Rule鉤子函數(shù),在處理css選擇器時手動給選擇器后面塞一個屬性選擇器[data-v-x]。iMq28資訊網(wǎng)——每日最新資訊28at.com

給Rule鉤子函數(shù)打個斷點,當postcss處理到我們代碼中的.block時就會走到斷點中。在debug終端看看rule的值,如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

從上圖中可以看到此時rule.selector的值為.block,是一個class值為block的類選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

processRule函數(shù)

將斷點走進processRule函數(shù)中,在我們這個場景中簡化后的processRule函數(shù)代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

import selectorParser from "postcss-selector-parser";function processRule(id: string, rule: Rule) {  rule.selector = selectorParser((selectorRoot) => {    selectorRoot.each((selector) => {      rewriteSelector(id, selector, selectorRoot);    });  }).processSync(rule.selector);}

前面我們講過rule.selector的值為.block,通過重寫rule.selector的值可以將當前css選擇器替換為一個新的選擇器。在processRule函數(shù)中就是使用postcss-selector-parser來解析一個選擇器,進行處理后返回一個新的選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

processSync方法的作用為接收一個選擇器,然后在回調(diào)中對解析出來的選擇器進行處理,最后將處理后的選擇器以字符串的方式進行返回。iMq28資訊網(wǎng)——每日最新資訊28at.com

在我們這里processSync方法接收的選擇器是字符串.block,經(jīng)過回調(diào)函數(shù)處理后返回的選擇器字符串就變成了.block[data-v-c1c19b25]。iMq28資訊網(wǎng)——每日最新資訊28at.com

我們接下來看selectorParser回調(diào)函數(shù)中的代碼,在回調(diào)函數(shù)中會使用selectorRoot.each去遍歷解析出來的選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

為什么這里需要去遍歷呢?iMq28資訊網(wǎng)——每日最新資訊28at.com

答案是css選擇器可以這樣寫:.block.demo,如果是這樣的選擇器經(jīng)過解析后,就會被解析成兩個選擇器,分別是.block和.demo。iMq28資訊網(wǎng)——每日最新資訊28at.com

在each遍歷中會調(diào)用rewriteSelector函數(shù)對當前選取器進行重寫。iMq28資訊網(wǎng)——每日最新資訊28at.com

rewriteSelector函數(shù)

將斷點走進rewriteSelector函數(shù),在我們這個場景中簡化后的代碼如下:iMq28資訊網(wǎng)——每日最新資訊28at.com

function rewriteSelector(id, selector) {  let node;  const idToAdd = id;  selector.each((n) => {    node = n;  });  selector.insertAfter(    node,    selectorParser.attribute({      attribute: idToAdd,      value: idToAdd,      raws: {},      quoteMark: `"`,    })  );}

在rewriteSelector函數(shù)中each遍歷當前selector選擇器,給node賦值。將斷點走到each遍歷之后,我們在debug終端來看看selector選擇器和node變量。如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

在這里selector是container容器,node才是具體要操作的選擇器節(jié)點。iMq28資訊網(wǎng)——每日最新資訊28at.com

比如我們這里要執(zhí)行的selector.insertAfter方法就是在selector容器中在一個指定節(jié)點后面去插入一個新的節(jié)點。這個和操作瀏覽器DOM API很相似。iMq28資訊網(wǎng)——每日最新資訊28at.com

我們再來看看要插入的節(jié)點,selectorParser.attribute函數(shù)的作用是創(chuàng)建一個attribute屬性選擇器。在我們這里就是創(chuàng)建一個[data-v-x]的屬性選擇器,如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

所以這里就是在.block類選擇器后面插入一個[data-v-c1c19b25]的屬性選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

我們在debug終端來看看執(zhí)行insertAfter函數(shù)后的selector選擇器,如下圖:iMq28資訊網(wǎng)——每日最新資訊28at.com

將斷點逐層走出,直到processRule函數(shù)中。我們在debug終端來看看此時被重寫后的rule.selector字符串的值是什么樣的,如下圖iMq28資訊網(wǎng)——每日最新資訊28at.com

原來rule.selector的值為.block,通過重寫rule.selector的值可以將.block類選擇器替換為一個新的選擇器,而這個新的選擇器是在原來的.block類選擇器后面再塞一個[data-v-c1c19b25]屬性選擇器。iMq28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

這篇文章我們講了當使用scoped后,vue是如何給組件內(nèi)CSS選擇器添加對應(yīng)的屬性選擇器[data-v-x]。主要分為兩部分,分別在兩個包里面執(zhí)行。iMq28資訊網(wǎng)——每日最新資訊28at.com

  • 第一部分為在@vitejs/plugin-vue包內(nèi)執(zhí)行。

首先會根據(jù)當前vue文件的路徑進行加密算法生成一個id,這個id就是添加的屬性選擇器[data-v-x]中的x。iMq28資訊網(wǎng)——每日最新資訊28at.com

然后就是執(zhí)行transformStyle函數(shù),這個transformStyle并不是實際干活的地方,他調(diào)用了@vue/compiler-sfc包的compileStyleAsync函數(shù)。并且傳入了id、code(css代碼字符串)、scoped(是否在style中使用scoped)。iMq28資訊網(wǎng)——每日最新資訊28at.com

  • 第二部分在@vue/compiler-sfc包執(zhí)行。
  • iMq28資訊網(wǎng)——每日最新資訊28at.com

    compileStyleAsync函數(shù)依然不是實際干活的地方,而是調(diào)用了doCompileStyle函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

    iMq28資訊網(wǎng)——每日最新資訊28at.com

  • iMq28資訊網(wǎng)——每日最新資訊28at.com

    在doCompileStyle函數(shù)中,如果scoped為true就向plugins數(shù)組中插入一個scopedPlugin插件,這個是vue寫的postcss插件,用于處理css scoped。然后使用postcss轉(zhuǎn)換編譯器對css代碼進行轉(zhuǎn)換。iMq28資訊網(wǎng)——每日最新資訊28at.com

    iMq28資訊網(wǎng)——每日最新資訊28at.com

  • iMq28資訊網(wǎng)——每日最新資訊28at.com

    當postcss處理到選擇器開頭的規(guī)則就會走到scopedPlugin插件中的Rule鉤子函數(shù)中。在Rule鉤子函數(shù)中會執(zhí)行processRule函數(shù)。iMq28資訊網(wǎng)——每日最新資訊28at.com

    iMq28資訊網(wǎng)——每日最新資訊28at.com

  • iMq28資訊網(wǎng)——每日最新資訊28at.com

    在processRule函數(shù)中會使用postcss-selector-parser包將當前選擇器替換為一個新的選擇器,新的選擇器和原來的選擇器的區(qū)別是在后面會添加一個屬性選擇器[data-v-x]。其中的x就是根據(jù)當前vue文件的路徑進行加密算法生成的id。iMq28資訊網(wǎng)——每日最新資訊28at.com

    iMq28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-96990-0.html掉了兩根頭發(fā)后,我悟了!Vue3的Scoped原來是這樣避免樣式污染

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

上一篇: vivo 互聯(lián)網(wǎng)自研代碼評審 VCR 落地實踐

下一篇: Vue props的類型如果為對象或者數(shù)組,為什么默認值一定得是個函數(shù)

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
一区二区三区波多野结衣在线观看| 国产精品网站在线观看| 久久综合99re88久久爱| 欧美成人精品一区二区三区| 欧美乱大交xxxxx| 国产精品乱码一区二区三区| 国产一区二区激情| 亚洲第一区在线| 91久久精品国产91久久性色tv| 日韩一区二区免费高清| 午夜日韩视频| 欧美成人按摩| 国产精品理论片在线观看| 韩国成人精品a∨在线观看| 亚洲精品乱码久久久久久日本蜜臀 | 国产精品一区二区在线观看网站| 国内精品久久久久久久影视蜜臀 | 欧美极品在线播放| 国产精品亚洲综合| 亚洲黄色一区| 午夜精品久久久久久久99黑人| 久久亚洲一区二区三区四区| 欧美午夜不卡影院在线观看完整版免费 | 欧美少妇一区| 伊人久久男人天堂| 亚洲一区二区三区激情| 美女脱光内衣内裤视频久久网站| 欧美午夜大胆人体| 在线观看日韩www视频免费| 一区二区三区欧美在线| 久久天堂av综合合色| 欧美视频你懂的| 亚洲高清资源| 欧美淫片网站| 欧美三级在线视频| 亚洲国产裸拍裸体视频在线观看乱了中文| 亚洲一区二区不卡免费| 免费欧美电影| 国产一区二区三区免费不卡| 99综合在线| 久久野战av| 国产农村妇女精品一二区| 亚洲精品欧美在线| 久久深夜福利| 国产性色一区二区| 亚洲一区二区三区免费视频| 欧美激情一区二区三区成人| 黄色精品免费| 欧美一区二区三区在线观看视频| 欧美日韩一区二区在线观看| 91久久国产综合久久| 久久久久综合一区二区三区| 国产伦精品一区二区三| 亚洲视频在线观看网站| 欧美激情第1页| 在线激情影院一区| 久久精品中文字幕一区| 国产乱码精品1区2区3区| 亚洲小说欧美另类婷婷| 欧美日韩国产大片| 亚洲精品一区二区网址| 老司机亚洲精品| 国内欧美视频一区二区| 性色av香蕉一区二区| 国产精品你懂的在线| 亚洲一区二区免费在线| 欧美日韩一区在线播放| av成人动漫| 欧美日韩视频在线第一区| 亚洲精品乱码久久久久久久久| 免费在线观看成人av| 在线欧美三区| 免播放器亚洲一区| 亚洲国产精品久久| 男女视频一区二区| 亚洲国产一区二区三区a毛片| 老司机精品福利视频| 影音先锋亚洲精品| 麻豆精品在线播放| 亚洲国产精品一区| 欧美激情 亚洲a∨综合| 亚洲精品女av网站| 欧美日本中文字幕| 一区二区三区毛片| 国产精品久久久久国产a级| 亚洲一区二区三区色| 国产精品欧美一区喷水| 亚洲欧美国产高清va在线播| 国产精品系列在线播放| 欧美一站二站| 尤物九九久久国产精品的特点| 久久视频一区二区| 亚洲国产激情| 欧美另类在线观看| 亚洲小说欧美另类社区| 国产日韩欧美在线播放| 久久久www成人免费毛片麻豆| 伊人色综合久久天天| 欧美福利在线观看| 99在线视频精品| 国产精品青草久久久久福利99| 欧美一级二区| 精品福利免费观看| 欧美国产视频在线| 亚洲一级一区| 国产一区二区三区高清播放| 另类天堂视频在线观看| 亚洲乱码精品一二三四区日韩在线| 欧美日韩极品在线观看一区| 亚洲一区区二区| 国产一区二区视频在线观看 | 国产欧美日韩综合| 久久免费少妇高潮久久精品99| 亚洲国产老妈| 欧美日韩在线观看视频| 午夜国产精品影院在线观看| 韩日精品视频一区| 欧美人与禽猛交乱配| 午夜精品一区二区三区在线 | 久久精品国产免费观看| 亚洲电影免费| 欧美午夜激情在线| 久久精品99久久香蕉国产色戒| 在线看片成人| 欧美特黄一级大片| 久久久水蜜桃| 一区二区日韩精品| 国产综合激情| 欧美日韩三级在线| 久久精品亚洲精品| 99综合电影在线视频| 韩日视频一区| 欧美午夜视频| 老牛影视一区二区三区| 亚洲自拍另类| 亚洲国产高清aⅴ视频| 国产精品萝li| 欧美第十八页| 欧美一级在线视频| 日韩网站在线观看| 国模吧视频一区| 欧美三级在线播放| 看片网站欧美日韩| 亚洲欧美另类久久久精品2019| 亚洲国产精品久久久久久女王| 国产精品久久久久久影视| 欧美r片在线| 欧美伊人影院| 中文亚洲欧美| 亚洲黄色在线视频| 国产亚洲va综合人人澡精品| 欧美日韩国产一级| 久久亚洲综合| 欧美一级视频| 一本高清dvd不卡在线观看| 国内精品久久久久久久97牛牛| 欧美日韩中文字幕综合视频 | 黄色精品一区| 国产精品亚洲第一区在线暖暖韩国| 欧美成人中文字幕| 久久国产婷婷国产香蕉| 在线亚洲观看| 亚洲人成网站在线观看播放| 国产综合欧美在线看| 国产精品国产精品| 欧美日韩国产色综合一二三四| 美国三级日本三级久久99| 性色av一区二区怡红| 一区二区欧美日韩| 亚洲欧洲日产国产综合网| 韩国av一区二区三区四区| 国产精品热久久久久夜色精品三区| 欧美另类极品videosbest最新版本 | 一区二区免费在线播放| 在线色欧美三级视频| 国产自产在线视频一区 | 亚洲一二三区精品| 亚洲精一区二区三区| 亚洲电影在线免费观看| 国产一区亚洲| 国产日产欧美精品| 国产精品试看| 国产精品久久久久91| 欧美日韩久久久久久| 欧美精品免费视频| 欧美成人免费视频| 蘑菇福利视频一区播放| 久久一区二区精品| 久久久人成影片一区二区三区观看 | 亚洲丁香婷深爱综合| 狠狠色伊人亚洲综合网站色| 国产午夜精品美女视频明星a级| 国产精品免费一区二区三区观看| 欧美色图天堂网| 欧美日韩国内| 欧美日韩小视频| 欧美日韩影院| 欧美视频久久| 国产精品大全| 国产精品伦子伦免费视频| 国产精品国内视频| 国产精品嫩草影院一区二区| 国产精品视频最多的网站| 国产精品一卡二卡|