在 Vue.js 中,scoped 是一个非常有用的特性,允许你将样式限制在当前组件的作用域内,避免样式泄漏到其他组件。它是通过 Vue 的单文件组件(.vue 文件)中的
<style>
标签实现的。
目录
案例演示
vue_4">创建多个vue文件
- Home.vue
<template>
<div class="test1">
<h1>定位:{{ address}}</h1>
<h1>详细:{{ detailAddress }}</h1>
</div>
</template>
<script>
export default {
name: "Company",
data() {
return {
detailAddress: "生态科技园",
address: "广东省深圳市南山区",
};
},
methods:{
test(){
this.hello();
},
},
};
</script>
<style>
.test1{
background: blue;
border: 10px solid red;
}
</style>
- Staff.vue
<template>
<div class="test2">
<h1>用户名:{{ name }}</h1>
<h1>性别:{{ sex }}</h1>
</div>
</template>
<script>
export default {
name: "Staff",
data() {
return {
name: "摔跤猫子",
sex: "男",
};
}
};
</script>
<style>
.test2{
background: pink;
border: 10px dotted green;
}
</style>
- App.vue
<template>
<div id="app">
<StaffVue />
<Home />
</div>
</template>
<script>
import StaffVue from './components/Staff.vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
StaffVue,
CompanyVue,
Home
}
}
</script>
启动项目后页面效果如下图所示,因为两个不同的vue文件中分别使用了不同的css样式以及不同的class名称,所以其样式各自独立并不冲突。
这时可以看到在没有修改样式内容,只修改了class类名的前提下,Home.vue的样式已经与Staff.vue的样式达到了一样的效果,当多个vue文件在一起时就很容易出现类名冲突的问题。
两个不同的vue文件中,class都是test2,为什么样式效果是渲染Staff.vue中css样式而不是Home.vue中的? 这是因为在App.vue中是先引用的Home.vue,再引用的Staff.vue,后面的vue文件会把前面的给覆盖掉。
如果将两者的顺序调整一下,先引用Staff.vue,再引用Home.vue,即以Home.vue中的样式为主。脚手架在解析App.vue文件的时候,先扫描的是引入的文件,然后再读取配置项,最后才解析模板。
如何处理类名样式冲突
当组件较少时也许可以通过使用不同的类名来解决这个问题,但终究不是长久之计,也不太现实。只需要在
style
标签中增加scoped
即可,scope翻译就有范围的意思。给这个style
标签增加了scoped
标记,也就意味着其样式只作用于当前vue结构中,对其进行限制。
在页面右键检查就可以看到,它是给最外层的div增加了一个特殊的标签属性并拼接了一个随机生成的值,每次运行这个值可能都不一样,通过这种方式就完成了控制指定的div。
vue_131">不适合用scoped的组件:App.vue
在 Vue.js 项目中,
App.vue
文件是应用的根组件,它是整个 Vue 应用的入口组件。通常,App.vue
作为最上层的组件,负责渲染并展示其他子组件。它通常用于配置应用的基本结构、路由、状态管理(例如 Vuex)等全局功能。
<style >
.title{
font-size: 30px;
color: white;
font-family: 'Courier New', Courier, monospace;
}
</style>
- 其他vue组件
<h1 class="title">用户名:{{ name }}</h1>
得到效果如下图,位于App.vue组件中的样式能够全局作用到其他组件。如果在App.vue组件中使用了scoped,则该样式只能作用于其本身组件中对应的类名标签上。
总结
scoped 的基本使用
<template>
<div class="my-component">
<p>This is a scoped style example.</p>
</div>
</template>
<script>
export default {
name: 'MyComponent'
};
</script>
<style scoped>
.my-component {
background-color: lightblue;
}
p {
color: green;
}
</style>
工作原理
在 Vue 的
<style scoped>
中,Vue 会自动为该组件的 CSS 选择器添加一个特殊的属性选择器,这样这些样式只会应用于当前组件的 DOM 元素。
例如,Vue 会为.my-component
类生成一个独特的属性选择器(比如 data-v-xxxxxx),并在 DOM 元素上添加这个属性。然后,样式将仅适用于当前组件的根节点或具有该属性的元素。
例如,以上代码经过 Vue 编译后,生成的 CSS 可能会类似于:
.my-component[data-v-123abc] {
background-color: lightblue;
}
p[data-v-123abc] {
color: green;
}
scoped 的局限性
- 全局样式:scoped 只影响当前组件的样式。如果你需要全局样式,scoped 不适用。可以使用
<style>
标签而不加 scoped,或者使用外部的 CSS 文件。 - 深度选择器:有时你需要为子组件中的元素应用样式,但 scoped 仅作用于当前组件。如果要跨组件的深度嵌套应用样式,可以使用 ::v-deep(也叫 >>> 或 /deep/)。
例如:
<style scoped>
.parent-class ::v-deep .child-class {
color: red;
}
</style>
或者使用 /deep/(这种写法是 Vue 2.x 的):
<style scoped>
.parent-class /deep/ .child-class {
color: red;
}
</style>
作用范围
scoped 样式仅限于当前组件,它不会影响其他组件的样式。它的作用是将 CSS 样式限制在该组件的 DOM 元素内部,从而避免全局样式的冲突。
组合与嵌套
可以将多个 scoped 样式放在同一个
<style>
标签中,Vue 会自动确保这些样式局部化。
<template>
<div class="my-component">
<p>This is scoped.</p>
<button class="btn">Click Me</button>
</div>
</template>
<style scoped>
.my-component {
color: blue;
}
.my-component p {
font-size: 14px;
}
.my-component .btn {
background-color: red;
color: white;
}
</style>
注意事项
注意事项
scoped
和@import
:如果你在 scoped 样式中使用了 @import 导入外部 CSS 文件,这些外部文件的样式会应用到全局,而不会被限制在当前组件的作用域内。为了避免全局污染,尽量避免在 scoped 样式中使用全局 @import。scoped
不适用JavaScript
变量:scoped 样式只针对 CSS 有效,而不支持 JavaScript 动态变量。需要动态样式时,可以使用 Vue 的动态绑定样式(v-bind:style)和类(v-bind:class)功能。
常见问题和解决方案
- 样式覆盖问题:当子组件的样式需要覆盖父组件时,可以使用 ::v-deep 或 /deep/ 来确保样式的覆盖。
- 多个 scoped 样式冲突:如果两个组件的 scoped 样式相互冲突,可以通过更改 CSS 的选择器来避免。例如,可以使用更具体的选择器来确保某个组件样式不会被其他组件覆盖。