Vue:scoped與module的使用與利弊

一個(gè)web應(yīng)用是離不開html、css與js带到,其中css充斥的整個(gè)web項(xiàng)目中。css它有一個(gè)特定,它是全局的超营。這樣的特性導(dǎo)致的結(jié)果是庆揩,一旦你在不同的地方定義了相同的css命名镊叁,那么它們的樣式就會(huì)相互覆蓋唾琼,最終導(dǎo)致的style錯(cuò)亂,從而影響整個(gè)網(wǎng)頁(yè)布局疯趟。

我相信對(duì)于每一個(gè)前端開發(fā)者都遇到過這種css樣式覆蓋的情況拘哨,值得慶幸的是,這些問題前輩都已經(jīng)給出了解決方案迅办。

在Vue中我們通過Scoped與Module來解決宅静。下面我會(huì)分別對(duì)scoped與module解決方案進(jìn)行說明,最后在分析它們的利弊與選擇站欺。如果你還未使用過或者說對(duì)它們之間的利弊與選擇存在疑問的姨夹,相信這篇文章能夠幫你解惑。

Scoped

假設(shè)我們有如下一段代碼:

index.vue

<template>
  <div class="content">
    <div class="title-wrap">我是紅色的</div>
    <green-title></green-title>
  </div>
</template>
 
<style lang="scss">
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>

GreenTitle.vue

<template>
  <div class="content">
    <div class="title-wrap">我是綠色的</div>
  </div>
</template>
 
<style lang="scss">
.content {
  .title-wrap {
    font-size: 20px;
    color: green;
  }
}
</style>

最終這屏幕上展示的是兩行紅色的文字矾策,這就是父組件與子組件都定義了title-wrap的樣式磷账,導(dǎo)致子組件的樣式被父組件所覆蓋。

遇到這種情況贾虽,可以在style標(biāo)簽中添加scoped屬性

<style lang="scss" scoped>
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>

scoped作用的阻止上層的css樣式傳遞到下層逃糟,限制當(dāng)前css作用域,使其只對(duì)當(dāng)前組件生效。

知道了它的作用绰咽,下面我們?cè)陂_深入看下它的實(shí)現(xiàn)菇肃。

前面的是沒有添加scoped的源碼,后面是添加了scoped的源碼取募。我們進(jìn)行一一對(duì)比琐谤,發(fā)現(xiàn)前面的兩個(gè)div標(biāo)簽都使用了title-wrap樣式,自然導(dǎo)致樣式覆蓋玩敏;而后面的兩個(gè)div標(biāo)簽斗忌,第一個(gè)增加了data-v-67e6b31f的前綴,這就是父組的style中增加scoped的效果旺聚,區(qū)別與第二個(gè)div中的title-wrap樣式织阳。

scoped的實(shí)現(xiàn)是借助了PostCSS實(shí)現(xiàn)的,一旦增加了scoped砰粹,他會(huì)將之前覆蓋的樣式轉(zhuǎn)換成下面的樣式

<style lang="scss">
.content[data-v-67e6b31f] {
  .title-wrap[data-v-67e6b31f] {
    font-size: 20px;
    color: red;
  }
}
</style>

通過這種轉(zhuǎn)換方式唧躲,間接的改變了原有的css命名。防止上層組件樣式覆蓋下層組件樣式碱璃。

特性

細(xì)心的讀者可能會(huì)發(fā)現(xiàn)上面的后一張?jiān)创a圖中第二個(gè)div的content中也有data-v-67e6b31f惊窖,可能會(huì)疑問,第二個(gè)content不是子組件中的css嗎厘贼?子組件中未添加scoped,為什么還會(huì)添加data-v-67e6b31f前綴圣拄?

這是scoped的一個(gè)特性嘴秸,使用 scoped 后,父組件的樣式將不會(huì)滲透到子組件中庇谆。不過一個(gè)子組件的根節(jié)點(diǎn)會(huì)同時(shí)受其父組件有作用域的 CSS 和子組件有作用域的 CSS 的影響岳掐。這樣設(shè)計(jì)是為了讓父組件可以從布局的角度出發(fā),調(diào)整其子組件根元素的樣式饭耳。

所以如果我們將子組件做如下修改

<template>
  <!-- <div class="content"> -->
    <div class="title-wrap">我是綠色的</div>
  <!-- </div> -->
</template>

由于父組件scoped特性串述,所以會(huì)影響到子組件的title-wrap,也會(huì)添加data-v-67e6b31f前綴

那么又有個(gè)疑問寞肖,增加了scoped是否就一定不能傳遞的下層組件呢纲酗?畢竟我們可能有需要個(gè)別樣式傳遞到下層的需求。別急新蟆,接著看觅赊,這個(gè)也能很方便的解決。

深度作用

如果你希望scoped中的某個(gè)樣式能夠作用的更深琼稻,影響到子組件吮螺,你可以使用>>>操作符

<style scoped>
.content >>> .title-wrap {
    font-size: 20px;
    color: red;
}
</style>

注意看我將style中的lang="scss"去掉了,因?yàn)榧恿祟A(yù)處理器后無(wú)法正確解析>>>,這種情況可以使用/deep/代替鸠补,本質(zhì)是>>>的別名

<style lang="scss" scoped>
.content {
  /deep/ {
    .title-wrap {
      font-size: 20px;
      color: red;
    }
  }
}
</style>

將會(huì)編譯成

.content[data-v-67e6b31f] .title-wrap {
    font-size: 20px;
    color: red;
}

通過 v-html 創(chuàng)建的 DOM 內(nèi)容不受作用域內(nèi)的樣式影響萝风,但是你仍然可以通過深度作用選擇器來為他們?cè)O(shè)置樣式

Module

針對(duì)上面的覆蓋問題,還可以通過設(shè)置module來解決

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是紅色的</div>
    <green-title></green-title>
  </div>
</template>
 
<style lang="scss" module>
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>

module的用法也很簡(jiǎn)單紫岩,只要在style中增加module屬性即可规惰。不同之處是它在布局中的引用,都需要添加前綴$style被因。因?yàn)橥ㄟ^module作用的style都被保存到$style對(duì)象中卿拴。我可以通過console查看它的具體引用名。

mounted() {
  console.log(this.$style)
  console.log(this.$style['title-wrap'])
}

通過觀察梨与,發(fā)現(xiàn)引用名有一定的規(guī)律堕花。都是已index開頭,后面再接著style中定義的命名粥鞋,最后再接個(gè)后綴缘挽。這里的index是父組件的文件名index.vue。所以通過module作用的style將會(huì)重新命名為:文件名原style名不定后綴呻粹。

這么命名又有什么好處呢壕曼?我們?cè)賮砜聪抡故镜男Ч?/p>

當(dāng)我們?cè)跒g覽的控制臺(tái)查看Elements時(shí),優(yōu)點(diǎn)顯而易見等浊。相對(duì)于scoped的方式腮郊,module的方式能夠一眼知道該元素時(shí)屬于哪個(gè)文件組件中。在大型項(xiàng)目中能夠幫助我們迅速定位到要查找的組件筹燕。

除了上述的快速定位轧飞,由于module會(huì)將所有的style都?xì)w入$style中,所以我們可以很靈活的將任意的父組件樣式傳遞到任意深層的子組件中撒踪。例如过咬,將父組件中的title-wrap通過props傳遞到子組件中

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是紅色的</div>
    <green-title :styleTitle="$style['title-wrap']"></green-title>
  </div>
</template>
<template>
  <div class="content">
    <div :class="styleTitle">我是綠色的</div>
  </div>
</template>
<script>
 
export default {
  props: {
    styleTitle: String,
  },
}
</script>

module還有一個(gè)特性非常不錯(cuò),它可以導(dǎo)出定義的變量制妄,將變量歸入$style中掸绞,例如:

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是紅色的</div>
    <green-title :styleTitle="$style['title-wrap']"></green-title>
    <div>{{$style.titleColor}}</div>
  </div>
</template>
 
<style lang="scss" module>
$title-color: red;
:export {
  titleColor: $title-color
}
.content {
  .title-wrap {
    font-size: 20px;
    color: $title-color;
  }
}
</style>

更多module相關(guān)操作可以點(diǎn)擊查看

總結(jié)

scoped與module都非常簡(jiǎn)單、易用耕捞,那么又該如何選擇呢衔掸?

通過上面的使用對(duì)比,發(fā)現(xiàn)scoped不需要額外的知識(shí)砸脊,只要在style中定義scoped屬性即可具篇,使用非常簡(jiǎn)便。但它的局限性是適用于中小項(xiàng)目中凌埂。因?yàn)閟coped作用的style對(duì)于我們來說不直觀驱显,對(duì)于快速查找定位,module更加合適,同時(shí)module對(duì)于style向下傳遞的控制權(quán)也非常靈活埃疫;額外的還有變量導(dǎo)出等便捷功能伏恐。

所以如果你是小項(xiàng)目中且低成本的使用,scoped更加適合栓霜;而對(duì)大項(xiàng)目module更加合適翠桦,雖然有一點(diǎn)學(xué)習(xí)成本,但對(duì)于用更好的控制權(quán)胳蛮、可觀性與定位速度來說也就不值一提销凑。

公眾號(hào)

感覺不錯(cuò)的可以來一波關(guān)注,微信搜索關(guān)注公眾號(hào):怪談時(shí)間仅炊,及時(shí)獲取最新知識(shí)技巧與互聯(lián)網(wǎng)新動(dòng)態(tài)斗幼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抚垄,隨后出現(xiàn)的幾起案子蜕窿,更是在濱河造成了極大的恐慌,老刑警劉巖呆馁,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桐经,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡浙滤,警方通過查閱死者的電腦和手機(jī)阴挣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纺腊,“玉大人屯吊,你說我怎么就攤上這事∧〔ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵骗爆,是天一觀的道長(zhǎng)次氨。 經(jīng)常有香客問我,道長(zhǎng)摘投,這世上最難降的妖魔是什么煮寡? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮犀呼,結(jié)果婚禮上幸撕,老公的妹妹穿的比我還像新娘。我一直安慰自己外臂,他們只是感情好坐儿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般貌矿。 火紅的嫁衣襯著肌膚如雪炭菌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天逛漫,我揣著相機(jī)與錄音黑低,去河邊找鬼。 笑死酌毡,一個(gè)胖子當(dāng)著我的面吹牛克握,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枷踏,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼菩暗,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了呕寝?” 一聲冷哼從身側(cè)響起勋眯,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎下梢,沒想到半個(gè)月后客蹋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡孽江,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年讶坯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岗屏。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辆琅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出这刷,到底是詐尸還是另有隱情婉烟,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布暇屋,位于F島的核電站似袁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏咐刨。R本人自食惡果不足惜昙衅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望定鸟。 院中可真熱鬧而涉,春花似錦、人聲如沸联予。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至谭羔,卻和暖如春华糖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘟裸。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工客叉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人话告。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓兼搏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親沙郭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子佛呻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容