一、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>