likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 57

scoped css

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

<template>
    <div class="example">
        <p>这是一个段落</p>
    </div>
</template>

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

最终页面效果如下: css moudle及其在vue项目中的使用

这是借助vue-loaderPostCSS 实现的.

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

Parent.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

<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属性,会对子组件造成污染.

<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

<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为:

<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 组合

/* 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>`

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

<button class="button--base-daf62 button--normal-abc53">Submit</button>

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

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

在webpack中配置css moudle

只使用css moudle:

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

同时使用scope和css moudle:

// 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'
      ]
    }
  ]
}
转载自:https://juejin.cn/post/7281570246111592504
评论
请登录