使用BEM架构构建Layout布局

239 阅读1分钟

一、BEM架构

BEM架构是一种css架构,oocss 实现的一种 (面向对象css),BEM实际上是block、element、modifier的缩写,分别为块层、元素层、修饰符层,element UI 也使用的是这种架构。

BEM 命名约定的模式是:

.block {}
 
.block__element {} // 双下划线
 
.block--modifier {} // 双中划线

二、初始化BEM架构

首先需要安装Sass预处理器

npm install sass -D // 安装到开发环境

然后创建一个sass文件

在该文件编写bem规则

$block-sel: "-"  !default;
$element-sel: "__"  !default;
$modifier-sel: '--'  !default;
$namespace: 'sys'  !default;


// 混入
// 1. 块
@mixin block($name) {
  .#{$namespace + $block-sel + $name} { // 拼接类名
    @content; // 块的内容
  }
}
// 2. 元素
@mixin element($name) {
  $selector: &; // 选择器
  @at-root { // 选择器的根
    #{$selector + $element-sel + $name} {
      @content;
    }
  }
}
// 3. 修饰符
@mixin modifier($name) {
  $selector: &;
  @at-root {
    #{$selector + $modifier-sel + $name} {
      @content;
    }
  }
}

在vite.config.ts文件中配置,使得整个项目的文件都可以使用BEM架构

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  // 配置全局scss
  css: {
    preprocessorOptions: {
        scss: {
            additionalData: `@import "./src/bem.scss";`
        }
    }
  }
})

使用示例

<script setup lang="ts">
</script>

<template>
  <div class="sys-test">
    <div class="sys-test__child">
    </div>
    <p class="sys-test--primary">hello</p>
  </div>
</template>

<style lang="scss">
@include block(test){
  width: 100px;
  height: 100px;
  border: 1px solid red;
  @include element(child){
    width: 50px;
    height: 50px;
    border: 1px solid blue;
  }
  @include modifier(primary) {
    color: green;
  }
}

</style>

三、构建Layout布局

接下来,就可以使用BEM架构来创建一个简单的Layout布局

首先,需要清除默认的样式

在index.html文件中,加入如下代码,不过建议另外建一个reset.css文件

<style>
          *{
              margin: 0;
              padding: 0;
          }
          html,body{
              height: 100%;
              overflow: hidden;
          }
      </style>

同时,App.vue文件中也需要加上初始化CSS代码

先在bem.scss文件中定义

@mixin bfc {
  height: 100%;
  overflow: hidden;
}

然后在APP.vue中使用

<style lang="scss">
// 注意,这里不需要使用scoped
#app{
  @include bfc;
}
</style>

创建文件夹,格式如下

menu下的index文件

<script setup lang="ts">

</script>

<template>
  <div class="sys-menu">
    menu
  </div>
</template>

<style scoped lang="scss">
@include block('menu'){
  min-width: 100px; // 侧边栏最小宽度
  border-right: 1px solid #ccc;
  height: 100%; // 侧边栏高度
}
</style>

header下的 index文件

<script setup lang="ts">

</script>

<template>
  <div class="sys-header">
    header
  </div>
</template>

<style scoped lang="scss">
@include block('header') {
  height: 60px; // 头部高度
  border-bottom: 1px solid #ccc;
  //line-height: 60px; // 文字垂直居中
  //padding: 0 20px; // 左右内边距
}
</style>

content 下的index文件

<script setup lang="ts">

</script>

<template>
  <div class="sys-content">
    <div v-for="item in 100">{{ item }}</div>
  </div>
</template>

<style scoped lang="scss">
@include block('content'){
  flex: 1; // 内容区域占满剩余空间
  overflow: auto; // 内容区域超出滚动
}
</style>

layout下的 index文件

<script setup lang="ts">
import Menu from './menu/index.vue'
import Header from './header/index.vue'
import Content from './content/index.vue'
</script>

<template>
  <div class="sys-wraps">
    <div>
      <Menu />
    </div>
    <div class="sys-wraps__right">
      <Header />
      <Content />
    </div>
  </div>
</template>

<style scoped lang="scss">
@include block('wraps'){
  @include bfc;
  display: flex;
  @include element('right'){
    display: flex; // 右侧内容区域使用flex布局
    flex-direction: column; //  内容区域垂直排列
    flex: 1;
  }
}
</style>

App.vue

<script setup lang="ts">
import Layout from './layout/index.vue'
</script>

<template>
  <Layout />
</template>

<style lang="scss">
// 注意,这里不需要使用scoped
#app{
  @include bfc;
}
</style>