scoped和module使用场景
用于解决样式覆盖问题
scoped
限制当前css作用域,阻止当前层css样式传递到下层
- 常规使用,阻止样式覆盖
<!-- 父组件 index.vue -->
<template>
<div class="content">
<div class="title-wrap">我是红色的</div>
<green-title></green-title>
</div>
</template>
<style lang="scss">
.content {
.title-wrap {
font-size: 20px;
color: red;
}
}
</style>
<!-- 子组件 -->
<template>
<div class="content">
<div class="title-wrap">我是绿色的</div>
</div>
</template>
<style lang="scss">
.content {
.title-wrap {
font-size: 20px;
color: green;
}
}
</style>
运行效果:
父组件覆盖子组件样式导致,使用scoped解决
<style lang="scss" scoped>
.content {
.title-wrap {
font-size: 20px;
color: red;
}
}
</style>
从css源码了解scoped实现原理:
---未添加scoped:
---添加scoped:
父组件class为'title-wrap'的div增加了data-v-67e6b31f的前缀, 用于区别子组件的同类名div
scoped特性:借助了PostCSS实现
使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件有作用域的 CSS 和子组件有作用域的 CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。因此子组件‘content’组件也有前缀
增加了scoped属性将父组件样式做如下转换:
<style lang="scss">
.content[data-v-67e6b31f] {
.title-wrap[data-v-67e6b31f] {
font-size: 20px;
color: red;
}
}
</style>
- 深度作用
用于个别样式传递到下层的需求
// 使用>>>
<style scoped>
.content >>> .title-wrap {
font-size: 20px;
color: red;
}
</style>
// 预处理器使用/deep/
<style lang="scss" scoped>
.content {
/deep/ {
.title-wrap {
font-size: 20px;
color: red;
}
}
}
</style>
// 最终样式编译结果
.content[data-v-67e6b31f] .title-wrap {
font-size: 20px;
color: red;
}
最终结果:
module
style中增加
module属性。在布局中的引用,都需要添加前缀
$style。因为通过module作用的style都被保存到$style对象中。导出style中定义的变量
<template>
<div :class="$style.content">
<div :class="$style['title-wrap']">我是红色的</div>
<green-title></green-title>
</div>
</template>
<style lang="scss" module>
.content {
.title-wrap {
font-size: 20px;
color: red;
}
}
</style>
//查看引用名
console.log(this.$style.content)
console.log(this.$style['title-wrap'])
css源码:
通过module作用的class会重新命名,命名格式如下:
组件名_类名_随机后缀 (index_title-wrap_3b0wc)
这种命名方式好处在于:
(1)大型项目中能够帮助我们迅速定位到要查找的组件
(2)可以很灵活的将任意的父组件样式传递到任意深层的子组件中
例如,将父组件中的title-wrap通过props传递到子组件中
<template>
<div :class="$style.content">
<div :class="$style['title-wrap']">我是红色的</div>
<green-title :styleTitle="$style['title-wrap']"></green-title>
</div>
</template>
<template>
<div class="content">
<div :class="styleTitle">我是绿色的</div>
</div>
</template>
<script>
export default {
props: {
styleTitle: String,
},
}
</script>
导出style中定义的变量
<template>
<div :class="$style.content">
<div :class="$style['title-wrap']">我是红色的</div>
<green-title :styleTitle="$style['title-wrap']"></green-title>
<div>{{$style.titleColor}}</div>
</div>
</template>
<style lang="scss" module>
$title-color: red;
:export {
titleColor: $title-color
}
.content {
.title-wrap {
font-size: 20px;
color: $title-color;
}
}
</style>
module动态绑定class写法:
// active为动态绑定的样式
:class="[$style.label, { [$style['active']]: tabIndex === 1 }]"
优劣势对比
--scoped:
适用于中小项目
影响子组件根元素样式
--module:大项目
快速查找定位
控制style向下传递(props)
变量导出
css 模块化
解决命名冲突
(1) BEM命名规范
Block_Element_modifier: 通过命名约束解决命名冲突问题
(2) CSS Modules
动态生成class名,实现局部作用域效果
// vue中使用(vue-cli提供为vue-loader, vue-loader提供了与 CSS Modules 的集成)
<style module> // 注入$style计算属性
<style module="a"> // 自定义注入名称
// 向组件注入一个局部对象,可在模板中动态绑定
<template>
<p :class="$style.red">
This should be red
</p>
</template>
-------------
// .js
import styles from './foo.module.css';
element.innerHTML = `<div class="${styles.green}">`;
-------------
// .css
.green {
color: green;
}
// 编写全局样式
:global(.green) {
color: red;
}
// 样式复用
.otherClassName {
composes: green;
color: yellow;
}
配合css-loader打包使用,或者使用vue-cli(支持css modules)创建项目
(3) CSS in JS
import styled from "styled-components";
// 创建一个带样式的 h1 标签
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
参考链接: Css Modules