最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3如何避免樣式污染的方法示例

 更新時(shí)間:2024年09月02日 08:38:07   作者:諸葛亮的芭蕉扇  
本文主要介紹了vue3如何避免樣式污染的方法示例,使用scoped可以避免父組件的樣式滲透到子組件中,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

眾所周知,在vue中使用scoped可以避免父組件的樣式滲透到子組件中。使用了scoped后會(huì)給html增加自定義屬性data-v-x,同時(shí)會(huì)給組件內(nèi)CSS選擇器添加對(duì)應(yīng)的屬性選擇器[data-v-x]。本文講一下vue是如何給CSS選擇器添加對(duì)應(yīng)的屬性選擇器[data-v-x]。注:本文中使用的vue版本為3.4.19,@vitejs/plugin-vue的版本為5.0.4。

先看個(gè)demo

代碼如下:

<template>
  <div class="block">hello world</div>
</template>

<style scoped>
.block {
  color: red;
}
</style>

經(jīng)過編譯后,上面的demo代碼就會(huì)變成下面這樣:

<template>
  <div data-v-c1c19b25 class="block">hello world</div>
</template>

<style>
.block[data-v-c1c19b25] {
  color: red;
}
</style>

從上面的代碼可以看到在div上多了一個(gè)data-v-c1c19b25自定義屬性,并且css的屬性選擇器上面也多了一個(gè)[data-v-c1c19b25]。

那有人就會(huì)好奇,為什么生成這樣的代碼就可以避免樣式污染呢?

.block[data-v-c1c19b25]:這里面包含兩個(gè)選擇器。.block是一個(gè)類選擇器,表示class的值包含block。[data-v-c1c19b25]是一個(gè)屬性選擇器,表示存在data-v-c1c19b25自定義屬性的元素。

所以只有class包含block,并且存在data-v-c1c19b25自定義屬性的元素才能命中這個(gè)樣式,這樣就能避免樣式污染。并且由于在同一個(gè)組件里面生成的data-v-x值是一樣的,所以在同一組件內(nèi)多個(gè)html元素只要class的值包含block,就可以命中color: red的樣式。

接下來我將通過debug的方式帶你了解,vue是如何在css中生成.block[data-v-c1c19b25]這樣的屬性選擇器。

@vitejs/plugin-vue

還是一樣的套路啟動(dòng)一個(gè)debug終端。這里以vscode舉例,打開終端然后點(diǎn)擊終端中的+號(hào)旁邊的下拉箭頭,下拉中點(diǎn)擊Javascript Debug Terminal就可以啟動(dòng)一個(gè)debug終端。

在這里插入圖片描述

假如vue文件編譯為js文件是一個(gè)毛線團(tuán),那么他的線頭一定是vite.config.ts文件中使用@vitejs/plugin-vue的地方。通過這個(gè)線頭開始debug我們就能夠梳理清楚完整的工作流程。

在這里插入圖片描述

vuePlugin函數(shù)

我們給上方圖片的vue函數(shù)打了一個(gè)斷點(diǎn),然后在debug終端上面執(zhí)行yarn dev,我們看到斷點(diǎn)已經(jīng)停留在了vue函數(shù)這里。然后點(diǎn)擊step into,斷點(diǎn)走到了@vitejs/plugin-vue庫中的一個(gè)vuePlugin函數(shù)中。我們看到簡(jiǎn)化后的vuePlugin函數(shù)代碼如下:

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

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

我們這里只需要看transform鉤子函數(shù),解析每個(gè)模塊時(shí)調(diào)用。

由于解析每個(gè)文件都會(huì)走到transform鉤子函數(shù)中,但是我們只關(guān)注index.vue文件是如何解析的,所以我們給transform鉤子函數(shù)打一個(gè)條件斷點(diǎn)。如下圖:

在這里插入圖片描述

然后點(diǎn)擊Continue(F5),vite服務(wù)啟動(dòng)后就會(huì)走到transform鉤子函數(shù)中打的斷點(diǎn)。我們可以看到簡(jiǎn)化后的transform鉤子函數(shù)代碼如下:

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ù)解析出當(dāng)前要處理的文件的filenamequery,在debug終端來看看此時(shí)這兩個(gè)的值。如下圖:

在這里插入圖片描述

從上圖中可以看到filename為當(dāng)前處理的vue文件路徑,query的值為空數(shù)組。所以此時(shí)代碼會(huì)走到transformMain函數(shù)中。

transformMain函數(shù)

將斷點(diǎn)走進(jìn)transformMain函數(shù),在我們這個(gè)場(chǎng)景中簡(jiǎn)化后的transformMain函數(shù)代碼如下:

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,
  };
}

首先調(diào)用createDescriptor函數(shù)根據(jù)當(dāng)前vue文件的code代碼字符串生成一個(gè)descriptor對(duì)象,簡(jiǎn)化后的createDescriptor函數(shù)代碼如下:

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ù)當(dāng)前vue文件的code代碼字符串生成一個(gè)descriptor對(duì)象,此時(shí)的descriptor對(duì)象主要有三個(gè)屬性template、scriptSetupstyle,分別對(duì)應(yīng)的是vue文件中的 <template>模塊、<template setup>模塊、 <style> 模塊。

然后調(diào)用getHash函數(shù)給descriptor對(duì)象生成一個(gè)id屬性,getHash函數(shù)代碼如下:

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部分。

然后在createDescriptor函數(shù)中將生成的descriptor對(duì)象緩存起來,關(guān)于descriptor對(duì)象的處理就這么多了。

接著在transformMain函數(shù)中會(huì)分別以descriptor對(duì)象為參數(shù)執(zhí)行genTemplateCode、genScriptCodegenStyleCode函數(shù),分別得到編譯后的render函數(shù)、編譯后的js代碼、編譯后的style代碼。

編譯后的render函數(shù)如下圖:

在這里插入圖片描述

從上圖中可以看到template模塊已經(jīng)編譯成了render函數(shù)

編譯后的js代碼如下圖:

在這里插入圖片描述

從上圖中可以看到script模塊已經(jīng)編譯成了一個(gè)名為_sfc_main的對(duì)象,因?yàn)槲覀冞@個(gè)demo中script模塊沒有代碼,所以這個(gè)對(duì)象是一個(gè)空對(duì)象。

編譯后的style代碼如下圖:

在這里插入圖片描述

從上圖中可以看到style模塊已經(jīng)編譯成了一個(gè)import語句。

最后就是使用換行符\ntemplateCode、scriptCodestylesCode拼接起來就是vue文件編譯后的js文件啦,如下圖:

在這里插入圖片描述

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

?vue&type=style&index=0&lang.css:這個(gè)query參數(shù)表明當(dāng)前import導(dǎo)入的是vue文件的css部分。

還記得前面講過的transform鉤子函數(shù)嗎?vite每解析一個(gè)模塊都會(huì)執(zhí)行一次transform鉤子函數(shù),這個(gè)import導(dǎo)入vue文件的css部分,當(dāng)然也會(huì)觸發(fā)transform鉤子函數(shù)的執(zhí)行。

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

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

transform鉤子函數(shù)代碼如下:

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
      );
    }
  }
}

由于此時(shí)的query中是有vue字段,所以!query.vue的值為false,這次代碼就不會(huì)走進(jìn)transformMain函數(shù)中了。在else代碼在先執(zhí)行getDescriptor函數(shù)拿到descriptor對(duì)象,getDescriptor函數(shù)代碼如下:

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

我們?cè)诘谝淮螆?zhí)行transformMain函數(shù)的時(shí)候會(huì)去執(zhí)行createDescriptor函數(shù),他的作用是根據(jù)當(dāng)前vue文件的code代碼字符串生成一個(gè)descriptor對(duì)象,并且將這個(gè)descriptor對(duì)象緩存起來了。在getDescriptor函數(shù)中就是將緩存的descriptor對(duì)象取出來。

由于query中有type=style,所以代碼會(huì)走到transformStyle函數(shù)中。

transformStyle函數(shù)

接著將斷點(diǎn)走進(jìn)transformStyle函數(shù),代碼如下:

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ù)。

在調(diào)用compileStyleAsync函數(shù)的時(shí)候有三個(gè)參數(shù)需要注意:sourceidscoped。

source字段的值為code,值是當(dāng)前css代碼字符串。

id字段的值為data-v-${descriptor.id},是不是覺得看著很熟悉?沒錯(cuò)他就是使用scoped后vue幫我們自動(dòng)生成的html自定義屬性data-v-x和css選擇屬性選擇器[data-v-x]

其中的descriptor.id就是在生成descriptor對(duì)象時(shí)根據(jù)vue文件路徑加密生成的id。

scoped字段的值為block.scoped,而block的值為descriptor.styles[index]。由于一個(gè)vue文件可以寫多個(gè)style標(biāo)簽,所以descriptor對(duì)象的styles屬性是一個(gè)數(shù)組,分包對(duì)應(yīng)多個(gè)style標(biāo)簽。我們這里只有一個(gè)style標(biāo)簽,所以此時(shí)的index值為0。block.scoped的值為style標(biāo)簽上面是否有使用scoped

直到進(jìn)入compileStyleAsync函數(shù)之前代碼其實(shí)一直都還在@vitejs/plugin-vue包中執(zhí)行,真正干活的地方是在@vue/compiler-sfc包中。

@vue/compiler-sfc

接著將斷點(diǎn)走進(jìn)compileStyleAsync函數(shù),代碼如下:

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

從上面的代碼可以看到實(shí)際干活的是doCompileStyle函數(shù)。

doCompileStyle函數(shù)

接著將斷點(diǎn)走進(jìn)doCompileStyle函數(shù),在我們這個(gè)場(chǎng)景中簡(jiǎn)化后的doCompileStyle函數(shù)代碼如下:

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)注sourcelongId。

其中的source為當(dāng)前css代碼字符串,longId為根據(jù)vue文件路徑加密生成的id,值的格式為data-v-x。他就是使用scoped后vue幫我們自動(dòng)生成的html自定義屬性data-v-x和css選擇屬性選擇器[data-v-x]。

接著就是判斷scoped是否為true,也就是style中使用有使用scoped。如果為true,就將scopedPlugin插件push到plugins數(shù)組中。從名字你應(yīng)該猜到了這個(gè)plugin插件就是用于處理css scoped的。

最后就是執(zhí)行result = postcss(plugins).process(source, postCSSOptions)拿到經(jīng)過postcss轉(zhuǎn)換編譯器處理后的css。

可能有的小伙伴對(duì)postcss不夠熟悉,我們這里來簡(jiǎn)單介紹一下。

postcss 是 css 的 transpiler(轉(zhuǎn)換編譯器,簡(jiǎn)稱轉(zhuǎn)譯器),它對(duì)于 css 就像 babel 對(duì)于 js 一樣,能夠做 css 代碼的分析和轉(zhuǎn)換。同時(shí),它也提供了插件機(jī)制來做自定義的轉(zhuǎn)換。

在我們這里主要就是用到了postcss提供的插件機(jī)制來完成css scoped的自定義轉(zhuǎn)換,調(diào)用postcss的時(shí)候我們傳入了source,他的值是style模塊中的css代碼。并且傳入的plugins插件數(shù)組中有個(gè)scopedPlugin插件,這個(gè)自定義插件就是vue寫的用于處理css scoped的插件。

在執(zhí)行postcss對(duì)css代碼進(jìn)行轉(zhuǎn)換之前我們?cè)赿ebug終端來看看此時(shí)的css代碼是什么樣的,如下圖:

在這里插入圖片描述

從上圖可以看到此時(shí)的css代碼還是和我們?cè)创a是一樣的,并沒有css選擇屬性選擇器[data-v-x]

scopedPlugin插件

scopedPlugin插件在我們這個(gè)場(chǎng)景中簡(jiǎn)化后的代碼如下:

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

這里的id就是我們?cè)?code>doCompileStyle函數(shù)中傳過來的longId,也就是生成的css選擇屬性選擇器[data-v-x]中的data-v-x。

在我們這個(gè)場(chǎng)景中只需要關(guān)注Rule鉤子函數(shù),當(dāng)postcss處理到選擇器開頭的規(guī)則就會(huì)走到Rule鉤子函數(shù)。

我們這里需要在使用了scoped后給css選擇器添加對(duì)應(yīng)的屬性選擇器[data-v-x],所以我們需要在插件中使用Rule鉤子函數(shù),在處理css選擇器時(shí)手動(dòng)給選擇器后面塞一個(gè)屬性選擇器[data-v-x]

Rule鉤子函數(shù)打個(gè)斷點(diǎn),當(dāng)postcss處理到我們代碼中的.block時(shí)就會(huì)走到斷點(diǎn)中。在debug終端看看rule的值,如下圖:

在這里插入圖片描述

從上圖中可以看到此時(shí)rule.selector的值為.block,是一個(gè)class值為block的類選擇器。

processRule函數(shù)

將斷點(diǎn)走進(jìn)processRule函數(shù)中,在我們這個(gè)場(chǎng)景中簡(jiǎn)化后的processRule函數(shù)代碼如下:

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的值可以將當(dāng)前css選擇器替換為一個(gè)新的選擇器。在processRule函數(shù)中就是使用postcss-selector-parser來解析一個(gè)選擇器,進(jìn)行處理后返回一個(gè)新的選擇器。

processSync方法的作用為接收一個(gè)選擇器,然后在回調(diào)中對(duì)解析出來的選擇器進(jìn)行處理,最后將處理后的選擇器以字符串的方式進(jìn)行返回。

在我們這里processSync方法接收的選擇器是字符串.block,經(jīng)過回調(diào)函數(shù)處理后返回的選擇器字符串就變成了.block[data-v-c1c19b25]。

我們接下來看selectorParser回調(diào)函數(shù)中的代碼,在回調(diào)函數(shù)中會(huì)使用selectorRoot.each去遍歷解析出來的選擇器。

為什么這里需要去遍歷呢?

答案是css選擇器可以這樣寫:.block.demo,如果是這樣的選擇器經(jīng)過解析后,就會(huì)被解析成兩個(gè)選擇器,分別是.block.demo。

在each遍歷中會(huì)調(diào)用rewriteSelector函數(shù)對(duì)當(dāng)前選取器進(jìn)行重寫。

rewriteSelector函數(shù)

將斷點(diǎn)走進(jìn)rewriteSelector函數(shù),在我們這個(gè)場(chǎng)景中簡(jiǎn)化后的代碼如下:

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遍歷當(dāng)前selector選擇器,給node賦值。將斷點(diǎn)走到each遍歷之后,我們?cè)赿ebug終端來看看selector選擇器和node變量。如下圖:

在這里插入圖片描述

在這里selector是container容器,node才是具體要操作的選擇器節(jié)點(diǎn)。

比如我們這里要執(zhí)行的selector.insertAfter方法就是在selector容器中在一個(gè)指定節(jié)點(diǎn)后面去插入一個(gè)新的節(jié)點(diǎn)。這個(gè)和操作瀏覽器DOM API很相似。

我們?cè)賮砜纯匆迦氲墓?jié)點(diǎn),selectorParser.attribute函數(shù)的作用是創(chuàng)建一個(gè)attribute屬性選擇器。在我們這里就是創(chuàng)建一個(gè)[data-v-x]的屬性選擇器,如下圖:

在這里插入圖片描述

所以這里就是在.block類選擇器后面插入一個(gè)[data-v-c1c19b25]的屬性選擇器。

我們?cè)赿ebug終端來看看執(zhí)行insertAfter函數(shù)后的selector選擇器,如下圖:

在這里插入圖片描述

將斷點(diǎn)逐層走出,直到processRule函數(shù)中。我們?cè)赿ebug終端來看看此時(shí)被重寫后的rule.selector字符串的值是什么樣的,如下圖

在這里插入圖片描述

原來rule.selector的值為.block,通過重寫rule.selector的值可以將.block類選擇器替換為一個(gè)新的選擇器,而這個(gè)新的選擇器是在原來的.block類選擇器后面再塞一個(gè)[data-v-c1c19b25]屬性選擇器。

總結(jié)

這篇文章我們講了當(dāng)使用scoped后,vue是如何給組件內(nèi)CSS選擇器添加對(duì)應(yīng)的屬性選擇器[data-v-x]。主要分為兩部分,分別在兩個(gè)包里面執(zhí)行。

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

    • 首先會(huì)根據(jù)當(dāng)前vue文件的路徑進(jìn)行加密算法生成一個(gè)id,這個(gè)id就是添加的屬性選擇器[data-v-x]中的x
    • 然后就是執(zhí)行transformStyle函數(shù),這個(gè)transformStyle并不是實(shí)際干活的地方,他調(diào)用了@vue/compiler-sfc包的compileStyleAsync函數(shù)。并且傳入了id、code(css代碼字符串)、scoped(是否在style中使用scoped)。
  • 第二部分在@vue/compiler-sfc包執(zhí)行。

    • compileStyleAsync函數(shù)依然不是實(shí)際干活的地方,而是調(diào)用了doCompileStyle函數(shù)。
    • doCompileStyle函數(shù)中,如果scoped為true就向plugins數(shù)組中插入一個(gè)scopedPlugin插件,這個(gè)是vue寫的postcss插件,用于處理css scoped。然后使用postcss轉(zhuǎn)換編譯器對(duì)css代碼進(jìn)行轉(zhuǎn)換。
    • 當(dāng)postcss處理到選擇器開頭的規(guī)則就會(huì)走到scopedPlugin插件中的Rule鉤子函數(shù)中。在Rule鉤子函數(shù)中會(huì)執(zhí)行processRule函數(shù)。
      ata-v-x]中的x`。
    • 然后就是執(zhí)行transformStyle函數(shù),這個(gè)transformStyle并不是實(shí)際干活的地方,他調(diào)用了@vue/compiler-sfc包的compileStyleAsync函數(shù)。并且傳入了id、code(css代碼字符串)、scoped(是否在style中使用scoped)。

到此這篇關(guān)于vue3是如何避免樣式污染的的文章就介紹到這了,更多相關(guān)vue3 樣式污染內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • vue3+vite5打包優(yōu)化方式

    vue3+vite5打包優(yōu)化方式

    本文主要介紹了如何使用Vite5進(jìn)行Vue3應(yīng)用的生產(chǎn)環(huán)境打包優(yōu)化,包括配置rollupOptions、minify、build.target、vite-plugin-compression、modulepreload等選項(xiàng),并提供了一個(gè)示例配置
    2025-12-12
  • Vue純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接

    Vue純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接

    這篇文章主要為大家詳細(xì)介紹了Vue如何純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2025-03-03
  • vue 使用iView組件中的Table實(shí)現(xiàn)定時(shí)自動(dòng)滾動(dòng)效果

    vue 使用iView組件中的Table實(shí)現(xiàn)定時(shí)自動(dòng)滾動(dòng)效果

    要在css中設(shè)置table的高度,使數(shù)據(jù)過多時(shí)出現(xiàn)滾動(dòng)條,將縱向設(shè)置為overflow-y: auto;橫向設(shè)置隱藏 overflow-x: hidden,接下來通過本文介紹vue使用iView組件中的Table實(shí)現(xiàn)定時(shí)自動(dòng)滾動(dòng)效果,需要的朋友可以參考下
    2024-05-05
  • 詳解Vue slot插槽

    詳解Vue slot插槽

    這篇文章主要為大家介紹了Vue的slot插槽,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • 基于Vue實(shí)現(xiàn)微信小程序的圖文編輯器

    基于Vue實(shí)現(xiàn)微信小程序的圖文編輯器

    這篇文章主要介紹了基于Vue實(shí)現(xiàn)微信小程序的圖文編輯器,由于微信小程序不能使用常規(guī)的圖文編輯器(比如百度的UEditor )編輯新聞內(nèi)容之類的,所以用vue寫了個(gè)針對(duì)小程序用的圖文編輯器需要的朋友可以參考下
    2018-07-07
  • uni-app中使用ECharts配置四種不同的圖表(示例詳解)

    uni-app中使用ECharts配置四種不同的圖表(示例詳解)

    在uni-app中集成ECharts可以為我們的應(yīng)用提供強(qiáng)大的圖表功能,我們?cè)敿?xì)說一下如何在uni-app中使用ECharts,并配置四種不同的圖表,感興趣的朋友跟隨小編一起看看吧
    2024-01-01
  • Tree-Shaking?機(jī)制快速掌握

    Tree-Shaking?機(jī)制快速掌握

    這篇文章主要為大家介紹了Tree-Shaking?機(jī)制的快速掌握教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • vue與django集成打包的實(shí)現(xiàn)方法

    vue與django集成打包的實(shí)現(xiàn)方法

    這篇文章主要介紹了vue與django集成打包的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 淺談element中InfiniteScroll按需引入的一點(diǎn)注意事項(xiàng)

    淺談element中InfiniteScroll按需引入的一點(diǎn)注意事項(xiàng)

    這篇文章主要介紹了淺談element中InfiniteScroll按需引入的一點(diǎn)注意事項(xiàng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • vue中如何解除數(shù)據(jù)之間的雙向綁定

    vue中如何解除數(shù)據(jù)之間的雙向綁定

    這篇文章主要介紹了vue中如何解除數(shù)據(jù)之間的雙向綁定,具有很好的參考價(jià)值,希望對(duì)
    2022-09-09

最新評(píng)論

防城港市| 松阳县| 乡城县| 山东| 兴安县| 抚松县| 县级市| 玉田县| 张家港市| 绥化市| 舒兰市| 伊宁县| 南昌市| 轮台县| 石棉县| 灵山县| 湾仔区| 闵行区| 江北区| 巢湖市| 临清市| 盈江县| 安塞县| 平邑县| 都昌县| 常熟市| 延庆县| 江安县| 晋宁县| 霍州市| 湛江市| 阿合奇县| 新乡县| 太谷县| 武安市| 新密市| 萍乡市| 锦州市| 林口县| 永吉县| 通渭县|