一文彻底弄懂scoped的原理,导致的问题及解决的办法

先说个前序,有多少人把scoped写成scope的…

原理:
在 vue 去编译组件的时候,如果当前 style 标签上有 scoped 属性,那么就会为当前组件所有标签(若有子组件,则会在子组件最外层标签)添加上一个 data-v-hash 的属性,而当前样式表的所有尾部选择器后面也会加上该属性,那么就使得当前组件内的样式只作用域当前组件内的元素。

通过 PostCSS 实现以下转换

<template>
  <div class="test">hello</div>
</template>

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

转换后

<template>
  <div class="test" data-v-efdef544>hello</div>
</template>

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

可能出现的情况:
1.当父组件无scoped属性,子组件带有scoped,子组件所有标签会套上子组件的data-v-hash属性,

2.当父组件有scoped属性,子组件无scoped.父组件所有标签和子组件的最外层标签有父组件的data-v-hash属性.

3.父子组件都有scoped,父组件的所有标签有父组件的data-v-hash属性,子组件的所有标签有子组件的data-v-hash属性,这时子组件的最外层标签就会同时套上父组件和子组件的data-v-hash属性

导致的问题
这里以情况3设个例子:

父组件

<template>
  <div class="father">
   <-- 子组件 -->
    <son><son>
   <-- 子组件 -->
  </div>
</template>
<style scoped>
.son .son-box {
  color: red;
}
</style>

子组件

<template>
 <div class="son">
    <div class="son-box">
      abc
    </div>
 </div>
</template>
<style scoped>
.son-box {
  color: yellow;
}
</style>

转换后

<template>
  <div class="father" data-v-acc63fea>
   <-- 子组件 -->
    <div class="son" data-v-4475b032 data-v-acc63fea>
     <div class="son-box" data-v-4475b032>
       abc
     </div>
    </div>
   <-- 子组件 -->
  </div>
</template>
<style scoped>
<-- 父组件样式,作用不了 -->
.son .son-box[data-v-acc63fea] {
  color: red;
}
<-- 子组件样式 -->
.son-box[data-v-4475b032] {
  color: yellow;
}
</style>

解决的办法
方法一: 通过外联css(即在外创建.css文件,在组件的<style scoped></style>中通过@import引入)
原理: 通过@import引入,外联样式表的所有尾部选择器后面不会加上data-v-hash属性
缺点: 会造成有多个css文件,若在子组件中应用时,因为通过@import引入的文件是没有data-v-hash唯一标识的,即这个文件的样式会造成组件间的污染
适用场景: 设置所有组件的全局样式时使用,即应用在app.vue

方法二: 在同一个组件, 同时存在两个<style scoped></style>,<style></style>
原理: 不加scoped的style,所有尾部选择器后面不会加上data-v-hash属性
优点: 方便修改
缺点: 若不是独一无二的class类,不带scoped的可能造成全局污染
使用场景: 该组件中有一个独一无二的class类进行包裹

方法三(推荐): 使用深度选择器(也叫样式穿透)
注意: (less,sass,scss等预编译)使用(/deep/或者::v-deep),非预编译的话是(>>>)
原理: 会将 /deep/或>>> 替换成对应组件的 hash 值
优点: 可以在scoped直接修改子组件样式
缺点: 没有缺点,实在说有缺点的话,就是要写(/deep/或>>>,::v-deep)
使用场景: 所有
注意: 使用/deep/在同等情况下,默认父组件设置的子组件样式权重比子组件内的高,但子组件设置的样式有嵌套父类,则子组件的高,但父组件也可以嵌套同样的父类,这样父组件权重还是比子组件的高

使用深度选择器后,通过 PostCSS 实现以下转换(注意,我没用预编译,所以应该使用>>>)

<template>
  <div class="test">hello</div>
</template>

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

转换后

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

最后,如果本文有哪些不对或者可以改善的,请评论指出,谢谢!

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值