如何優雅的使用VUE? 如何讓自己與剛學vue的人拉開差距呢?

本文是轉載文章,轉載自掘金https://juejin.im/post/5e475829f265da57444ab10f

 


本文會從以下三個方面,來進階我們對vue的運用能力

 

  • 組件 : 全局組件註冊
  • Render函數 : 拯救繁亂的template
  • Vue權限控制 : 高精度全局權限控制

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組件,那麼這個組件的封裝,又是一個技巧點,利用VUErender函數,減少不必要的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'"是具有權限且顯示

 


總結

以上三個方面操作起來看似簡單,但很多人在寫代碼的時候,喜歡停留在業務上,只考慮能否實現,實際上,很多大型項目都需要有這些理念去減少代碼量,減少冗餘,在合適的場景下使用合適的方法才能提高自己的能力


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章