vue中慎用style的scoped属性

时间: 2017-11-23阅读: 3352标签: 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

12种使用Vue的最佳做法

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

简单理解vue中的$nextTick

Vue.nectTick() 是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的DOM(dom的改变是发生在nextTick()之后),这个方法作用是当数据被修改后使用这个方法

谈谈vue的render函数?

使用vue 这么长时间,对vue 对源码了解还是不多,作为一个不甘平庸的前端小白,决定奋起,那么今天我们就来谈谈vue 的render 函数;打开源码,我发现render 函数返回一个VNode; 可是我们并未在模版中写render 呀,这又是一个什么样的过程呢?

Vue 3.0 将从头开始重写!

Vue.js 伦敦大会上,Vue.js 作者尤雨溪简要介绍了 Vue 下一个主要版本要发布的内容,不久前,尤雨溪在 medium 个人博客上发布了 Vue 3.0 的开发路线,我们不妨看看 Vue 3.0 将会有怎样的发展。

Vue项目使用CDN优化首屏加载

将引用的外部js、css文件剥离开来,不编译到vendor.js中,而是用资源的形式引用,这样浏览器可以使用多个线程异步将vendor.js、外部的js等加载下来,达到加速首开的目的。外部的库文件,可以使用CDN资源,或者别的服务器资源等。

Vue组件的三种调用方式

主要讲Vue三种方式调用组件:v-model或者.sync显式控制组件显示隐藏,通过js代码调用,通过Vue指令调用,在写组件的时候很多写法、灵感来自于element-ui

vue框架开发出现页面空白、白屏的解决方法总汇

使用Vue-cli脚手架开发单页应用时出现页面空白的情况:1.npm run build打包页面空白,2. iOS的Safari下无法打开网页,3.升级vue2+部分手机访问出现页面空白,4.升级vue2+IP访问页面空白,5.Vue在IE下显示空白问题,6.Vue只在iOS 10出现白屏问题

vue中修改Modal的重置功能怎么写?

工作中遇到弹出模态框形式的修改功能,模态框里面是Form表单,Form表单中的内容是从后台获取的,这时候用户修改完没有提交,而是想重置然后重新修改,怎么办呢?

vue与后台交互ajax数据

Vue.js是一套构建用户界面的渐进式的前端框架。 vueJS与后台交互数据的方法我所了解的有以下几种

Vue组件中prop属性使用说明

props 把数据传给子组件!prop是组件数据的一个字段,期望从父作用域传下来。子组件需要显式地用 props 选项。props的大小写、静态的和动态的 Prop、传入一个数字、传入一个布尔值、Vue的组件中的props属性单向数据流

点击更多...

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