样式

caoguanjie2022年8月29日大约 5 分钟约 1364 字

样式

CSS Modules

在样式开发过程中,有两个问题比较突出:

  • 全局污染: CSS 文件中的选择器是全局生效的,不同文件中的同名选择器,根据 build 后生成文件中的先后顺序,后面的样式会将前面的覆盖;
  • 选择器复杂: 为了避免上面的问题,我们在编写样式的时候不得不小心翼翼,类名里会带上限制范围的标示,变得越来越长,多人开发时还很容易导致命名风格混乱,一个元素上使用的选择器个数也可能越来越多,最终导致难以维护。

好在 vue 为我们提供了 scopedopen in new window 可以很方便的解决上述问题。 它顾名思义给 css 加了一个域的概念。

/* 编译前 */
.example {
  color: red;
}

/* 编译后 */
.example[_v-f3f3eg9] {
  color: red;
}

只要加上<style scoped>这样 css 就只会作用在当前组件内了。详细文档见 vue-loaderopen in new window

提示

使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。

目录结构

FitsAdmin所有全局样式都在 @/styles 下设置

......                        
├── src                                 
│   ├── style                       # 样式文件
│   │    ├── _global.scss           # 全局变量,跟variables.module.scss几乎功能一样
│   │    ├── element-plus.scss      # 全局自定义 element-ui 样式
│   │    ├── index.scss             # 全局通用样式
│   │    ├── mixin.scss             # 全局mixin
│   │    ├── sidebar.scss           # 布局中侧边栏的自定义样式
│   │    ├── theme.scss             # 全局主题样式,主要定义root的样式
│   │    ├── transition.scss        # 布局不同组件
└   └    └── variables.module.scss  # 全局变量,这个变量可以导入ts或者scss里面使用
......    

这里重点提一下 _global.scssvariables.module.scss,这两个文件都是定义css变量,但是 _global.scss是在vite.config.ts里面全局导入的,直接在任何css标签里面直接引入即可,variables.module.scss里面的变量如果要使用,需要在css里面导入@import该文件才能使用,也可以通过import关键字直接导入ts文件中使用,例如:import variables from '@/styles/variables.module.scss';

// vite.config.ts
export default ({ mode }: ConfigEnv): UserConfig => {
    css: {
      // css预处理器
      preprocessorOptions: {
        scss: {
          charset: false,
          // 引入全局scss变量,不过这样有个坑,就是一定要下划线的scss文件路径才引入正常。
          additionalData: '@import "./src/styles/_global.scss";',
        },
      },
    },
}

常见的工作流程是,全局样式都写在src/styles目录下,每个页面自己对应的样式都写在自己的.vue文件之中

<style>
/* global styles */
</style>

<style scoped>
/* local styles */
</style>

自定义 element Plus 样式

现在我们来说说怎么覆盖 element Plus 样式。由于 element Plus 的样式我们是在全局引入的,所以你想在某个页面里面覆盖它的样式就不能加 scoped,但你又想只覆盖这个页面的 element 样式,你就可在它的父级加一个 class,用命名空间来解决问题。

.article-page {
  /* 你的命名空间 */
  .el-tag {
    /* element-ui 元素*/
    margin-right: 0px;
  }
}

当然也可以使用深度作用选择器 下文会介绍

深度选择器:deep

深度选择器就是父组件改变子组件样式,当你子组件使用了 scoped 但在父组件又想修改子组件的样式可以 通过 :deep()来实现:

<style scoped>
 :deep(.el-input){
    display: none;
 }


// 下面的例子要看清楚,当有并集选择器,直接把类名放入 :deep() 括号中是不太对的
// 如下修改只能改到第一个类名,修改不到第二个类名
:deep(.el-input__inner,
.el-button.is-round) {
    width: 440px;
    height: 60px;
    line-height: 20px;
    border-radius: 30px;
    border: 1px solid rgba(211, 211, 211, 100);
    font-size: 16px;
}

//应改为
:deep(.el-input__inner),
:deep(.el-button.is-round) {
    width: 440px;
    height: 60px;
    line-height: 20px;
    border-radius: 30px;
    border: 1px solid rgba(211, 211, 211, 100);
    font-size: 16px;
}
</style>

警告

  • :deep()深度选择器只会在scoped标签内生效
  • >>>/deep/::v-deep这vue2模式中常用的深度选择器都将在vue3项目上弃用

知识拓展

vue2一开始用的是>>>来作为深度选择器,但是后来发现某些CSS预处理程序(例如SASS)在解析它时会遇到问题,因为这不是官方的CSS组合器。

所以后来采用了/deep/,但是又有人担心担心/deep/在Vue SFC中使用它们会导致在删除该功能的浏览器中不支持其代码。

为避免混淆的/deep/组合器,就引入了自定义组合器,::v-deep这次更明确地说明这是Vue特定的扩展,并使用伪元素语法,

更多详情open in new window

@mixin与@include实现css编程式风格

在vue中使用sass的mixin来简化样式代码,提高代码的复用率

// src/styles/mixin.scss
// @mixin 函数名($参数名: 默认值)
@mixin flex($justify-content: center, $align-center: center, $flex-direction: row){
  display: flex;
  justify-content: $justify-content;
  align-items: $align-center;
  flex-direction: $flex-direction;
}

像上面的写法,封装好scss的函数之后,在.vue文件中使用关键字@include进行引用即可

<style lang="scss" scoped>
@import './mixin.scss';
.main-wrap {
  @include flex(center,center,row);
}
</style>
上次编辑于: 2023/7/5 03:00:45
贡献者: caoguanjie
Loading...