本文是轉載文章,轉載自掘金https://juejin.im/post/5e475829f265da57444ab10f
本文會從以下三個方面,來進階我們對vue
的運用能力
組件
: 全局組件註冊Render函數
: 拯救繁亂的templateVue權限控制
: 高精度全局權限控制
1 -「全局組件註冊」
組件是我們非常常用的東西,很多人使用組件都是通過一個一個文件去引用和註冊。如果一個組件在整個項目裏面的使用次數較多,每一次使用都需要引用並註冊,就會顯得特別麻煩
- 一般組件應用弊端
- 傻瓜式,太笨拙
- 繁瑣,低效
<template>
<div>
<h1>I am HelloWorld</h1>
<Child1></Child1>
</div>
</template>
<script>
import Child1 from './child1.vue' // 引入
export default {
name: 'HelloWorld',
data(){
return{
}
},
components:{ // 註冊
Child1
},
props: {
msg: String
},
methods:{
}
}
</script>
<style scoped lang="less">
</style>
複製代碼
當我們在項目需要重複多次使用該組件,會導致出現很多重複的引入和註冊代碼,既繁瑣又不雅觀。因此我們可以通過一個全局的Js
文件來管理,將需要多次使用的組件進行全局註冊
創建全局.js
文件管理全局組件
// 1 - globalComponent.js
import Vue from 'vue' // 引入vue
// 處理首字母大寫 abc => Abc
function changeStr(str){
return str.charAt(0).toUpperCase() + str.slice(1)
}
/*
require.context(arg1,arg2,arg3)
arg1 - 讀取文件的路徑
arg2 - 是否遍歷文件的子目錄
arg3 - 匹配文件的正則
關於這個Api的用法,建議小夥伴們去查閱一下,用途也比較廣泛
*/
const requireComponent = require.context('.', false, /\.vue$/)
console.log('requireComponent.keys():',requireComponent.keys()) // 打印
requireComponent.keys().forEach(fileName => {
const config = requireComponent(fileName)
console.log('config:',config) // 打印
const componentName = changeStr(
fileName.replace(/^\.\//, '').replace(/\.\w+$/, '') // ./child1.vue => child1
)
Vue.component(componentName, config.default || config) // 動態註冊該目錄下的所有.vue文件
})
複製代碼
// 2 - 將globalComponent.js引入main.js
import global from './components/globalComponent'
複製代碼
// 3 - 使用這類組件不再需要引入和註冊,直接標籤使用即可
<template>
<div>
<h1>I am HelloWorld</h1>
<Child1></Child1>
</div>
</template>
複製代碼
運行程序,我們看下是否能夠正常顯示並分析兩句打印
Extra: 路由分區以及動態添加路由
假設我們有很多路由,每一個路由都通過傻瓜式的引入方式,會導致整個項目代碼量增多,繁瑣,更重要的一點是增加後期維護的難度。因此我們也可以通過上面類似的方式,對路由的引入和使用進行管理,實現分區引入路由,將不同功能下的路由進行區分,通過動態的方式進行引入,即方便快捷又增加可維護
創建專門的路由.js
文件管理所有的路由
總路由管理文件 - index.js
分區路由
- index.routes.js
- login.routes.js
在大型項目中,往往會有很多互不關聯的模塊,例如電商平臺中的商城,個人信息,這種情況下就可以對路由進行分區
複製代碼
// 分區路由文件寫法
export default {
path:'/index',
name:'Index',
component: () => import('../views/Index.vue'), // 懶加載式引入,當跳轉到時才進行引入chunk
children: [...]
}
複製代碼
// 總路由管理文件 index.js 寫法
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routerList = [] // 路由數組 - 存放所有路由
function importAll(routerArr){
// 該函數用於將所有分區路由中的路由添加到路由數組
routerArr.keys().forEach( key => {
console.log(key)
routerList.push((key).default)
})
}
importAll(require.context('.',true,/\.routes\.js/))
const routes = [
...routerList
]
const router = new VueRouter({
routes
})
export default router
複製代碼
運行程序,我們看下是否能夠正常顯示並分析兩句打印
優化之後的代碼,會更靈活,更具有觀賞性,既便捷高效,又方便維護
2 -「拯救繁亂的template」
很多人在寫組件的時候,會依賴腳手架中的<template></template>
標籤,其實template
也存在一定的缺陷,例如:
template
裏存在一值多判斷- 過多使用
template
會使代碼冗餘,雜亂
VUE
給我們提供了一個render
函數,我們可以通過這個函數巧妙的解決template
造成的問題
實戰 - 處理多個button
<template>
<div>
<h1>I am Home</h1>
<!-- 假設按鈕有多種類型,通過value來顯示不同類型 -->
<div v-if='value === 1'>
<button>button1</button>
</div>
<div v-else-if='value === 2'>
<button>button2</button>
</div>
<div v-else>
<button>button3</button>
</div>
</div>
</template>
<script>
export default {
name: 'Home',
data(){
return{
value:1
}
},
methods:{
}
}
</script>
<style scoped lang="less">
</style>
複製代碼
上面這種寫法,當出現多種類型的button,就會顯得雜亂無章,當然,很多人會選擇去封裝一個button組件,那麼這個組件的封裝,又是一個技巧點,利用VUE
的render
函數,減少不必要的template
,因此ru我們可以這樣寫
// 創建一個button.vue文件 寫法如下
<script>
export default {
props:{
type:{
type:String,
default:'normal'
},
text:{
type:String,
default:'button'
}
},
render(h){
/*
h 類似於 createElement, 接受2個參數
1 - 元素
2 - 選項
*/
return h('button',{
// 相當於 v-bind:class
class:{
btn:true,
'btn-success':this.type === 'success',
'btn-danger':this.type === 'danger',
'btn-warning':this.type === 'warning',
'btn-normal':this.type === 'normal',
},
domProps:{
innerText: this.text || '默認'
},
on:{
click:this.handleClick
}
})
},
methods:{
handleClick(){
this.$emit('myClick')
}
}
}
</script>
<style scoped>
.btn{
width: 100px;
height:40px;
line-height:40px;
border:0px;
border-radius:5px;
color:#ffff;
}
.btn-success{
background:#2ecc71;
}
.btn-danger{
background:#e74c3c;
}
.btn-warning{
background:#f39c12;
}
.btn-normal{
background:#bdc3c7;
}
</style>
複製代碼
// 引入
<template>
<div>
<h1>I am Home</h1>
<!-- 按鈕根據value顯示不同類型的button -->
<Button type='success' text='button1' @myClick='...'></Button>
</div>
</template>
<script>
import Button from './button.vue'
export default {
name: 'Home',
data(){
return{
value:1
}
},
components:{
Button
},
methods:{
}
}
</script>
<style scoped lang="less">
</style>
複製代碼
上面這種寫法,根據value
來顯示不同類型的button
,我們只需要通過value
去修改type,text
等,就可以實現這一目的,而不需要去創建多個<button>
,通過v-if
去判斷
優化之後的代碼,避免了一值多判斷的缺點,減少冗餘,更加靈活, 這種方式較適合業務簡單,使用次數多的組件
3 -「高精度全局權限處理」
權限的控制由前端處理的場景很多,例如根據後臺返回內容,判斷該人是否對此功能有權限,進而去修改元素
v-if / v-show
,這種情況下,當這個功能在多處地方出現,就會導致我們做很多很多不必要的重複代碼,如果判斷條件繁瑣的情況,更加冗餘,代碼量也會增加很多。因此我們可以造一個小車輪,掛在全局上對權限進行處理
實戰 - 處理某按鈕顯示權限問題
這種場景出現機率極高,尤其是處理含有多種角色的項目,如果這一類型的權限判斷有多次處理,每一次出現都經歷判斷的話,代碼將會異常難看且冗餘,因此我們可以通過全局權限判斷來處理
/*
在項目裏新建一個common文件夾用於存放全局 .js 文件
這種全局文件夾做法相當普遍,一般項目裏都應該有這樣一個文件夾來管理全局的東西
*/
// common/jurisdiction.js 用於存放與權限相關的全局函數/變量
export function checkJurisdiction(key) {
// 權限數組
let jurisdictionList = ['1', '2', '3', '5']
let index = jurisdictionList.indexOf(key)
console.log('index:',index)
if (index > -1) {
// 有權限
return true
} else {
// 無權限
return false
}
}
複製代碼
// 將全局權限Js掛載到全局中
// main.js
import { checkJurisdiction } from './common/jurisdiction'
// 優雅操作 - VUE自定義指令
Vue.directive('permission',{
inserted(el, binding){
// inserted → 元素插入的時候
let permission = binding.value // 獲取到 v-permission的值
if(permission){
let hasPermission = checkJurisdiction(permission)
if(!hasPermission){
// 沒有權限 移除Dom元素
el.parentNode && el.parentNode.removeChild(el)
}
}else{
throw new Error('需要傳key')
}
}
})
複製代碼
// 使用方式
<template>
<div>
<h1>I am Home</h1>
<!-- 按鈕根據value -->
<div v-permission="'10'">
<button>權限1</button>
</div>
<div v-permission="'5'">
<button>權限2</button>
</div>
</div>
</template>
// 無需再通過value去判斷,直接通過v-permission的值進行判斷即可
複製代碼
運行程序,我們看下是否能夠正常顯示並分析打印
可以看到 v-permission = "'10'"
是沒有權限且不顯示,v-permission = "'5'"
是具有權限且顯示
總結
以上三個方面操作起來看似簡單,但很多人在寫代碼的時候,喜歡停留在業務上,只考慮能否實現,實際上,很多大型項目都需要有這些理念去減少代碼量,減少冗餘,在合適的場景下使用合適的方法才能提高自己的能力