Vue項(xiàng)目中最新用到的一些實(shí)用小技巧
寫(xiě)在前面
在最近的 Vue 項(xiàng)目中,為了完成需求使用了一些小技巧,做個(gè)筆記,或許也能幫到道友。
閱讀重點(diǎn)
需求一:為路徑配置別名
在開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要引入各種文件,如圖片、CSS、JS等,為了避免寫(xiě)很長(zhǎng)的相對(duì)路徑(../),我們可以為不同的目錄配置一個(gè)別名。
找到 webpack.base.config.js 中的 resolve 配置項(xiàng),在其 alias 中增加別名,如下:
創(chuàng)建一個(gè) CSS 文件,隨便寫(xiě)點(diǎn)樣式:
.avatar display: flex; justify-content: center; align-items: center; .avatar-img padding 20px border solid 1px #ccc border-radius 5px
接著,在我們需要引入的文件中就可以直接使用了:
<template>
<div class="avatar">
<img class="avatar-img" src="~img/avatar.png" alt="">
</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style scoped lang="stylus">
@import "~css/avatar";
</style>
需要注意的是,如果不是通過(guò) import 引入則需要在別名前加上 ~,效果如下:

需求二:要求實(shí)現(xiàn)在生產(chǎn)包中直接修改api地址
這個(gè)需求,怎么說(shuō)呢,反正就是需求,就想辦法實(shí)現(xiàn)吧。
假設(shè)有一個(gè) apiConfig.js 文件,用于對(duì) axios 做一些配置,如下:
import axios from 'axios';
axios.defaults.timeout = 10000;
axios.defaults.retry = 3;
axios.defaults.retryDelay = 2000;
axios.defaults.responseType = 'json';
axios.defaults.withCredentials = true;
axios.defaults.headers.post["Content-type"] = "application/json";
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
export default axios
在 static 文件夾中增加一個(gè) config.json 文件,用于統(tǒng)一管理所有的 api 地址:
{
"base": "/api",
"static": "http://static.com/api",
"news": "http://news.com.api"
}
打開(kāi) main.js,寫(xiě)入下列代碼:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from 'js/apiConfig'; //import直接引入,不用添加~
Vue.config.productionTip = false;
Vue.use(ElementUI);
/* eslint-disable no-new */
let startApp = function () {
let randomStamp = new Date().getTime();
axios.get(`/static/config.json?t=${randomStamp}`).then((data) => {
axios.defaults.baseURL = data.base; //設(shè)置一個(gè)默認(rèn)的根路徑
Vue.prototype.$axios = axios;
Vue.prototype.$apiURL = data; //將所有路徑配置掛載到 Vue 原型上
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>'
});
})
};
startApp();
就是先用 axios 獲取 api 文件,然后再初始化。
需求三:由后臺(tái)根據(jù)用戶(hù)權(quán)限值返回菜單
菜單是樹(shù)形結(jié)構(gòu)(PS:就算不是樹(shù)形結(jié)構(gòu),你也得處理成樹(shù)形結(jié)構(gòu)),我這里使用的是 ElementUI ,參考了道友的這篇文章,實(shí)現(xiàn)如下:
新建一個(gè) Menu.vue 文件,寫(xiě)入如下代碼:
<script>
export default {
name: "MenuItem",
props: {
data: {
type: Array
},
collapse: {
type: Boolean
}
},
methods: {
//生成菜單項(xiàng)
createMenuItem(data, createElement) {
return data.map(item => {
if (item.children && item.children.length) {
return createElement('el-submenu', {props: {index: item.id.toString()}},
[
createElement('template', {slot: 'title'}, [
createElement('i', {class: item.icon}),
createElement('span', [item.title]),
]
),
this.createMenuItem(item.children, createElement) //遞歸
]
)
} else {
return createElement('el-menu-item', {props: {index: item.path}},
[
createElement('i', {class: item.icon}),
createElement('span', {slot: 'title'}, [item.title]),
]
)
}
})
},
//選中菜單
onSelect(key, keyPath) {
console.log(key, keyPath);
}
},
render(createElement) {
return createElement(
'el-menu',
{
props: {
backgroundColor: "#545c64",
textColor: "#fff",
activeTextColor: "#ffd04b",
collapse: this.collapse,
router:true
},
class:'el-menu-vertical-demo',
on: {
select: this.onSelect
}
},
this.createMenuItem(this.data, createElement)
)
}
}
</script>
<style scoped lang="stylus">
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
這里主要用到兩個(gè)東西,一個(gè)是 render 函數(shù),一個(gè)是遞歸,如果不熟悉 render 函數(shù)的道友請(qǐng)點(diǎn)這里??赡苡械烙褧?huì)問(wèn)為什么不用模板,因?yàn)椤ぁぁぁぁぁぷ霾坏桨?#128557;,在 template 中只能有一個(gè)根元素,而 Vue 限制了不能對(duì)根元素使用 v-for;再者,通過(guò)在瀏覽器中查看代碼可以知道,菜單就是 ul 加上 li,如果有了根元素會(huì)破壞標(biāo)簽結(jié)構(gòu)(雖然不影響功能,但還是覺(jué)得不舒服😂)。然后,在需要使用的地方:
<template>
<el-container>
<el-aside width="auto">
<Menu :data="menu" :collapse="isCollapsed"></Menu>
</el-aside>
<el-container>
<el-header>
<el-button type="text" icon="el-icon-d-arrow-left"
@click="isCollapsed=!isCollapsed"></el-button>
<h3>MenuName</h3>
<span>MeFelixWang</span>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
import Menu from '@/components/Menu';
export default {
name: 'App',
data() {
return {
menu: [
{
title: '導(dǎo)航一',
id: 1,
path: '',
icon: 'el-icon-search',
children: [
{
title: '導(dǎo)航一杠一', id: 2, path: '', icon: '', children: [
{title: '導(dǎo)航一杠一杠一', id: 4, path: '/test', icon: '', children: []},
{
title: '導(dǎo)航一杠一杠二', id: 5, path: '', icon: '', children: [
{title: '導(dǎo)航一杠一杠二杠一', id: 6, path: '/6', icon: '', children: []},
{title: '導(dǎo)航一杠一杠二杠二', id: 7, path: '/7', icon: '', children: []},
]
},
]
},
{title: '導(dǎo)航一杠二', id: 3, path: '/3', icon: '', children: []}
]
},
{title: '導(dǎo)航二', id: 8, path: '/8', icon: 'el-icon-setting', children: []},
{title: '導(dǎo)航三', id: 9, path: '/9', icon: 'el-icon-document', children: []},
{
title: '導(dǎo)航四', id: 10, path: '', icon: 'el-icon-date', children: [
{title: '導(dǎo)航四杠一', id: 11, path: '/11', icon: '', children: []},
{
title: '導(dǎo)航四杠二', id: 12, path: '', icon: '', children: [
{title: '導(dǎo)航四杠二杠一', id: 14, path: '/14', icon: '', children: []}
]
},
{title: '導(dǎo)航四杠三', id: 13, path: '/13', icon: '', children: []},
]
},
],
isCollapsed: false
}
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
components: {
Menu
}
}
</script>
<style lang="stylus">
*
margin 0
padding 0
html, body, .el-container, .el-aside
height 100%
.el-aside
background-color rgb(84, 92, 100)
.el-menu
border-right solid 1px rgb(84, 92, 100)
.el-header
display flex
justify-content space-between
align-items center
background-color aliceblue
.el-button--text
color: #606266;
i
font-weight bold
</style>
效果如下:

需求四:這個(gè) Select 選項(xiàng)是樹(shù)形結(jié)構(gòu),一定得是樹(shù)形結(jié)構(gòu)
樹(shù)形結(jié)構(gòu)就樹(shù)形結(jié)構(gòu)吧,不就是樣式嘛,改改應(yīng)該就可以了。
<template>
<div>
<el-select v-model="tree" placeholder="請(qǐng)選擇活動(dòng)區(qū)域">
<el-option v-for="(item,index) in options" :key="index" :label="item.label" :value="item.id"
:style="{paddingLeft:(item.level*10+20)+'px'}" :class="item.level?'is-sub':''"></el-option>
</el-select>
選擇的是:{{tree}}
</div>
</template>
<script>
export default {
name: "Home",
data() {
return {
tree: '',
options: [],
originData: [
{
label: '這是根一', id: 1, children: [
{label: '這是莖一一', id: 2, children: []},
{label: '這是莖一二', id: 3, children: []},
{
label: '這是莖一三', id: 4, children: [
{label: '這是葉一三一', id: 6, children: []},
{label: '這是葉一三二', id: 7, children: []},
]
},
{label: '這是莖一四', id: 5, children: []},
]
},
{
label: '這是根二', id: 8, children: [],
},
{
label: '這是根三', id: 9, children: [
{label: '這是莖三一', id: 10, children: []},
{
label: '這是莖三二', id: 11, children: [
{label: '這是葉三二一', id: 12, children: []}
]
},
],
},
]
}
},
created() {
this.options = this.decomposeTree(this.originData, 0);
},
methods: {
//分解樹(shù)形結(jié)構(gòu)
decomposeTree(array, level) {
let tmpArr = [];
(function decompose(arr, lev) {
for (let i = 0; i < arr.length; i++) {
let tmpObj = {};
let item = arr[i];
item.level = lev;
tmpObj = Object.assign({}, item);
tmpArr.push(tmpObj);
if (item.children) {
decompose(item.children, lev + 1); //遞歸
}
delete tmpObj.children; //刪掉其 children,避免數(shù)據(jù)過(guò)大(不刪也可以,也許后面有用呢)
}
})(array, level);
return tmpArr;
}
}
}
</script>
<style scoped lang="stylus">
.is-sub:before
content '- '
</style>
因?yàn)?option 接收的是一個(gè)一維數(shù)組,所以通過(guò)遞歸展平樹(shù)形結(jié)構(gòu),在展平的時(shí)候設(shè)置每項(xiàng)的層級(jí),通過(guò)層級(jí)來(lái)設(shè)置縮進(jìn)及前綴符號(hào),效果如下:

之所以這樣做,是因?yàn)槭枪芾硐到y(tǒng),簡(jiǎn)單有效,沒(méi)必要因?yàn)檫@一個(gè)組件引個(gè)新的插件或者自己寫(xiě)一個(gè)(以后用得著的除外哈);也可以用 input 加上 tree 控件來(lái)模擬(PS:最終還是引入了一個(gè)插件,哈哈😂)。
最后叨叨
本文是我最近用到的一些小技巧,如果道友們有更好的實(shí)現(xiàn)方法,歡迎在評(píng)論區(qū)留言討論,文中錯(cuò)誤也歡迎指出,共同學(xué)習(xí)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
vue項(xiàng)目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具
這篇文章主要為大家介紹了vue項(xiàng)目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具的踩坑分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè)
這篇文章主要介紹的是如何用Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè),主要是做個(gè)簡(jiǎn)單的點(diǎn)名器,不做樣式,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12
element-ui 上傳圖片后清空?qǐng)D片顯示的實(shí)例
今天小編就為大家分享一篇element-ui 上傳圖片后清空?qǐng)D片顯示的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
京東 Vue3 組件庫(kù)支持小程序開(kāi)發(fā)的詳細(xì)流程
這篇文章主要介紹了京東 Vue3 組件庫(kù)支持小程序開(kāi)發(fā)的詳細(xì)流程,通過(guò)引入NutUI,即可在項(xiàng)目中使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-06-06
vue 使用localstorage實(shí)現(xiàn)面包屑的操作
這篇文章主要介紹了vue 使用localstorage實(shí)現(xiàn)面包屑的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
Vue移動(dòng)端項(xiàng)目實(shí)現(xiàn)使用手機(jī)預(yù)覽調(diào)試操作
這篇文章主要介紹了Vue移動(dòng)端項(xiàng)目實(shí)現(xiàn)使用手機(jī)預(yù)覽調(diào)試操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
vue iview的菜單組件Mune 點(diǎn)擊不高亮的解決方案
今天小編就為大家分享一篇vue iview的菜單組件Mune 點(diǎn)擊不高亮的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11

