Vue3 实战 - 配置 scss
安装 sass
bash
$ pnpm install sass -D
在 style 标签中注明即可
vue
<style scoped lang="scss"></style>
什么是 scoped
实现组件的私有化。当前 style
属性只属于当前模块。
在 DOM
结构中可以发现,vue
通过在 DOM
结构以及 css
样式上加了唯一标记,达到样式私有化,不污染全局的作用。
BEM
架构
他是一种 css
架构 oocss 实现的一种 (面向对象css),BEM
实际上是 block
、element
、modifier
的缩写,分别为块层、元素层、修饰符层,element
UI
也使用的是这种架构
BEM 命名约定的模式是:
scss
.block {}
.block__element {}
.block--modifier {}
scss
.el-input__inner # be
.el-button--success # bm
使用 sass
最小单元复刻一个 bem
架构,在 src
目录下新建 styles
目录,添加 bem.scss
文件,内容如下:
scss
// bem.scss
$block-sel: "-" !default;
$element-sel: "__" !default;
$modifier-sel: "--" !default;
$namespace:'am' !default;
@mixin bfc {
height: 100%;
overflow: hidden;
}
// 混入
@mixin b($block) {
$B: $namespace + $block-sel + $block; //变量
.#{$B}{ //插值语法#{}
@content; //内容替换
}
}
@mixin e($element) {
$selector:&;
@at-root {
#{$selector + $element-sel + $element} {
@content;
}
}
}
@mixin m($modifier) {
$selector:&;
@at-root {
#{$selector + $modifier-sel + $modifier} {
@content;
}
}
}
全局扩充 scss
ts
# 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';"
}
}
}
})
Vue 组件中使用:
vue
<template>
<div class="am-wraps">
<div>
<Menu></Menu>
</div>
<div class="am-wraps__right">
<Header></Header>
<Content></Content>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from "vue"
import Menu from './Menu/index.vue'
import Content from './Content/index.vue'
import Header from './Header/index.vue'
</script>
<style lang="scss" scoped>
@include b('wraps'){
@include bfc;
@include flex;
@include e(right){
flex:1;
display: flex;
flex-direction: column;
}
}
</style>
其他全局样式设置
除了上面配置的 bem.scss
外,我们还有一些其他的需要全局配置的样式(如清除默认样式等),可以如下操作,在 src/styles
目录下新建 index.scss
reset.scss
custom.scss
文件,内容分别如下:
scss
// index.scss
@import './reset.scss';
@import './custom.scss';
scss
// reset.scss
*,
::before,
::after {
box-sizing: border-box;
border-color: currentcolor;
border-style: solid;
border-width: 0;
}
#app {
width: 100%;
height: 100%;
}
html {
box-sizing: border-box;
width: 100%;
height: 100%;
line-height: 1.5;
tab-size: 4;
text-size-adjust: 100%;
}
body {
width: 100%;
height: 100%;
margin: 0;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial,
sans-serif;
line-height: inherit;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizelegibility;
}
a {
color: inherit;
text-decoration: inherit;
}
img,
svg {
display: inline-block;
}
svg {
vertical-align: -0.15em; // 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果
}
ul,
li {
padding: 0;
margin: 0;
list-style: none;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
a,
a:focus,
a:hover {
color: inherit;
text-decoration: none;
cursor: pointer;
}
a:focus,
a:active,
div:focus {
outline: none;
}
scss
// custom.scss
// 其他全局样式
在 main.ts
中引入 index.scss
ts
import '@/styles/index.scss'
import 'virtual:svg-icons-register'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router).mount('#app')