Vue中使用裝飾器的方法詳解
前言
相信各位在開發(fā)中一定遇到過二次彈框確認(rèn)相關(guān)的需求。不管你使用的是UI框架的二次彈框組件,還是自己封裝的彈框組件。都避免不了在多次使用時(shí)出現(xiàn)大量重復(fù)代碼的問題。這些代碼的積累導(dǎo)致項(xiàng)目的可讀性差。項(xiàng)目的代碼質(zhì)量也變得很差。那么我們?nèi)绾谓鉀Q二次彈框代碼重復(fù)的問題呢?使用裝飾器
什么是裝飾器?
Decorator是ES7的一個(gè)新語法。Decorator通過對(duì)類、對(duì)象、方法、屬性進(jìn)行修飾。對(duì)其添加一些其他的行為。通俗來說:就是對(duì)一段代碼進(jìn)行二次包裝。
裝飾器的使用
使用方法很簡(jiǎn)單 我們定義一個(gè)函數(shù)
const decorator = (target, name, descriptor) => {
var oldValue = descriptor.value;
descriptor.value = function(){
alert('哈哈')
return oldValue.apply(this,agruments)
}
return descriptor
}
// 然后直接@decorator到函數(shù)、類或者對(duì)象上即可。裝飾器的目的旨在對(duì)代碼進(jìn)行復(fù)用。下面我們先來一個(gè)小例子看看
js中使用裝飾器
//定義一個(gè)裝飾器
const log = (target, name, descriptor) => {
var oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling ${name} with`, arguments);
return oldValue.apply(this, arguments);
};
return descriptor;
}
//計(jì)算類
class Calculate {
//使用裝飾器
@log()
function subtraction(a,b){
return a - b
}
}
const operate = new Calculate()
operate.subtraction(5,2)不使用裝飾器
const log = (func) => {
if(typeof(func) !== 'function') {
throw new Error(`the param must be a function`);
}
return (...arguments) => {
console.info(`${func.name} invoke with ${arguments.join(',')}`);
func(...arguments);
}
}
const subtraction = (a, b) => a + b;
const subtractionLog = log(subtraction);
subtractionLog(10,3); 這樣一對(duì)比你會(huì)發(fā)現(xiàn)使用裝飾器后代碼的可讀性變強(qiáng)了。裝飾器并不關(guān)心你內(nèi)部代碼的實(shí)現(xiàn)。
vue 中使用裝飾器
如果你的項(xiàng)目是用vue-cli搭建的 并且vue-cli的版本大于2.5 那么你無需進(jìn)行任何配置即可使用。如果你的項(xiàng)目還包含eslit 那么你需要在eslit中開啟支持裝飾器相關(guān)的語法檢測(cè)
//在 eslintignore中添加或者修改如下代碼:
parserOptions: {
ecmaFeatures:{
// 支持裝飾器
legacyDecorators: true
}
}加上這段代碼之后eslit就支持裝飾器語法了。
通常在項(xiàng)目中我們經(jīng)常會(huì)使用二次彈框進(jìn)行刪除操作:
//decorator.js
//假設(shè)項(xiàng)目中已經(jīng)安裝了 element-ui
import { MessageBox, Message } from 'element-ui'
/**
* 確認(rèn)框
* @param {String} title - 標(biāo)題
* @param {String} content - 內(nèi)容
* @param {String} confirmButtonText - 確認(rèn)按鈕名稱
* @param {Function} callback - 確認(rèn)按鈕名稱
* @returns
**/
export function confirm(title, content, confirmButtonText = '確定') {
return function(target, name, descriptor) {
const originValue = descriptor.value
descriptor.value = function(...args) {
MessageBox.confirm(content, title, {
dangerouslyUseHTMLString: true,
distinguishCancelAndClose: true,
confirmButtonText: confirmButtonText
}).then(originValue.bind(this, ...args)).catch(error => {
if (error === 'close' || error === 'cancel') {
Message.info('用戶取消操作'))
} else {
Message.info(error)
}
})
}
return descriptor
}
}如上代碼 confirm方法里執(zhí)行了一個(gè)element-ui中的MessageBox組件 當(dāng)用戶取消時(shí) Message組件會(huì)提示用戶取消了操作。
我們?cè)趖est()方法上用裝飾器修飾一下
import { confirm } from '@/util/decorator'
import axios form 'axios'
export default {
name:'test',
data(){
return {
delList: '/merchant/storeList/commitStore'
}
}
},
methods:{
@confirm('刪除門店','請(qǐng)確認(rèn)是否刪除門店?')
test(id){
const {res,data} = axios.post(this.delList,{id})
if(res.rspCd + '' === '00000') this.$message.info('操作成功!')
}
}此時(shí)用戶點(diǎn)擊某個(gè)門店進(jìn)行刪除。裝飾器將會(huì)起作用。彈出如下圖所示:

當(dāng)我點(diǎn)擊取消時(shí):

tips: 用戶取消了操作.被修飾的test方法不會(huì)執(zhí)行。
當(dāng)我們點(diǎn)擊確定時(shí):

接口被調(diào)用了 并且彈出了message
一些常用的裝飾器
下面小編羅列了幾個(gè)小編在項(xiàng)目中常用的幾個(gè)裝飾器,方便大家使用
1. 函數(shù)節(jié)流與防抖
函數(shù)節(jié)流與防抖應(yīng)用場(chǎng)景是比較廣的,一般使用時(shí)候會(huì)通過throttle或debounce方法對(duì)要調(diào)用的函數(shù)進(jìn)行包裝,現(xiàn)在就可以使用上文說的內(nèi)容將這兩個(gè)函數(shù)封裝成裝飾器, 防抖節(jié)流使用的是lodash提供的方法,大家也可以自行實(shí)現(xiàn)節(jié)流防抖函數(shù)哦
import { throttle, debounce } from 'lodash'
/**
* 函數(shù)節(jié)流裝飾器
* @param {number} wait 節(jié)流的毫秒
* @param {Object} options 節(jié)流選項(xiàng)對(duì)象
* [options.leading=true] (boolean): 指定調(diào)用在節(jié)流開始前。
* [options.trailing=true] (boolean): 指定調(diào)用在節(jié)流結(jié)束后。
*/
export const throttle = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = throttle(descriptor.value, wait, options)
}
}
/**
* 函數(shù)防抖裝飾器
* @param {number} wait 需要延遲的毫秒數(shù)。
* @param {Object} options 選項(xiàng)對(duì)象
* [options.leading=false] (boolean): 指定在延遲開始前調(diào)用。
* [options.maxWait] (number): 設(shè)置 func 允許被延遲的最大值。
* [options.trailing=true] (boolean): 指定在延遲結(jié)束后調(diào)用。
*/
export const debounce = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = debounce(descriptor.value, wait, options)
}
}封裝完之后,在組件中使用
import {debounce} from '@/decorator'
export default {
methods:{
@debounce(100)
resize(){}
}
}2. loading
在加載數(shù)據(jù)的時(shí)候,為了個(gè)用戶一個(gè)友好的提示,同時(shí)防止用戶繼續(xù)操作,一般會(huì)在請(qǐng)求前顯示一個(gè)loading,然后在請(qǐng)求結(jié)束之后關(guān)掉loading,一般寫法如下
export default {
methods:{
async getData() {
const loading = Toast.loading()
try{
const data = await loadData()
// 其他操作
}catch(error){
// 異常處理
Toast.fail('加載失敗');
}finally{
loading.clear()
}
}
}
}我們可以把上面的loading的邏輯使用裝飾器重新封裝,如下代碼
import { Toast } from 'vant'
/**
* loading 裝飾器
* @param {*} message 提示信息
* @param {function} errorFn 異常處理邏輯
*/
export const loading = function(message = '加載中...', errorFn = function() {}) {
return function(target, name, descriptor) {
const fn = descriptor.value
descriptor.value = async function(...rest) {
const loading = Toast.loading({
message: message,
forbidClick: true
})
try {
return await fn.call(this, ...rest)
} catch (error) {
// 在調(diào)用失敗,且用戶自定義失敗的回調(diào)函數(shù)時(shí),則執(zhí)行
errorFn && errorFn.call(this, error, ...rest)
console.error(error)
} finally {
loading.clear()
}
}
}
}然后改造上面的組件代碼
export default {
methods:{
@loading('加載中')
async getData() {
try{
const data = await loadData()
// 其他操作
}catch(error){
// 異常處理
Toast.fail('加載失敗');
}
}
}
}3. 確認(rèn)框
當(dāng)你點(diǎn)擊刪除按鈕的時(shí)候,一般都需要彈出一個(gè)提示框讓用戶確認(rèn)是否刪除,這時(shí)候常規(guī)寫法可能是這樣的
import { Dialog } from 'vant'
export default {
methods: {
deleteData() {
Dialog.confirm({
title: '提示',
message: '確定要?jiǎng)h除數(shù)據(jù),此操作不可回退。'
}).then(() => {
console.log('在這里做刪除操作')
})
}
}
}我們可以把上面確認(rèn)的過程提出來做成裝飾器,如下代碼
import { Dialog } from 'vant'
/**
* 確認(rèn)提示框裝飾器
* @param {*} message 提示信息
* @param {*} title 標(biāo)題
* @param {*} cancelFn 取消回調(diào)函數(shù)
*/
export function confirm(
message = '確定要?jiǎng)h除數(shù)據(jù),此操作不可回退。',
title = '提示',
cancelFn = function() {}
) {
return function(target, name, descriptor) {
const originFn = descriptor.value
descriptor.value = async function(...rest) {
try {
await Dialog.confirm({
message,
title: title
})
originFn.apply(this, rest)
} catch (error) {
cancelFn && cancelFn(error)
}
}
}
}然后再使用確認(rèn)框的時(shí)候,就可以這樣使用了
export default {
methods: {
// 可以不傳參,使用默認(rèn)參數(shù)
@confirm()
deleteData() {
console.log('在這里做刪除操作')
}
}
}是不是瞬間簡(jiǎn)單多了,當(dāng)然還可以繼續(xù)封裝很多很多的裝飾器
總結(jié)
裝飾器用于將一段代碼進(jìn)行二次包裝。給代碼增加一些行為操作和屬性。 使用裝飾器能大大減少代碼的重復(fù)。增強(qiáng)代碼可讀性。
到此這篇關(guān)于Vue中使用裝飾器的文章就介紹到這了,更多相關(guān)Vue使用裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于vue-cli創(chuàng)建的項(xiàng)目的目錄結(jié)構(gòu)及說明介紹
下面小編就為大家分享一篇基于vue-cli創(chuàng)建的項(xiàng)目的目錄結(jié)構(gòu)及說明介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-11-11
vue項(xiàng)目下載文件重命名監(jiān)測(cè)進(jìn)度demo
這篇文章主要為大家介紹了vue項(xiàng)目下載文件重命名監(jiān)測(cè)進(jìn)度demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Vue3全局掛載使用Axios學(xué)習(xí)實(shí)戰(zhàn)
這篇文章主要為大家介紹了Vue3全局掛載使用Axios學(xué)習(xí)實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
elementui使用el-upload組件如何實(shí)現(xiàn)自定義上傳
這篇文章主要介紹了elementui使用el-upload組件如何實(shí)現(xiàn)自定義上傳,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
vue?el-table實(shí)現(xiàn)動(dòng)態(tài)添加行和列具體代碼
最近遇到一個(gè)動(dòng)態(tài)增加行和列的需求,所以這里給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于vue?el-table實(shí)現(xiàn)動(dòng)態(tài)添加行和列的相關(guān)資料,需要的朋友可以參考下2023-09-09
Vue.directive 實(shí)現(xiàn)元素scroll邏輯復(fù)用
這篇文章主要介紹了Vue.directive 實(shí)現(xiàn)元素scroll邏輯復(fù)用功能,文中給大家提到元素實(shí)現(xiàn)滾動(dòng)的條件有兩個(gè),具體內(nèi)容詳情大家參考下本文2019-11-11

