【Vue3】BEM 架构和 Sass 语法

news2024/11/16 15:28:29

1. BEM 架构

BEM(Block, Element, Modifier)是一种命名约定,用于在编写 CSS 和 HTML 类名时创建可维护和可重用的样式。BEM 是一种常用的 CSS 命名规范,它的目的是减少样式之间的耦合,增加样式的可读性,并提高样式的复用性。

BEM 的三个主要概念:

  1. Block(块):Block 是一个独立的、可复用的组件或模块,它代表一个完整的功能单元。块是一个顶层的元素,它本身应该有意义并且可以独立存在。
  2. Element(元素):Element 是块的组成部分,它不能单独存在,必须依赖于块。Element 是块的一部分,它只有在块的上下文中才有意义。
  3. Modifier(修饰符):Modifier 是用于改变块或元素外观、状态或行为的标志。通过添加修饰符类名,可以修改块或元素的样式,从而实现不同的变体。

BEM 的优点:

  1. 可读性:BEM 的类名规范清晰明了,易于理解和阅读,使其他开发者更容易理解代码结构和样式的用途。
  2. 可维护性:BEM 通过将样式与组件封装在一起,降低了样式之间的耦合性,使样式更易于维护和修改。
  3. 可重用性:BEM 鼓励将样式抽象为可复用的块和元素,提高了样式的复用性,减少了重复编写样式的工作。

element-plusinputbutton元素的样式为例:

在这里插入图片描述

在这里插入图片描述

BEM 的命名约定(以element-plus为例):

  • el:namespace(element-plus所有样式都是el开头)
  • -:block(代表块级区域)
  • __:element(连接元素内容)
  • --:modifier(修饰内容)

2. Sass 常用语法

2.1. 嵌套规则 (Nested Rules)

Sass 允许将一套 CSS 样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器,避免了重复输入父选择器。

例如:

#main p {
  color: #00ff00;
  width: 97%;

  .redbox {
    background-color: #ff0000;
    color: #000000;
  }
}

编译为:

#main p {
  color: #00ff00;
  width: 97%; 
}
#main p .redbox {
    background-color: #ff0000;
    color: #000000; 
}

2.2. 父选择器 & (Referencing Parent Selectors: &)

在嵌套 CSS 规则时,有时也需要直接使用嵌套外层的父选择器。

例如,当给某个元素设定 hover 样式时,或者当 body 元素有某个 classname 时,可以用 & 代表嵌套规则外层的父选择器。

a {
  font-weight: bold;
  text-decoration: none;
  &:hover { text-decoration: underline; }
  body.firefox & { font-weight: normal; }
}

编译为

a {
    font-weight: bold;
    text-decoration: none; 
}
a:hover {
	text-decoration: underline; 
}
body.firefox a {
    font-weight: normal; 
}

如果含有多层嵌套,最外层的父选择器会一层一层向下传递:

#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; }
  }
}

编译为

#main {
  color: black;
}
#main a {
  font-weight: bold;
}
#main a:hover {
  color: red;
}

2.3. 变量 ## (Variables: ## )

SassScript 最普遍的用法就是变量,变量以美元符号开头,赋值方法与 CSS 属性的写法一样:

$width: 5em;

直接使用即调用变量:

#main {
  width: $width;
}

编译为

#main {
  width: 5em;
}

2.4. 插值语句 #{} (Interpolation: #{})

通过 #{} 插值语句可以在选择器或属性名中使用变量:

$name: foo;
$attr: border;
/* 动态类名必须结合插值语句 */
p.#{$name} {
  #{$attr}-color: blue;
}

编译为

p.foo {
  border-color: blue; 
}

2.5. @at-root

子级跳出父级的嵌套

例如:

.parent {
  ...
  @at-root .child { ... }
}

编译为:

.parent { ... }
.child { ... }
/* 如果没有@at-root则编译为: */
/* .parent {...} */
/* .parent .child (...) */

2.6. 定义混合指令 @mixin (Defining a Mixin: @mixin)

公共的、常用的样式使用@mixin进行封装

@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}
.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

编译为:

.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px;
}

2.7. 参数 (Arguments)

参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:

/* 很类似于js中的函数 */
@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue, 1in); }
/* 1in:1英寸 */

编译为

p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed; 
}

3. 编写BEM架构和全局Sass文件

bem.scss

$namespace: 'el' !default;
$block-sel: '-' !default;
$elem-sel: '__' !default;
$mod-sel: '--' !default;

// block
// <div class="el-block"> 定义变量生成此规则
@mixin b($block) {
  $B:#{$namespace + $block-sel + $block};
  .#{$B} {
    @content; //相当于一个占位符
  }
}

// element
// .el-block__inner{} 定义变量生成此规则
@mixin e($el) {
  $selector: &;
  @at-root {
    #{$selector + $elem-sel + $el} {
      @content;
    }
  }
}

// modifier
@mixin m($m) {
  $selector: &;
  @at-root {
    #{$selector + $mod-sel + $m} {
      @content;
    }
  }
}

vite.config.ts

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  // 通过配置变为全局通用样式
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@import "./src/bem.scss";',
      },
    },
  }
})

App.vue

<template>
  <div class="el-test">
    test
    <div class="el-test__inner">inner</div>
    <div class="el-test--success">modify</div>
  </div>
</template>

<script setup lang="ts">

</script>

<style lang="scss" scoped>
@include b(test) {
  color: red;
  @include e(inner) {
    color: white;
  }
  @include m(success) {
    color: green;
  }
}
</style>

在这里插入图片描述

4. 小案例(Layout布局)

在这里插入图片描述

bem.scss

$namespace: 'el' !default;
$block-sel: '-' !default;
$elem-sel: '__' !default;
$mod-sel: '--' !default;

// BFC(Block Formatting Context)块格式化上下文
@mixin bfc {
  height: 100%;
  overflow: hidden;  
}

// block
// <div class="el-block"> 定义变量生成此规则
@mixin b($block) {
  $B:#{$namespace + $block-sel + $block};
  .#{$B} {
    @content; //相当于一个占位符
  }
}

// element
// .el-block__inner{} 定义变量生成此规则
@mixin e($el) {
  $selector: &;
  @at-root {
    #{$selector + $elem-sel + $el} {
      @content;
    }
  }
}

// modifier
@mixin m($m) {
  $selector: &;
  @at-root {
    #{$selector + $mod-sel + $m} {
      @content;
    }
  }
}

App.vue

<template>
  <Layout></Layout>
</template>

<script setup lang="ts">
// import { ref,reactive,onMounted } from 'vue';
import Layout from './Layout/index.vue';

</script>

<style lang="scss">
#app {
  @include bfc;
}
</style>

index.vue …\Content

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

<script setup lang="ts">
// import { ref,reactive } from 'vue';
</script>

<style lang="scss" scoped>
@include b(content) {
  flex: 1;
  overflow: auto;
  @include e(items) {
    padding: 10px;
    margin: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
}
</style>

index.vue …\Header

<template>
  <div class="el-header"> 
    Header
  </div>
</template>

<script setup lang="ts">
// import { ref,reactive } from 'vue';
</script>

<style lang="scss" scoped>
@include b(header) {
  height: 60px;
  border-bottom: 1px solid #ccc;
}
</style>

index.vue …\Menu

<template>
  <div class="el-menu">
    Menu
  </div>
</template>

<script setup lang="ts">
// import { ref,reactive } from 'vue';
</script>

<style lang="scss" scoped>
@include b(menu) {
  min-width: 200px;
  border-right: 1px solid #ccc;
  height: 100%;

}
</style>

index.vue …\Layout

<template>
  <div class="el-box">
    <div>
      <Menu></Menu>
    </div>
    <div class="el-box__right">
      <Header></Header>
      <Content></Content>
    </div>
  </div>
</template>

<script setup lang="ts">
// import { ref, reactive } from 'vue';
import Menu from './Menu/index.vue';
import Header from './Header/index.vue';
import Content from './Content/index.vue';
</script>

<style lang="scss" scoped>
@include b(box) {
  @include bfc;
  display: flex;
  @include e(right) {
    display: flex;
    flex-direction: column;
    flex: 1;
  }
}
</style>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/804783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多目标优化:NSGA(Ⅱ)

多目标优化的基本概念 习多目标优化的过程中&#xff0c;其中涉及相关概念如下&#xff1a; Pareto 支配关系 (Pareto Dominance)&#xff1a;支配&#xff1a;对于多个目标值&#xff0c;随机自变量x1、x2&#xff0c;对于任意一个目标函数都存在f(x1)<f(x2)&#xff0c;则…

Vue 3:玩一下web前端技术(三)

前言 本章内容为VUE工作过程与相关使用讨论。 上一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;二&#xff09;_Lion King的博客-CSDN博客 下一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;四&#xff09;_Lion Ki…

视频监控综合管理平台EasyCVR向上级联时,上级一直回复401是什么原因?

视频监控管理EasyCVR视频融合平台基于云边端一体化架构&#xff0c;可支持多协议、多类型设备接入&#xff0c;具体包括&#xff1a;NVR、IPC、视频编码器、无人机、车载设备、智能手持终端、移动执法仪等。平台具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环…

SSM 书籍借阅管理系统【纯干货分享,免费领源码04770】

摘 要 随着科学技术的告诉发展&#xff0c;我们已经步入数字化、网络化的时代。图书馆是学校的文献信息中心&#xff0c;是为全校教学和科学研究服务的学术性机构&#xff0c;是学校信息化的重要基地。图书馆的工作是学校和科学研究工作的重要组成部分&#xff0c;是全校师生学…

向量距离度量中的几种计算公式

距离度量 衡量两条向量之间的距离&#xff0c;可以将某一张图片通过特征提取来转换为一个特征向量。衡量两张图片的相似度就可以通过衡量这两张图片对应的两个特征向量之间的距离来判断了。 1.欧式距离 欧式距离可以简单理解为两点之间的直线距离。对于两个n维空间点 a ( x…

实景三维在智慧矿山中的应用

项目背景 智慧矿山是以矿山数字化、信息化为前提和基础&#xff0c;对矿山生产、职业健康与安全、技术支持与后勤保障等进行主动感知、自动分析、快速处理&#xff0c;建设智慧矿山&#xff0c;最终实现安全矿山、无人矿山、高效矿山、清洁矿山的建设。 智慧矿山的可视化管理…

解决新版 Idea 中 SpringBoot 热部署不生效

标题 依赖中添加 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <opt…

组件开发系列--Apache Commons Chain

一、前言 Commons-chain是apache commons中的一个子项目,主要被使用在"责任链"的场景中,struts中action的调用过程,就是使用了"chain"框架做支撑.如果你的项目中,也有基于此种场景的需求,可以考虑使用它. 在责任链模式里&#xff0c;很多对象由每一个对象对…

纯nginx制作文件上传下载服务器

什么是webdav webdav 是一组超文本传输协议的技术集合&#xff0c;有利于用户键协同编辑和管理存储在万维网服务器文档。同时来说就是&#xff0c;webdav可以让用户直接存储&#xff0c;下载&#xff0c;编辑文件&#xff0c;操作文件需要进行用户认证 基于nginx快速搭建webdav…

ORA-00923: FROM keyword not found where expected

举个栗子呗&#xff0c;就是语法错误找不到“FROM”&#xff0c;也是少了逗号 数据库提示不精确 ERROR 1064 - You have an error in your SQL syntax&#xff1b;_spencer_tseng的博客-CSDN博客

倒立摆控制(SMART PLC串级PID控制)

专栏有好几篇倒立摆相关的文章,大家可以自行参考阅读,包括编码器角度测量以及一些模型介绍,这篇博客我们记录、介绍S7-200 SMART PLC进行倒立摆控制采用串级PID的调试过程。 1、倒立摆的串级PID控制 2、设置摆杆PID作用区域 角度作用区域,在其它文章有详细图示,大家可以…

文心一言 VS 讯飞星火 VS chatgpt (67)-- 算法导论6.5 6题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;67&#xff09;-- 算法导论6.5 6题 六、在 HEAP-INCREASE-KEY 的第 5 行的交换操作中&#xff0c;一般需要通过三次赋值来完成。想一想如何利用INSERTION-SORT 内循环部分的思想&#xff0c;只用一次赋值就完成这一交换操作? 文…

获取Bean的两种方法

简单获取Bean的两种方法 简单获取Bean的两种方法那么对于调用Bean对象时需要注意什么&#xff1f; 五大类注解自定义名称三种bean注入 简单获取Bean的两种方法 在之前使用spring时我们都是使用xml语句进行对象注入&#xff0c;而如果对于一个大型项目采用这种方法&#xff0c;…

Python_使用requests获取当当网榜单中的图书数据

使用requests获取当当网榜单中的图书数据 使用到的库概述发送请求xpath解析提取数据tips 完整代码 使用到的库 requestsetree 概述 主要抓取目标为 当当网图书畅销榜中近24小时畅销的图书信息 主要提取的数据为 排名、书名、评论数、推荐度、作者信息、出版时间、出版社、折扣…

MySQL主从复制(三十五)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、MySQL Replication概述 1.1 MySQL Replication优点&#xff1a; 二、MySQL复制类型 2.1 异步复制&#xff08;Asynchronous repication&#xff09; 2.2 全同步…

vue的条件渲染以及列表渲染的总结归纳加代码演示

&#x1f600;前言 本片文章是vue系列第4篇整理了vue的条件渲染以及列表渲染的总结归纳加代码演示 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我…

OR-Tools解决复杂调度问题:实际案例分析

目录 前言一、调度问题介绍二、案例分析2-1、护士调度问题2-2、作业车间调度问题 三、知识库3-1、collection3-2、CpModel().AddNoOverlap()3-3、CpModel().AddMaxEquality()3-4、cp_model.CpModel().NewIntVar()3-5、cp_model.CpModel().NewIntervalVar 总结 前言 调度问题是一…

干货 | 电路中为何需要串联小电阻?这样解释就懂了

干货 | 电路中为何需要串联小电阻&#xff1f;这样解释就懂了 一、电阻概念 电阻作为元器件&#xff0c;又叫作电阻器&#xff0c;导体的电阻通常用字母R表示&#xff0c;电阻的单位是欧姆&#xff08;ohm&#xff09;&#xff0c;简称欧&#xff0c;符号是Ω&#xff08;希腊字…

oracle,获取每日24*60,所有分钟数

前言&#xff1a; 为规范用户的时间录入&#xff0c;因此我们采用下拉的方式&#xff0c;让用户选择需要的时间&#xff0c;因此我们需要将一天24小时的时间拆分为类似00:00,00:01...23:00,23:01,23:59。因此我们需要生成24*601440行的下拉复选值。具体效果如下图所示。 思路 1…

langchina的PlayWrightBrowserToolkit (PlayWright 浏览器工具包)

langchina中的PlayWrightBrowserToolkit 好久不见了&#xff0c;朋友们&#xff0c;我&#xff08;小云&#xff09;也是好久不写博客了&#xff0c;随着ai的不断引进&#xff0c;和一大堆大语言的到来&#xff0c;我们今天就学习一下啊langchain这个大语言模型中PlaywrightBr…