css moudle及其在vue项目中的使用

scoped css

在Vue项目中,一般使用 scoped 属性来创建样式模块。带有scoped属性的样式模块只会作用于当前组件的元素。

CSS 复制代码
<template>
    <div class="example">
        <p>这是一个段落</p>
    </div>
</template>

<style scoped>
.example {
    color: red;
}
</style>

最终页面效果如下:

这是借助vue-loader和PostCSS 实现的.

不过这种方式存在缺陷: 如果你子组件的根元素上有一个类已经在这个父组件中定义过了,那么这个父组件的样式就会泄露到子组件中。例如:

Parent.vue:

vue 复制代码
<template>
  <div class="container">
    <p>parent</p>
    <child />
  </div>
</template>

<script>
import Child from "./components/Child";
export default {
  name: "App",
  components: {
    Child,
  },
};
</script>
<style scoped>
.container {
  color: red;
  border: 1px solid blue;
}
</style>

Child.vue

vue 复制代码
<template>
  <div class="container">
    <p>child</p>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
};
</script>
<style scoped>
</style>

为什么Child会受到Parent样式的影响? 可以看到经过loader处理后的html代码如下,如果父子组件都使用了scoped,那子组件的根元素也会有父组件的data-v-hash属性,会对子组件造成污染.

xml 复制代码
<div data-v-4184d4e3 class="container">
    <p data-v-4184d4e3>parent</p>
    <div data-v-00d89a5e data-v-4184d4e3 class="container">
        <p data-v-00d89a5e>child</p>
    </div>
</div>

css moudle

vue 复制代码
<template>
  <div :class="$style.container">
    <p>child</p>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  mounted() {
    console.log(this.$style);  // {container: '_src_components_Child__container'}
  }
};
</script>
<style module>
.container {
  color: green;
}
</style>

上面的模板在经过loader处理后的html为:

html 复制代码
<div data-v-4184d4e3 class="_src_components_Child__container">
    <p>child</p>
</div>

可以看到生成的class类名 _src_components_Child__container 为 文件路径+文件名+css类名 ,确保了class类名不会重复. 在模板中可以通过$style获取所有的样式.

可以明显看到使用css moudle的优点:

1、可以一眼看出样式属于哪个组件

2、不会让父组件的样式泄漏到子组件

实际上它还有一些其它的功能:

组合样式

对于样式复用,CSS Modules 只提供了唯一的方式来处理:composes 组合

css 复制代码
/* components/Button.css */
.base { /* 所有通用的样式 */ }
.normal {
  composes: base;
  /* normal 其它样式 */
}
.disabled {
  composes: base;
  /* disabled 其它样式 */
}

import styles from './Button.css';
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

由于在 .normal 中 composes 了 .base,编译后会 normal 会变成两个 class

html 复制代码
<button class="button--base-daf62 button--normal-abc53">Submit</button>

composes 还可以组合外部文件中的样式

css 复制代码
/* settings.css */
.primary-color {
    color: #f40;
}
/* components/Button.css */
.base { /* 所有通用的样式 */ }
.primary {
    composes: base;
    composes: primary-color from './settings.css';
    /* primary 其它样式 */
}
通过 :global 声明为全局样式
css 复制代码
:global {
  .global-class-name {
    color: green;
  }
}

在webpack中配置css moudle

只使用css moudle:

javascript 复制代码
{
  module: {
    rules: [
      // ... 其它规则省略
      {
        test: /.css$/,
        use: [
          'vue-style-loader',
          {
            loader: 'css-loader',
            options: {
              // 开启 CSS Modules
              modules: true,
              // 自定义生成的类名
              localIdentName: '[local]_[hash:base64:8]'
            }
          }
        ]
      }
    ]
  }
}

同时使用scope和css moudle:

perl 复制代码
// webpack.config.js -> module.rules
{
  test: /.css$/,
  oneOf: [
    // 这里匹配 `<style module>`
    {
      resourceQuery: /module/,
      use: [
        'vue-style-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true,
            localIdentName: '[local]_[hash:base64:5]'
          }
        }
      ]
    },
    // 这里匹配普通的 `<style>` 或 `<style scoped>`
    {
      use: [
        'vue-style-loader',
        'css-loader'
      ]
    }
  ]
}
相关推荐
LuHang1 小时前
从天地图切换到高德地图:一次真实的底图迁移实战
前端·vue.js·cesium
用户360055579001 小时前
Kestrel_VLLM - 27 · 寄存器常驻与融合发射:两次「少发一次」
前端
前端小万1 小时前
用"道法术器"重构你和 AI 的协作方式
前端·人工智能·程序员
鶴哥只手遮天1 小时前
Angular 22 源码级深度解析-第 06 章 模板指令全解:`ɵɵelementStart`、`ɵɵproperty`、`ɵɵadvance` 与绑定指令
前端·开源·angular.js
像我这样帅的人丶你还1 小时前
我html生成的doc文档为何在手机文档显示不了图片?
前端·javascript
前端双越老师3 小时前
程序员 1v1 访谈系列第十期:纯前端坚持不了多久了
前端·ai编程·全栈
门思科技4 小时前
LoRaWAN 网络排障的五层漏斗:从"上不到云"到"数值不对",每一层该用什么工具证明
前端
计算机魔术师4 小时前
Cursor 官方插件商城现恶意 Claude Code 扩展,约 11 小时影响最多 5000 名开发者
前端
掘金者阿豪4 小时前
MongoDB迁移到金仓数据库:商品属性继续灵活存,订单报表交给 SQL
前端·后端
栉甜5 小时前
Vue2学习内容(上)
前端·javascript·vue.js·学习