场景
在子组件中用到了ele-ui
的el-scrollbar
(自定义滚动的隐藏组件,官方无文档说明,可以在其他地方搜到使用方法),如图:
style样式如下:
此处期望修改为X轴无滚动条,Y轴显示自定义滚动条:
然而直接在子组件里添加代码下方代码,并未生效(子组件style添加了scoped属性)。同时在控制台styles中并未找到对应样式设置。
.el-scrollbar__wrap {
overflow-y: scroll;
overflow-x: hidden;
}
然后尝试将此段代码添加到公共样式中,生效。
问题
scoped究竟有何作用?el-scrollbar
在子组件里使用,子组件中设置el-scrollbar__wrap
的样式却无效?如何解决这个问题?
求解
官方文档,有作用域的 CSS。
- 当
<style>
标签有scoped
属性时,它的 CSS 只作用于当前组件中的元素。 - 通过
v-html
创建的 DOM 内容不受作用域内的样式影响,但是你仍然可以通过深度作用选择器来为他们设置样式。 - 有些像
Sass
之类的预处理器无法正确解析>>>
。这种情况下你可以使用/deep/
操作符取而代之——这是一个>>>
的别名,同样可以正常工作。
在上面场景中,el-scrollbar
虽然是在子组件中使用,但是el-scrollbar__wrap
却是动态生成的DOM元素,如果要在子组件中设置需要使用深度作用选择器>>>
(或/deep/
) 。此处子组件style
设置了lang="scss"
,上述代码修改如下:
/* .el-scrollbar 为原有的DOM元素 */
.el-scrollbar {
&/deep/ .el-scrollbar__wrap {
overflow-y: scroll;
overflow-x: hidden;
}
}
同时删除了公共样式中相关样式设置。然后运行,达成预期。
当然文档里同样说明在一个组件中可以同时使用有作用域和无作用域的样式。另一种方案则是此组件中另写个全局样式标签,并将需要设置的样式放入其中。(并不能感觉和最初有啥区别,都是设置全局)
其它
scoped
属性可以理解为组件样式的私有化,其设置的样式只对当前组件有效,即只对组件中的DOM
元素有效(包括组件中用到的子组件的根元素
)。
有组件About.vue
如下:
<template>
<div class="about">
<h1>This is an about page</h1>
<!-- 组件c-div -->
<c-div class="cdiv"></c-div>
</div>
</template>
<script>
import Cdiv from "@/views/Cdiv";
export default {
data() {
return {};
},
components: {
"c-div": Cdiv
}
};
</script>
<style lang="scss" scoped>
h1 {
color: red;
}
.cdiv {
width: 100px;
height: 100px;
margin: 0 auto;
border: 1px solid #000;
h3 {
color: red;
}
}
</style>
下面的是子组件Cdiv.vue
:
<template>
<div class="about">
<h3>这是组件C</h3>
</div>
</template>
<script>
export default {
data() {
return {};
},
components: {}
};
</script>
<style lang="scss" scoped>
h3 {
color: blue;
}
</style>
在浏览器下查看
DOM
结构,不难发现scoped
设置组件样式私有化,是通过给DOM
元素添加对应属性(如data-v-039c5b43
),并在对应样式中添加对应属性选择器,由于不同组件之间的属性是不同的,因此可以实现样式私有化控制。
将Cdiv.vue
中style
标签的scoped
移除,并添加插槽:
<c-div class="cdiv">
<h3>about</h3>
</c-div>
在没有使用
深度作用选择器
的情况下,属性会添加到样式直接作用的具体元素,无论是子组件的子元素,还是后续动态添加的元素都无法在PostCSS
转换的时候被添加对应属性(还不存在),因此scoped
对子元素或动态添加的元素无效。深度作用选择器
有点像属性委托,将被直接作用到的子元素的的属性委托到其父元素上,如解决方案中修改后的样子: