vue-cli4-vant
簡介
這是基于 vue-cli4 實(shí)現(xiàn)的移動端 H5 開發(fā)模板屠升,其中包含項(xiàng)目常用的配置及組件封裝歌逢,可供快速開發(fā)使用衫生。
技術(shù)棧:vue-cli4 + webpack4 + vant + axios + less + postcss-px2rem
// 安裝依賴
npm install
// 本地啟動
npm run dev
// 生產(chǎn)打包
npm run build
配置 vant
vant 是一套輕量媳溺、可靠的移動端 Vue 組件庫洞渤,非常適合基于 vue 技術(shù)棧的移動端開發(fā)况既。在過去很長的一段時間內(nèi)这溅,本人用的移動端 UI 框架都是 vux。后來由于 vux 不支持 vue-cli3棒仍,就轉(zhuǎn)用了 vant悲靴,不得不說,無論是在交互體驗(yàn)上莫其,還是代碼邏輯上癞尚,vant 都比 vux 好很多,而且 vant 的坑比較少乱陡。
對于第三方 UI 組件浇揩,如果是全部引入的話,比如會造成打包體積過大憨颠,加載首頁白屏?xí)r間過長的問題胳徽,所以按需加載非常必要积锅。vant 也提供了按需加載的方法。babel-plugin-import 是一款 babel 插件养盗,它會在編譯過程中將 import 的寫法自動轉(zhuǎn)換為按需引入的方式缚陷。
1、安裝依賴
npm i babel-plugin-import -D
2往核、配置 .babelrc 或者 babel.config.js 文件
// 在.babelrc 中添加配置
{
"plugins": [
["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]
]
}
// 對于使用 babel7 的用戶蹬跃,可以在 babel.config.js 中配置
module.exports = {
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
};
3、按需引入
你可以在代碼中直接引入 Vant 組件铆铆,插件會自動將代碼轉(zhuǎn)化為方式二中的按需引入形式
import Vue from 'vue'
import { Button } from 'vant'
Vue.use(Button)
rem 適配
移動端適配是開發(fā)過程中不得不面對的事情蝶缀。在此,我們使用 postcss 中的 px2rem-loader薄货,將我們項(xiàng)目中的 px 按一定比例轉(zhuǎn)化 rem翁都,這樣我們就可以對著藍(lán)湖上的標(biāo)注寫 px 了。
我們將 html 字跟字體設(shè)置為 100px谅猾,很多人選擇設(shè)置為 375px柄慰,但是我覺得這樣換算出來的 rem 不夠精確,而且我們在控制臺上調(diào)試代碼的時候無法很快地口算得出它本來的 px 值税娜。如果設(shè)置 1rem=100px坐搔,這樣我們看到的 0.16rem,0.3rem 就很快得算出原來是 16px敬矩,30px 了概行。
具體步驟如下;
1弧岳、安裝依賴
npm install px2rem-loader --save-dev
2凳忙、在 vue.config.js 進(jìn)行如下配置
css: {
// css預(yù)設(shè)器配置項(xiàng)
loaderOptions: {
postcss: {
plugins: [
require('postcss-px2rem')({
remUnit: 100
})
]
}
}
},
3、在 main.js 設(shè)置 html 跟字體大小
function initRem() {
let cale = window.screen.availWidth > 750 ? 2 : window.screen.availWidth / 375
window.document.documentElement.style.fontSize = `${100 * cale}px`
}
window.addEventListener('resize', function() {
initRem()
})
axios 請求封裝
1禽炬、設(shè)置請求攔截和響應(yīng)攔截
const PRODUCT_URL = 'https://xxxx.com'
const MOCK_URL = 'http://xxxx.com'
let http = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? PRODUCT_URL : MOCK_URL,
})
// 請求攔截器
http.interceptors.request.use(
(config) => {
// 設(shè)置token涧卵,Content-Type
var token = sessionStorage.getItem('token')
config.headers['token'] = token
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
// 請求顯示loading效果
if (config.loading === true) {
vm.$loading.show()
}
return config
},
(error) => {
vm.$loading.hide()
return Promise.reject(error)
}
)
// 響應(yīng)攔截器
http.interceptors.response.use(
(res) => {
vm.$loading.hide()
// token失效,重新登錄
if (res.data.code === 401) {
// 重新登錄
}
return res
},
(error) => {
vm.$loading.hide()
return Promise.reject(error)
}
)
2腹尖、封裝 get 和 post 請求方法
function get(url, data, lodaing) {
return new Promise((resolve, reject) => {
http
.get(url)
.then(
(response) => {
resolve(response)
},
(err) => {
reject(err)
}
)
.catch((error) => {
reject(error)
})
})
}
function post(url, data, loading) {
return new Promise((resolve, reject) => {
http
.post(url, data, { loading: loading })
.then(
(response) => {
resolve(response)
},
(err) => {
reject(err)
}
)
.catch((error) => {
reject(error)
})
})
}
export { get, post }
3柳恐、把 get,post 方法掛載到 vue 實(shí)例上热幔。
// main.js
import { get, post } from './js/ajax'
Vue.prototype.$http = { get, post }
工具類函數(shù)封裝
1乐设、添加方法到 vue 實(shí)例的原型鏈上
export default {
install (Vue, options) {
Vue.prototype.util = {
method1(val) {
...
},
method2 (val) {
...
},
}
}
2、在 main.js 通過 vue.use()注冊
import utils from './js/utils'
Vue.use(utils)
本文提供以下函數(shù)封裝
- 獲取 url 參數(shù)值
- 判斷瀏覽器類型
- 判斷 IOS/android
- 校驗(yàn)手機(jī)號碼
- 檢驗(yàn)車牌號
- 校驗(yàn)車架號
- 檢驗(yàn)身份證號碼
- 日期格式化
- 時間格式化
- 城市格式化
- 壓縮圖片
- 圖片轉(zhuǎn)成 base64
vue-router 配置
平時很多人對 vue-router 的配置可配置了 path 和 component断凶,實(shí)現(xiàn)了路由跳轉(zhuǎn)即可伤提。其實(shí) vue-router 可做的事情還有很多,比如
- 路由懶加載配置
- 改變單頁面應(yīng)用的 title
- 登錄權(quán)限校驗(yàn)
- 頁面緩存配置
路由懶加載配置
Vue 項(xiàng)目中實(shí)現(xiàn)路由按需加載(路由懶加載)的 3 中方式:
// 1认烁、Vue異步組件技術(shù):
{
path: '/home',
name: 'Home',
component: resolve => reqire(['../views/Home.vue'], resolve)
}
// 2肿男、es6提案的import()
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue')
}
// 3介汹、webpack提供的require.ensure()
{
path: '/home',
name: 'Home',
component: r => require.ensure([],() => r(require('../views/Home.vue')), 'home')
}
本項(xiàng)目采用的是第二種方式,為了后續(xù) webpack 打包優(yōu)化舶沛。
改變單頁面應(yīng)用的 title
由于單頁面應(yīng)用只有一個 html嘹承,所有頁面的 title 默認(rèn)是不會改變的,但是我們可以才路由配置中加入相關(guān)屬性如庭,再在路由守衛(wèi)中通過 js 改變頁面的 title
router.beforeEach((to, from, next) => {
document.title = to.meta.title
})
登錄權(quán)限校驗(yàn)
在應(yīng)用中叹卷,通常會有以下的場景,比如商城:有些頁面是不需要登錄即可訪問的坪它,如首頁骤竹,商品詳情頁等,都是用戶在任何情況都能看到的往毡;但是也有是需要登錄后才能訪問的蒙揣,如個人中心,購物車等开瞭。此時就需要對頁面訪問進(jìn)行控制了懒震。
此外,像一些需要記錄用戶信息和登錄狀態(tài)的項(xiàng)目嗤详,也是需要做登錄權(quán)限校驗(yàn)的个扰,以防別有用心的人通過直接訪問頁面的 url 打開頁面。
此時葱色。路由守衛(wèi)可以幫助我們做登錄校驗(yàn)递宅。具體如下:
1、配置路由的 meta 對象的 auth 屬性
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue'),
meta: { title: '首頁', keepAlive: false, auth: false },
},
{
path: '/mine',
name: 'mine',
component: () => import('../views/mine.vue'),
meta: { title: '我的', keepAlive: false, auth: true },
},
]
2冬筒、在路由首頁進(jìn)行判斷恐锣。當(dāng)to.meta.auth
為true
(需要登錄),且不存在登錄信息緩存時舞痰,需要重定向去登錄頁面
router.beforeEach((to, from, next) => {
document.title = to.meta.title
const userInfo = sessionStorage.getItem('userInfo') || null
if (!userInfo && to.meta.auth) {
next('/login')
} else {
next()
}
})
頁面緩存配置
項(xiàng)目中,總有一些頁面我們是希望加載一次就緩存下來的诀姚,此時就用到 keep-alive 了响牛。keep-alive 是 Vue 提供的一個抽象組件,用來對組件進(jìn)行緩存赫段,從而節(jié)省性能呀打,由于是一個抽象組件,所以在 v 頁面渲染完畢后不會被渲染成一個 DOM 元素糯笙。
1贬丛、通過配置路由的 meta 對象的 keepAlive 屬性值來區(qū)分頁面是否需要緩存
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue'),
meta: { title: '首頁', keepAlive: false, auth: false },
},
{
path: '/list',
name: 'list',
component: () => import('../views/list.vue'),
meta: { title: '列表頁', keepAlive: true, auth: false },
},
]
2、在 app.vue 做緩存判斷
<div id="app">
<router-view v-if="!$route.meta.keepAlive"></router-view>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
</div>
多環(huán)境變量配置
首先我們先來了解一下環(huán)境變量给涕,一般情況下我們的項(xiàng)目會有三個環(huán)境豺憔,本地環(huán)境(development)额获,測試環(huán)境(test),生產(chǎn)環(huán)境(production)恭应,我們可以在項(xiàng)目根目錄下建三個配置環(huán)境變量的文件.env.development抄邀,.env.test,.env.production
環(huán)境變量文件中只包含環(huán)境變量的“鍵=值”對:
NODE_ENV = 'production'
VUE_APP_ENV = 'production' // 只有VUE_APP開頭的環(huán)境變量可以在項(xiàng)目代碼中直接使用
除了自定義的 VUEAPP*變量之外昼榛,還有兩個可用的變量:
- NODE_ENV : "development"境肾、"production" 或 "test"中的一個。具體的值取決于應(yīng)用運(yùn)行的模式胆屿。
- BASE_URL : 和 vue.config.js 中的 publicPath 選項(xiàng)相符奥喻,即你的應(yīng)用會部署到的基礎(chǔ)路徑。
下面開始配置我們的環(huán)境變量
1非迹、在項(xiàng)目根目錄中新建.env.*
- .env.development 本地開發(fā)環(huán)境配置
NODE_ENV='development'
VUE_APP_ENV = 'development'
- env.staging 測試環(huán)境配置
NODE_ENV='production'
VUE_APP_ENV = 'staging'
- env.production 正式環(huán)境配置
NODE_ENV='production'
VUE_APP_ENV = 'production'
為了在不同環(huán)境配置更多的變量环鲤,我們在 src 文件下新建一個 config/index
// 根據(jù)環(huán)境引入不同配置 process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config
在同級目錄下新建 env.development.js,env.test.js彻秆,env.production.js楔绞,在里面配置需要的變量。
以 env.development.js 為例
module.exports = {
baseUrl: 'http://localhost:8089', // 項(xiàng)目地址
baseApi: 'https://www.mock.com/api', // 本地api請求地址
}
2唇兑、配置打包命令
package.json 里的 scripts 不同環(huán)境的打包命令
- 通過 npm run serve 啟動本地
- 通過 npm run test 打包測試
- 通過 npm run build 打包正式
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"test": "vue-cli-service build --mode test",
}
vue.config.js 配置
vue-cli3 開始酒朵,新建的腳手架都需要我們在 vue.config.js 配置我們項(xiàng)目的東西。主要包括
- 打包后文件輸出位置
- 關(guān)閉生產(chǎn)環(huán)境 souecemap
- 配置 rem 轉(zhuǎn)化 px
- 配置 alias 別名
- 去除生產(chǎn)環(huán)境 console
- 跨域代理設(shè)置
此外扎附,還有很多屬于優(yōu)化打包的配置蔫耽,后面會一一道來。
module.exports = {
// 部署應(yīng)用包時的基本URL留夜,默認(rèn)為'/'
publicPath: './',
// 將構(gòu)建好的文件輸出到哪里匙铡,本司要求
outputDir: 'dist/static',
// 放置生成的靜態(tài)資源(js、css碍粥、img鳖眼、fonts)的目錄。
assetsDir: 'static',
// 指定生成的 index.html 的輸出路徑
indexPath: 'index.html',
// 是否使用包含運(yùn)行時編譯器的 Vue 構(gòu)建版本嚼摩。
runtimeCompiler: false,
// 默認(rèn)情況下 babel-loader 會忽略所有 node_modules 中的文件钦讳。如果你想要通過 Babel 顯式轉(zhuǎn)譯一個依賴,可以在這個選項(xiàng)中列出來枕面。
transpileDependencies: [],
// 如果你不需要生產(chǎn)環(huán)境的 source map愿卒,可以將其設(shè)置為 false 以加速生產(chǎn)環(huán)境構(gòu)建。
productionSourceMap: false,
// 配置css
css: {
// 是否使用css分離插件 ExtractTextPlugin
extract: true,
sourceMap: true,
// css預(yù)設(shè)器配置項(xiàng)
loaderOptions: {
postcss: {
// options here will be passed to postcss-loader
plugins: [
require('postcss-px2rem')({
remUnit: 100,
}),
],
},
},
// 啟用 CSS modules for all css / pre-processor files.
modules: false,
},
// 是一個函數(shù)潮秘,允許對內(nèi)部的 webpack 配置進(jìn)行更細(xì)粒度的修改琼开。
chainWebpack: (config) => {
// 配置別名
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
.set('views', resolve('src/views'))
config.optimization.minimizer('terser').tap((args) => {
// 去除生產(chǎn)環(huán)境console
args[0].terserOptions.compress.drop_console = true
return args
})
},
// 是否為 Babel 或 TypeScript 使用 thread-loader。該選項(xiàng)在系統(tǒng)的 CPU 有多于一個內(nèi)核時自動啟用枕荞,僅作用于生產(chǎn)構(gòu)建柜候。
parallel: require('os').cpus().length > 1,
devServer: {
host: '0.0.0.0',
port: 8088, // 端口號
https: false, // https:{type:Boolean}
open: false, // 配置自動啟動瀏覽器 open: 'Google Chrome'-默認(rèn)啟動谷歌
// 配置多個代理
proxy: {
'/api': {
target: 'https://www.mock.com',
ws: true, // 代理的WebSockets
changeOrigin: true, // 允許websockets跨域
pathRewrite: {
'^/api': '',
},
},
},
},
}
基礎(chǔ)組件封裝
在開發(fā)項(xiàng)目過程中搞动,通常會用到很多功能和設(shè)計相類似的組件,toast 和 dialog 組件基本是每一個移動端項(xiàng)目都會用到的改橘。為了更好匹配自己公司的 UI 設(shè)計風(fēng)格滋尉,我們沒有直接用 vant 的 toast 和 dialog 組件,而是自己封裝了類似的組件飞主,可供直接調(diào)用狮惜,如:
this.$toast({ msg: '手機(jī)號碼不能為空' })
this.$toast({
msg: '成功提示',
type: 'success',
})
this.$dialog({
title: '刪除提示',
text: '是否確定刪除此標(biāo)簽?',
showCancelBtn: true,
confirmText: '確認(rèn)',
confirm(content) {
alert('刪除成功')
},
})
效果圖如下
<img src="./static/toast.png">
toast 傳入?yún)?shù)
Props
name | type | default | description |
---|---|---|---|
msg | String | '' | 彈窗提示語 |
type | String | '' | 彈窗類型:success(成功提示),fail(失敗提示),warning(警告),loading(加載) |
dialog 傳入?yún)?shù)
Props
name | type | default | description |
---|---|---|---|
title | String | '' | 標(biāo)題 |
text | String | '' | 文本內(nèi)容 |
type | String | '' | 默認(rèn)純文本碌识,input(輸入框) |
maxlength | Number | 20 | 輸入的最多字?jǐn)?shù) |
confirmText | String | 確定 | 右邊按鈕 |
cancelText | String | 取消 | 左邊按鈕 |
Events
name | params | description |
---|---|---|
confirm | null | 選擇后的回調(diào) |
cancel | ull | 取消后的回調(diào) |
webpack 可視化分析
從這里開始碾篡,我們開始進(jìn)行 webpack 優(yōu)化打包。首先我們來分析一下 webpack 打包性能瓶頸筏餐,找出問題所在开泽,然后才能對癥下藥。此時就用到 webpack-bundle-analyzer 了魁瞪。
1穆律、安裝依賴
npm install webpack-bundle-analyzer -D
2、在 vue.config.js 配置
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(new BundleAnalyzerPlugin())
}
}
打包后导俘,我們可以看到這樣一份依賴圖
<img src="./static/cdn前.png">
從以上的界面中峦耘,我們可以得到以下信息:
- 打包出的文件中都包含了什么,以及模塊之間的依賴關(guān)系
- 每個文件的大小在總體中的占比旅薄,找出較大的文件辅髓,思考是否有替換方案,是否使用了它包含了不必要的依賴少梁?
- 是否有重復(fù)的依賴項(xiàng)洛口,對此可以如何優(yōu)化?
- 每個文件的壓縮后的大小凯沪。
CDN 資源優(yōu)化
CDN 的全稱是 Content Delivery Network
第焰,即內(nèi)容分發(fā)網(wǎng)絡(luò)。CDN 是構(gòu)建在網(wǎng)絡(luò)之上的內(nèi)容分發(fā)網(wǎng)絡(luò)妨马,依靠部署在各地的邊緣服務(wù)器樟遣,通過中心平臺的負(fù)載均衡、內(nèi)容分發(fā)身笤、調(diào)度等功能模塊,使用戶就近獲取所需內(nèi)容葵陵,降低網(wǎng)絡(luò)擁塞液荸,提高用戶訪問響應(yīng)速度和命中率。CDN 的關(guān)鍵技術(shù)主要有內(nèi)容存儲和分發(fā)技術(shù)脱篙。
隨著項(xiàng)目越做越大娇钱,依賴的第三方 npm 包越來越多伤柄,構(gòu)建之后的文件也會越來越大。再加上又是單頁應(yīng)用文搂,這就會導(dǎo)致在網(wǎng)速較慢或者服務(wù)器帶寬有限的情況出現(xiàn)長時間的白屏适刀。此時我們可以使用 CDN 的方法,優(yōu)化網(wǎng)絡(luò)加載速度煤蹭。
1笔喉、將 vue、vue-router硝皂、vuex常挚、axios
這些 vue 全家桶的資源,全部改為通過 CDN 鏈接獲取稽物,在 index.html
里插入 相應(yīng)鏈接奄毡。
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script>
</body>
2、在 vue.config.js
配置 externals 屬性
module.exports = {
···
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'axios':'axios'
}
}
3贝或、卸載相關(guān)依賴的 npm 包
npm uninstall vue vue-router vuex axios
此時啟動項(xiàng)目運(yùn)行就可以了吼过。我們在控制臺就能發(fā)現(xiàn)項(xiàng)目加載了以上四個 CDN 資源。
不過現(xiàn)在有不少聲音說咪奖,vue 全家桶加載 CDN 資源其實(shí)作用并不大盗忱,而且公共的 CDN 資源也沒有 npm 包那么穩(wěn)定,這個就見仁見智了赡艰。所以我在源碼時新建的分支做這個優(yōu)化售淡。當(dāng)項(xiàng)目較小的就不考慮 CDN 優(yōu)化了。
當(dāng)然慷垮,當(dāng)引入其他較大第三方資源揖闸,比如 echarts,AMAP(高德地圖)料身,采用 CDN 資源還是很有必要的汤纸。
gZip 加速優(yōu)化
所有現(xiàn)代瀏覽器都支持 gzip 壓縮,啟用 gzip 壓縮可大幅縮減傳輸資源大小芹血,從而縮短資源下載時間贮泞,減少首次白屏?xí)r間,提升用戶體驗(yàn)幔烛。
gzip 對基于文本格式文件的壓縮效果最好(如:CSS啃擦、JavaScript 和 HTML),在壓縮較大文件時往往可實(shí)現(xiàn)高達(dá) 70-90% 的壓縮率饿悬,對已經(jīng)壓縮過的資源(如:圖片)進(jìn)行 gzip 壓縮處理令蛉,效果很不好。
const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
new CompressionPlugin({
// gzip壓縮配置
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 對超過10kb的數(shù)據(jù)進(jìn)行壓縮
deleteOriginalAssets: false, // 是否刪除原文件
})
)
}
}
首頁添加骨架屏
隨著 SPA 在前端界的逐漸流行,單頁面應(yīng)用不可避免地給首頁加載帶來壓力珠叔,此時良好的首頁用戶體驗(yàn)至關(guān)重要蝎宇。很多 APP 采用了“骨架屏”的方式去展示未加載內(nèi)容,給予了用戶煥然一新的體驗(yàn)祷安。
所謂的骨架屏姥芥,就是在頁面內(nèi)容未加載完成的時候,先使用一些圖形進(jìn)行占位汇鞭,待內(nèi)容加載完成之后再把它替換掉凉唐。在這個過程中用戶會感知到內(nèi)容正在逐漸加載并即將呈現(xiàn),降低了“白屏”的不良體驗(yàn)虱咧。
本文采用 vue-skeleton-webpack-plugin 插件為單頁面應(yīng)用注入骨架屏熊榛。
1、在 src 的 common 文件夾下面創(chuàng)建了 Skeleton1.vue腕巡,Skeleton2.vue玄坦,具體的結(jié)構(gòu)和樣式自行設(shè)計,此處省略一萬字绘沉。煎楣。。车伞。
2择懂、在同級目錄下新建 entry-skeleton.js
import Vue from 'vue'
import Skeleton1 from './Skeleton1'
import Skeleton2 from './Skeleton2'
export default new Vue({
components: {
Skeleton1,
Skeleton2,
},
template: `
<div>
<skeleton1 id="skeleton1" style="display:none"/>
<skeleton2 id="skeleton2" style="display:none"/>
</div>
`,
})
在 vue.config.js 下配置插件
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
configureWebpack: (config) => {
config.plugins.push(
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, './src/common/entry-skeleton.js'),
},
},
minimize: true,
quiet: true,
router: {
mode: 'hash',
routes: [
{ path: '/', skeletonId: 'skeleton1' },
{ path: '/about', skeletonId: 'skeleton2' },
],
},
})
)
}
此時重新加載頁面就可以看到我們的骨架屏了。注意:一定要配置樣式分離 extract: true
使用 SvgIcon 組件
svg 優(yōu)點(diǎn):
- 圖標(biāo)易于實(shí)時修改另玖,可以帶動畫
- 可以使用標(biāo)磚的 prop 和默認(rèn)值來將圖標(biāo)保持在一個典型的尺寸并隨時按需改變他們
- 圖標(biāo)是內(nèi)聯(lián)的困曙,所以不需要額外的 HTTP 請求
- 可以動態(tài)地使得圖標(biāo)可訪問
通常我們項(xiàng)目都是使用 iconfont 阿里巴巴圖標(biāo)矢量庫,但是操作比較麻煩谦去,每次更新都要重新下載鏈接慷丽。另外我們可以使 svg-sprite-loader 實(shí)現(xiàn)。
1鳄哭、新增 SvgIcon 組件
<template>
<svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true,
},
},
computed: {
iconName() {
return `#icon-${this.iconClass}`
},
},
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
2要糊、全局注冊組件并導(dǎo)入 svg
import SvgIcon from './SvgIcon.vue'
import Vue from 'vue'
// 注冊到全局
Vue.component('svg-icon', SvgIcon)
const requireAll = (requireContext) => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
3、在 main.js 中引入
import './components/icon'
4妆丘、配置 vue.config.js
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule.exclude.add(/node_modules/)
svgRule
.test(/\.svg$/)
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
})
const imagesRule = config.module.rule('images')
imagesRule.exclude.add(resolve('src/icons'))
config.module.rule('images').test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
},
}