vue中慎用style的scoped属性

时间: 2017-11-23阅读: 3494标签: vue

vue组件中,为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,这是一个非常好的举措,但是为什么要慎用呢?因为scoped往往会造成我们在修改公共组件(三方库或者项目定制的组件)的样式困难,需要增加额外的工作量。

scoped实现原理

通过查看DOM结构发现:vue通过在DOM结构以及css样式上加唯一不重复的标记,以保证唯一,达到样式私有化模块化的目的。具体的渲染结果是怎样的,通过一个例子来说明。

公共组件button组件

一个公共组件button,为了样式模块化,给其加上scoped属性,

//button.vue
<template>
<div>
<button>text</button>
</div>
</template>
...
<style scoped>
.button-warp{
display:inline-block;
}
.button{
padding: 5px 10px;
font-size: 12px;
border-radus: 2px;
}
</style>

浏览器渲染button组件

button组件在浏览器渲染出的html部分和css部分分别为:

<div data-v-2311c06a class="button-warp">
<button data-v-2311c06a class="button">text</button>
</div>
.button-warp[data-v-2311c06a]{
display:inline-block;
}
.button[data-v-2311c06a]{
padding: 5px 10px;
font-size: 12px;
border-radus: 2px;
}

从上面的字可以看出,添加了scoped属性的组件,为了达到组件样式模块化,做了两个处理:

  • html的DOM节点加一个不重复data属性(形如:data-v-2311c06a)来表示他的唯一性
  • 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-2311c06a])来私有化样式

这样做虽然达到了组件样式模块化的目的,但是会造成一种后果:每个样式的权重加重了,会造成css样式不容易修改

其他组件引用button组件

如果在组件content.vue中使用了button组件,那么content.vue组件是否添加scoped属性渲染出来的结果有什么区别呢?我们来看看:

//content.vue
<template>
<div>
<p></p>
<!-- v-button假设是上面定义的组件 -->
<v-button></v-button>
</div>
</template>
...
<style>
.content{
width: 1200px;
margin: 0 auto;
}
.content .button{
border-raduis: 5px;
}
</style>

没有加scoped属性引用组件的渲染

如果style上没有加scoped属性,那么渲染出来html和css分别就是:

<div class="content">
<p class="title"></p>
<!-- v-button假设是上面定义的组件 -->
<div data-v-2311c06a class="button-warp">
<button data-v-2311c06a class="button">text</button>
</div>
</div>
.button-warp[data-v-2311c06a]{
display:inline-block;
}
.button[data-v-2311c06a]{
padding: 5px 10px;
font-size: 12px;
border-radus: 2px;
}
.content{
width: 1200px;
margin: 0 auto;
}
.content .button{
border-raduis: 5px;
}

可以看出,虽然在content组件中,修改了button的border-raduis属性,但是由于权重关系,生效的依然是组件内部的样式(此时是外部的样式被覆盖)。所以如果要达到修改样式的目的,就必须加重我们要修改样式的权重(增加选择器层级,ID选择器,并列选择器,impotant等)

添加scoped属性引用组件的渲染

如果加了scoped属性呢?按照开始分析出来的规则(事实也是这么的):
首先是在所有的DOM节点加上data属性
然后在css选择器尾部加上data属性选择器

那么渲染出来html和css分别就是:

<div data-v-57bc25a0 class="content">
<p data-v-57bc25a0 class="title"></p>
<!-- v-button假设是上面定义的组件 -->
<div data-v-57bc25a0 data-v-2311c06a class="button-warp">
<button data-v-2311c06a class="button">text</button>
</div>
</div>
.button-warp[data-v-2311c06a]{
display:inline-block;
}
.button[data-v-2311c06a]{
padding: 5px 10px;
font-size: 12px;
border-radus: 2px;
}
.content[data-v-57bc25a0]{
width: 1200px;
margin: 0 auto;
}
.content .button[data-v-57bc25a0]{
border-raduis: 5px;
}

对于上面的两种情况,可以明显看出来渲染后的结果大不相同。
并且content也修改了button组件的样式,但是仔细看,由于.content .button这句在末尾加的是content组件的标记,所以这句其实根本作用不到我们想要的DOM节点上,所以这种情况我们在content内部写的任何样式都不会影响到button组件,所以这就尴尬了。。。。当然这个问题也是可以解决的,就是在content属性再加一个不带scoped属性的标签,也就意味着要加两个style,一个用于私有样式,一个用于共有样式。真是shit,即:

//content.vue
<template>
<div>
<p></p>
<!-- v-button假设是上面定义的组件 -->
<v-button></v-button>
</div>
</template>
...
<style scoped>
.content{
width: 1200px;
margin: 0 auto;
}
</style>
<style>
.content .button{
border-raduis: 5px;
}
</style>

这样符合规范么?貌似没看到不能这么写,并且这么写也确实生效了。。。不知道怎么感概!!!

总结

总结一下scoped三条渲染规则

  • 给HTML的DOM节点加一个不重复data属性(形如:data-v-2311c06a)来表示他的唯一性
  • 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-2311c06a])来私有化样式
  • 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性

最后

在使用scoped一定要谨慎这个巨坑,已提 issue 
issue已被干掉,scoped设计的初衷就是不能让当前组件的样式修改其他任何地方的样式,所以如果要修改其他组件的样式,那么必定不能加scoped属性
如果大家有好的解决方案或者其他发现希望一起交流

原始链接:http://2ue.github.io/2017/11/15/vue-style-scoped/   

站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/162

Vue基于snabbdom做了哪些事

Snabbdom 核心代码大约只有 200 行。它提供了模块化架构,具有丰富的功能,可通过自定义模块进行扩展。在了解核心 patch 前,需要先了解 snabbdom 的模块化架构思想。

vue中$nextTick详细讲解

今天我们要实现这个一个小功能; 页面渲染完成后展示一个div元素; 当点击这个div元素后; div元素消失; 出现一个input元素;并且input元素聚焦

Vue中mixin怎么理解?

mixin是为了让可复用的功能灵活的混入到当前组件中,混合的对象可以包含任意组件选项(生命周期,指令之类等等), mixin翻译过来叫混合,高级的词汇可以叫插件入侵

Vue2 中三种逻辑复用方法

Mixin对象能够使用组件的任何属性(data,mounted,created,update等),而且当组件使用mixin时,这个mixin的所有信息也会混合到这个组件里

vue知识点总汇

keep-alive它是vue的内置组件在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:

Vue 中的作用域插槽

什么时候使用作用域插槽呢?当子组件循环或某一部分的dom结构应该由外部传递进来的时候,我们要用作用域插槽,使用作用域插槽,子组件可以向父组件的作用域插槽里传递数据,父组件如果想接收这个数据,必须在外层使用template模版占位符,同时通过slot-scope对应的属性名字,来接收你传递过来的数据

vue介绍

库是一种插件,是一种封装好的特定方法的集合。提供给开发者使用,控制器在使用者手里。框架是一套架构,会基于自身特定向用户提供一套相当完整的解决方案,控制权在框架本身

12种使用Vue的最佳做法

随着 VueJS 的使用越来越广泛,出现了几种最佳实践并逐渐成为标准。在本文中,主要分享在平时开发中一些有用资源和技巧,废话少说,我们开始吧。

你应该知道的Vue高级特性

Vue为我们提供了很多高级特性,学习和掌握它们有助于提高你的代码水平。从我们刚开始学习Vue的时候,对于侦听属性,都是简单地如下面一般使用:

基于vue移动端UI框架有哪些?vue移动端UI框架总汇

vue现在使用的人越来越多了,这篇文章主要整理一些比较优秀的移动端ui框架,推荐给大家,例如:mint UI、vux、vonic、vant、cube-ui、Muse-ui、Vue-Carbon、YDUI等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!