当前位置: 首页 > news >正文

七、vue3后台项目系列——包装scss、全句变量scss与导入

直接进入正题:使用scss的好处是方便复用样式,并且统一修改,只要需要修改一处,全部引用就能生效。

一、解决原生 CSS 的核心痛点:提升开发效率

原生 CSS 没有变量、复用、逻辑控制等能力,写复杂样式时容易出现 “重复代码多、修改繁琐、结构混乱” 的问题,SCSS 针对性解决了这些痛点:

1. 变量($ 定义):统一管理可复用值
  • 作用:将重复使用的样式值(如颜色、尺寸、间距)定义为变量,修改时只需改一处,避免全局查找替换。
  • 场景:项目主题色、侧边栏宽度、通用间距等。
  • 示例

    scss

    // 定义变量
    $primary-color: #324157; // 主色调
    $sidebar-width: 210px;    // 侧边栏宽度
    $gap: 16px;               // 通用间距// 使用变量
    .sidebar {width: $sidebar-width;background: $primary-color;padding: $gap;
    }
    
  • 好处:主题切换、全局样式调整时,无需逐行修改,降低出错概率。
2. 混合宏(@mixin):复用带逻辑的样式片段
  • 作用:将重复的样式块(甚至带参数的动态样式)封装为 “函数式片段”,需要时直接调用,支持传参自定义。
  • 场景:flex 居中、文字省略、滚动条样式等通用样式。
  • 示例

    scss

    // 定义带参数的混合宏(多行文字省略)
    @mixin text-ellipsis($line: 1) {overflow: hidden;text-overflow: ellipsis;@if $line == 1 {white-space: nowrap; // 单行} @else {display: -webkit-box;-webkit-line-clamp: $line; // 多行-webkit-box-orient: vertical;}
    }// 使用混合宏(2行省略)
    .card-title {@include text-ellipsis(2);font-size: 16px;
    }
    
  • 好处:减少重复代码,统一通用样式逻辑(如所有 “文字省略” 样式只需维护一个混合宏)。
3. 嵌套语法:贴合 HTML 结构,减少选择器冗余
  • 作用:支持样式选择器嵌套,结构与 HTML 保持一致,无需重复写父选择器,代码更易读。
  • 场景:组件内部的父子元素样式(如导航栏 → 菜单项 → 激活态)。
  • 示例

    scss

    // SCSS 嵌套(贴合 HTML 结构)
    .nav {height: 60px;background: #fff;// 子元素 .nav-item.nav-item {float: left;padding: 0 20px;// 子元素的伪类&:hover {color: #409EFF;}// 子元素的激活态&.active {border-bottom: 2px solid #409EFF;}}
    }// 编译后的原生 CSS(自动补全父选择器)
    .nav { height: 60px; background: #fff; }
    .nav .nav-item { float: left; padding: 0 20px; }
    .nav .nav-item:hover { color: #409EFF; }
    .nav .nav-item.active { border-bottom: 2px solid #409EFF; }
    
  • 好处:避免选择器冗余(如不用写 .nav .nav-item 多次),结构更清晰,降低维护成本。

二、提升代码质量:可维护性与扩展性

1. 模块化(@use/@forward):拆分样式文件,解耦逻辑
  • 作用:将样式按功能拆分到不同文件(如 mixin.scss 放混合宏、variables.scss 放变量、sidebar.scss 放侧边栏样式),通过 @use 导入使用,避免单文件过大。
  • 场景:中大型项目(如后台管理系统)的样式拆分。
  • 示例

    scss

    // 1. 拆分变量文件:src/styles/variables.scss
    $primary-color: #324157;
    $sidebar-width: 210px;// 2. 拆分混合宏文件:src/styles/mixin.scss
    @use './variables' as var; // 导入变量文件
    @mixin sidebar-width {width: var.$sidebar-width; // 使用变量
    }// 3. 组件中使用:src/components/Sidebar.vue
    @use '@/styles/mixin' as mix; // 导入混合宏
    .sidebar {@include mix.sidebar-width;background: var.$primary-color;
    }
    
  • 好处:样式文件按功能划分,权责清晰,多人协作时不易冲突(如改变量不影响混合宏,改侧边栏样式不影响全局)。
2. 继承(@extend):复用相同样式,减少代码冗余
  • 作用:让一个选择器 “继承” 另一个选择器的所有样式,适合纯样式复用(无参数需求)。
  • 场景:多个元素共享基础样式(如 “成功按钮” 和 “主要按钮” 共享基础按钮样式)。
  • 示例

    scss

    // 基础按钮样式
    .btn {padding: 8px 16px;border: none;border-radius: 4px;cursor: pointer;
    }// 成功按钮继承基础样式,再扩展自己的颜色
    .btn-success {@extend .btn;background: #30B08F;color: #fff;
    }// 主要按钮继承基础样式,扩展自己的颜色
    .btn-primary {@extend .btn;background: #409EFF;color: #fff;
    }
    
  • 好处:避免重复写基础样式,编译后会合并选择器(如 .btn, .btn-success, .btn-primary { ... }),减少 CSS 文件体积。
3. 逻辑控制:支持条件、循环,实现动态样式
  • 作用:通过 @if/@else(条件)、@for/@each(循环)实现动态样式,适合批量生成或按条件切换的场景。
  • 场景:生成多尺寸的间距类、按主题切换样式。
  • 示例

    scss

    // 1. 条件判断:按主题切换颜色
    $theme: 'dark'; // 主题变量
    .header {@if $theme == 'dark' {background: #1f2d3d;color: #fff;} @else {background: #fff;color: #333;}
    }// 2. 循环生成:批量生成间距类(m-1 ~ m-4)
    @for $i from 1 through 4 {.m-#{$i} {margin: $i * 8px; // 每次递增 8px}
    }
    
  • 好处:复杂样式逻辑无需手写重复代码(如 10 个间距类只需一行循环),支持动态主题切换。

三、生态与工具链:无缝集成现代开发流程

1. 与构建工具兼容:Vite、Webpack 等自动处理
  • SCSS 可被主流构建工具(Vite、Webpack、Rollup)通过插件(如 sass-loader)自动编译为原生 CSS,无需手动处理。
  • 例如 Vite 中只需安装 sass 依赖,即可直接使用 .scss 文件,配置简单。
2. 支持后处理器:与 PostCSS 配合增强功能
  • SCSS 可与 PostCSS(自动前缀、CSS 压缩等)配合使用:先通过 SCSS 编译出 CSS,再通过 PostCSS 自动添加浏览器前缀(如 -webkit--moz-)、压缩代码,兼顾开发效率和浏览器兼容性。
3. 社区成熟:丰富的插件与预设
  • 有大量成熟的 SCSS 工具库(如 BEM 命名规范插件、Bootstrap 的 SCSS 源码),可直接复用,减少重复造轮子。
总结:SCSS 适合什么场景?
  • 中小项目:通过变量、混合宏减少重复代码,提升开发速度;
  • 中大型项目:通过模块化拆分、逻辑控制实现样式解耦,降低维护成本;
  • 团队协作:统一样式规范(如变量、混合宏),避免风格混乱。

简单来说,SCSS 不是 “替代 CSS”,而是 “增强 CSS”—— 让你用更高效、更优雅的方式写 CSS,尤其在项目复杂度提升时,其优势会越来越明显。

四、回到项目中来

我包装的mixin.scss如下:

// 清除浮动
@mixin clearfix {&:after {content: "";display: table;clear: both;}
}// 给页面滚动条设置样式
@mixin scrollBar {&::-webkit-scrollbar-track-piece {background: #d3dce6;}&::-webkit-scrollbar {width: 6px;}&::-webkit-scrollbar-thumb {background: #99a9bf;border-radius: 20px;}
}// 相对定位(父元素)
@mixin relative {position: relative;width: 100%;height: 100%;
}// 快速设置 “指定宽度 + 居中”
@mixin pct($pct) {width: #{$pct};position: relative;margin: 0 auto;
}// 快速弄个三角形出来
@mixin triangle($width, $height, $color, $direction) {$width: $width/2;$color-border-style: $height solid $color;$transparent-border-style: $width solid transparent;height: 0;width: 0;@if $direction==up {border-bottom: $color-border-style;border-left: $transparent-border-style;border-right: $transparent-border-style;}@else if $direction==right {border-left: $color-border-style;border-top: $transparent-border-style;border-bottom: $transparent-border-style;}@else if $direction==down {border-top: $color-border-style;border-left: $transparent-border-style;border-right: $transparent-border-style;}@else if $direction==left {border-right: $color-border-style;border-top: $transparent-border-style;border-bottom: $transparent-border-style;}
}// 绝对定位居中(支持水平/垂直/全居中)
@mixin absoluteCenter($type: both) {position: absolute;@if $type == both { // 水平+垂直居中top: 50%;left: 50%;transform: translate(-50%, -50%);} @else if $type == horizontal { // 仅水平居中left: 50%;transform: translateX(-50%);} @else if $type == vertical { // 仅垂直居中top: 50%;transform: translateY(-50%);}
}// 内容在容器中完全居中(水平+垂直居中,不换行)
@mixin flex-center() {display: flex;justify-content: center; // 主轴居中align-items: center;     // 交叉轴居中flex-wrap: nowrap;       // 不换行
}// 内容左对齐,垂直居中(比如列表项、导航栏)
@mixin flex-start-center() {display: flex;justify-content: flex-start; // 主轴左对齐align-items: center;         // 交叉轴居中flex-wrap: nowrap;
}// 内容右对齐,垂直居中(比如顶部导航的用户菜单)
@mixin flex-end-center() {display: flex;justify-content: flex-end; // 主轴右对齐align-items: center;       // 交叉轴居中flex-wrap: nowrap;
}// 两端对齐(左右靠边,中间留白),垂直居中(比如卡片标题和操作按钮)
@mixin flex-between-center() {display: flex;justify-content: space-between; // 主轴两端对齐align-items: center;            // 交叉轴居中flex-wrap: nowrap;
}// 水平居中,垂直靠上(比如多行文字顶部居中)
@mixin flex-center-start() {display: flex;justify-content: center;   // 主轴居中align-items: flex-start;   // 交叉轴居上flex-wrap: nowrap;
}// 内容平均分布,垂直居中,超出换行(比如标签列表、图片网格)
@mixin flex-around-center-wrap() {display: flex;justify-content: space-around; // 主轴平均分布(两侧留白相等)align-items: center;           // 交叉轴居中flex-wrap: wrap;               // 换行
}// 左对齐,子元素拉伸占满高度,超出换行(比如表单项目)
@mixin flex-start-stretch-wrap() {display: flex;justify-content: flex-start; // 主轴左对齐align-items: stretch;        // 交叉轴拉伸(子元素高度相等)flex-wrap: wrap;             // 换行
}// 通用 flex 混入:可自定义主轴、交叉轴、换行方式
@mixin flex($justify: center,    // 主轴默认左对齐$align: center,         // 交叉轴默认拉伸$wrap: nowrap            // 默认不换行
) {display: flex;justify-content: $justify;align-items: $align;flex-wrap: $wrap;
}// 文字省略:单行或多行
@mixin textEllipsis($line: 1) {overflow: hidden;text-overflow: ellipsis;white-space: nowrap; // 单行不换行@if $line > 1 { // 多行省略(需浏览器支持)white-space: normal;display: -webkit-box;-webkit-line-clamp: $line; // 显示行数-webkit-box-orient: vertical;}
}

我包装的variables.scss如下:

// -------------------------- 基础颜色变量 --------------------------
// 深蓝色(常用于主色调、标题等)
$blue: #324157;
// 浅蓝色(常用于次要强调、边框等)
$light-blue: #3A71A8;
// 红色(常用于错误提示、删除按钮等)
$red: #C03639;
// 粉红色(常用于特殊标记、提醒等)
$pink: #E65D6E;
// 绿色(常用于成功提示、确认按钮等)
$green: #30B08F;
// 蒂芙尼蓝(常用于特殊模块、高亮等)
$tiffany: #4AB7BD;
// 黄色(常用于警告提示、重要标记等)
$yellow: #FEC171;
// 潘通绿(和上面的绿色类似,可能用于特定场景的区分)
$panGreen: #30B08F;// -------------------------- 侧边栏专用变量 --------------------------
// 侧边栏菜单文字默认颜色
$menuText: #bfcbd9;
// 侧边栏菜单选中时的文字颜色
$menuActiveText: #409EFF;
// 侧边栏子菜单选中时的文字颜色
$subMenuActiveText: #f4f4f5;// 侧边栏菜单背景色
$menuBg: #304156;
// 侧边栏菜单项 hover(鼠标经过)时的背景色
$menuHover: #263445;// 侧边栏子菜单背景色
$subMenuBg: #1f2d3d;
// 侧边栏子菜单项 hover(鼠标经过)时的背景色
$subMenuHover: #001528;// 侧边栏宽度(用于布局计算,比如内容区宽度 = 100% - 侧边栏宽度)
$sideBarWidth: 210px;// -------------------------- 供 JS 访问的变量 --------------------------
// 作用:让 JS 能读取 SCSS 中的变量(比如在 Vue 组件的 JS 部分动态计算布局时使用)
:root {--menuText: #{$menuText};           // 导出菜单文字颜色--menuActiveText: #{$menuActiveText}; // 导出菜单选中文字颜色--subMenuActiveText: #{$subMenuActiveText}; // 导出子菜单选中文字颜色--menuBg: #{$menuBg};               // 导出菜单背景色--menuHover: #{$menuHover};         // 导出菜单 hover 背景色--subMenuBg: #{$subMenuBg};         // 导出子菜单背景色--subMenuHover: #{$subMenuHover};   // 导出子菜单 hover 背景色--sideBarWidth: #{$sideBarWidth};   // 导出侧边栏宽度
}

在main.js中导入全局变量,一次导入

import { createApp } from 'vue'
import { createPinia } from 'pinia'
// 导入vite-plugin-svg-icons生成的雪碧图注册脚本
// 注意:这个文件是Vite构建时自动生成的,无需手动创建
import 'virtual:svg-icons-register'
// 初始化css样式
import 'normalize.css'
// 全局变量css样式
import '@/styles/variables.scss'
import App from './App.vue'
import router from '@/router/index.js' // 引入路由配置import SvgIcon from '@/components/SvgIcon/index.vue' // 导入组件// 创建Pinia实例
const pinia = createPinia()// 创建app实例
const app = createApp(App)
// 全局注册SvgIcon组件
app.component('SvgIcon', SvgIcon)
app.use(pinia)
app.use(router)// 挂在实例
app.mount('#app')

在layout中使用mixin.scss

使用@include语法导入所需要的预定样式

<style lang="scss" scoped>
@use "@/styles/mixin.scss" as *;
.app-wrapper {@include clearfix;position: relative;height: 100%;width: 100%;&.mobile.openSidebar {position: fixed;top: 0;}}.drawer-bg {background: #000;opacity: 0.3;width: 100%;top: 0;height: 100%;position: absolute;z-index: 999;}.fixed-header {position: fixed;top: 0;right: 0;z-index: 9;width: calc(100% - var(--sideBarWidth));transition: width 0.28s;}.hideSidebar .fixed-header {width: calc(100% - 54px)}.mobile .fixed-header {width: 100%;}</style>


文章转载自:

http://2fylJ7ED.tnnfy.cn
http://r86OJ0a7.tnnfy.cn
http://pkVo9mea.tnnfy.cn
http://NobbusGC.tnnfy.cn
http://wgQuq4vF.tnnfy.cn
http://os8E2Oz6.tnnfy.cn
http://SctMSbXS.tnnfy.cn
http://nspb4QXi.tnnfy.cn
http://PLOoLB2M.tnnfy.cn
http://YafAezpC.tnnfy.cn
http://9nAuVR8m.tnnfy.cn
http://SV92GVzZ.tnnfy.cn
http://q3hmkPjH.tnnfy.cn
http://2apzAGKo.tnnfy.cn
http://cujMTpeD.tnnfy.cn
http://PUHENLUk.tnnfy.cn
http://wQj80u4N.tnnfy.cn
http://4H2X0CrQ.tnnfy.cn
http://d6a3OrQf.tnnfy.cn
http://YxG3iBnt.tnnfy.cn
http://krotgkwM.tnnfy.cn
http://DrCDYJxb.tnnfy.cn
http://grBahLOx.tnnfy.cn
http://KUxjaTCa.tnnfy.cn
http://I9bLEsp2.tnnfy.cn
http://12vykpgM.tnnfy.cn
http://0iCEOoYc.tnnfy.cn
http://zx8XFO2d.tnnfy.cn
http://s3nijSYN.tnnfy.cn
http://ROf8bJEm.tnnfy.cn
http://www.dtcms.com/a/385452.html

相关文章:

  • 煤矿山井下绝绝缘监测故障定位
  • 海外分部人员OA请假申请时长为0
  • MySQL --JDBC
  • python使用pyodbc通过不同认证方式连接sqlserver数据源
  • java通过线程池加CompletableFuture实现批量异步处理
  • Coze源码分析-资源库-创建知识库-后端源码-详细流程梳理
  • 极简版 Nginx 反向代理实验步骤
  • python-86-基于Graphviz或Mermaid绘制流程图
  • 智能农机无人驾驶作业套圈路径规划
  • Rayon Rust中的数据并行库入门教程
  • NumPy数组与Python列表的赋值行为解析
  • 基于 AI 的大前端智能家居控制应用开发
  • RAGFlow集成SGLang部署的大模型:实现OpenAI API兼容的自定义LLM调用
  • sqlsever 内存配置错误无法连接,后面恢复连接
  • 51c大模型~合集182
  • 2025.9.15总结
  • 深入理解 Roo Code 的 Code Actions 功能
  • Java---线程池讲解
  • PEFT QLora Deepspeed Zero Stage 3 Offload Trainning
  • 线程概念,控制
  • 扫描仪常见样式:平板与馈纸的特性与适用场景
  • Python进程和线程——多线程
  • 2025年AIOCR审核革命!七大智能费控报销系统终结手工录入
  • 从循环到矩阵运算:矢量化加速机器学习的秘诀
  • R 语言入门实战|第七章 程序:从“老虎机”项目学透流程控制与代码优化
  • clickhouse 中SUM(CASE WHEN ...) 返回什么类型?
  • NR帧结构
  • 【联合查询】
  • 常见IC封装详解:从DIP到BGA的演进与应用
  • DockerComposeUI+cpolar:容器管理的远程可视化方案