8. 集成Vant组件库
安装Vant:
npm i vant@next -S
安装按需加载插件:
npm i vite-plugin-style-import -D
配置vite.config.js:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import styleImport, { VantResolve } from 'vite-plugin-style-import'
import postCssPxToRem from 'postcss-pxtorem'
// vite.config.js 继续
export default defineConfig({
plugins: [
vue(),
styleImport({
resolves: [VantResolve()],
libs: [
{
libraryName: 'vant',
esModule: true,
resolveStyle: (name) => `vant/es/${name}/style/index`
}
]
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
css: {
postcss: {
plugins: [
postCssPxToRem({
rootValue: 37.5, // Vant 官方根字体大小是 37.5
propList: ['*'],
selectorBlackList: ['.norem'] // 过滤掉.norem-开头的class,不进行rem转换
})
]
}
},
build: {
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
vant: ['vant'],
vendor: ['vue', 'vue-router', 'vuex']
}
}
}
}
})
9. 移动端适配
创建src/utils/flexible.js文件来处理移动端适配:
(function flexible(window, document) {
const docEl = document.documentElement
const dpr = window.devicePixelRatio || 1
// 调整body标签的fontSize
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = '16px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize()
// 设置根元素fontSize
function setRemUnit() {
const rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// 当页面大小变化时,重新设置rem
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
setRemUnit()
}
})
// 当设备屏幕支持0.5px时,设置meta标签的viewport
if (dpr >= 2) {
const fakeBody = document.createElement('body')
const testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
在main.js中引入:
import './utils/flexible'
10. 全局样式和组件
创建全局样式文件src/styles/index.scss:
// 引入重置样式
@import './reset.scss';
@import './variables.scss';
@import './mixin.scss';
// 全局样式
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
html {
height: 100%;
box-sizing: border-box;
}
// 滚动条样式
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #aaa;
}
// 清除浮动
.clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
// 页面过渡动画
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
// 安全区适配
.safe-area-bottom {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
创建src/styles/reset.scss:
/* 基本样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
html, body {
width: 100%;
height: 100%;
user-select: none;
}
a {
text-decoration: none;
color: inherit;
}
img {
vertical-align: middle;
width: 100%;
}
input, button, textarea {
border: none;
outline: none;
background: none;
}
ul, ol, li {
list-style: none;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
}
创建全局变量文件src/styles/variables.scss:
// 颜色变量
$primary-color: #1989fa;
$success-color: #07c160;
$warning-color: #ff976a;
$danger-color: #ee0a24;
$info-color: #909399;
// 文字颜色
$text-color-primary: #303133;
$text-color-regular: #606266;
$text-color-secondary: #909399;
$text-color-placeholder: #c0c4cc;
// 边框颜色
$border-color-base: #dcdfe6;
$border-color-light: #e4e7ed;
$border-color-lighter: #ebeef5;
$border-color-extra-light: #f2f6fc;
// 背景颜色
$background-color-base: #f5f7fa;
$background-color-light: #f5f5f5;
$background-color-white: #ffffff;
// 字体大小
$font-size-extra-large: 20px;
$font-size-large: 18px;
$font-size-medium: 16px;
$font-size-base: 14px;
$font-size-small: 13px;
$font-size-extra-small: 12px;
// 间距
$spacing-extra-large: 32px;
$spacing-large: 24px;
$spacing-medium: 16px;
$spacing-base: 12px;
$spacing-small: 8px;
$spacing-extra-small: 4px;
// 圆角
$border-radius-base: 4px;
$border-radius-small: 2px;
$border-radius-large: 8px;
$border-radius-round: 20px;
$border-radius-circle: 50%;
// 阴影
$box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12);
$box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
创建src/styles/mixin.scss:
// 文本溢出显示省略号
@mixin ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// 多行文本溢出显示省略号
@mixin multi-ellipsis($line: 2) {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: $line;
-webkit-box-orient: vertical;
}
// flex布局
@mixin flex($justify: center, $align: center, $direction: row) {
display: flex;
justify-content: $justify;
align-items: $align;
flex-direction: $direction;
}
// 定位居中
@mixin position-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
// 宽高
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
// 一像素边框
@mixin hairline($position: bottom, $color: $border-color-base) {
position: relative;
&::after {
content: '';
position: absolute;
@if $position == top {
left: 0;
top: 0;
right: 0;
height: 1px;
transform: scaleY(0.5);
border-top: 1px solid $color;
}
@else if $position == right {
top: 0;
right: 0;
bottom: 0;
width: 1px;
transform: scaleX(0.5);
border-right: 1px solid $color;
}
@else if $position == bottom {
left: 0;
right: 0;
bottom: 0;
height: 1px;
transform: scaleY(0.5);
border-bottom: 1px solid $color;
}
@else if $position == left {
top: 0;
left: 0;
bottom: 0;
width: 1px;
transform: scaleX(0.5);
border-left: 1px solid $color;
}
@else if $position == all {
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
border: 1px solid $color;
}
}
}