三步帶你玩轉前端裝飾器
什么是裝飾器 裝飾器怎么封裝 裝飾器能干啥
1、什么是裝飾器
看個例子就懂了eg:
正常開發(fā)是這樣的:
1、先定義節(jié)流方法:
methods: {
throttle (func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
}
2、然后執(zhí)行A方法:
methods: {
a() {
this.throttle(()=>{
//執(zhí)行業(yè)務邏輯
}, 400)
}
}反正就是各種嵌套,看起來代碼很膿腫,接下來看看【裝飾器】怎么寫↓
//使用裝飾器過后的寫法
import { throttle} from "@/utils/decorator";
methods: {
@throttle(400) // 裝飾器(節(jié)流)
a() {
// 執(zhí)行業(yè)務邏輯
//此時會發(fā)現點擊效果跟上面寫法一樣
console.log('執(zhí)行業(yè)務')
},
}
現在看到的寫法是不是涼快了很多,沒有多層嵌套
2、裝飾器怎么封裝
1、在工具文件創(chuàng)建decorator.js
// utils/decorator.js
/**
* 節(jié)流,一定時間內,只能觸發(fā)一次操作
* @export
* @param {Function} fn - 運行函數
* @param {Number} wait - 延遲時間
* @returns
*/
export function throttle(wait = 2000) {
//返回值:被傳遞給函數的對象。
return function(target, name, descriptor) {
// @param target 類本身
// @param name 裝飾的屬性(方法)名稱
// @param descriptor 屬性(方法)的描述對象
const fn = descriptor.value
let canRun = true
descriptor.value = async function(...args) {
//具體的裝飾器業(yè)務在這里面編寫
if (!canRun) return
await fn.apply(this, args) // 執(zhí)行業(yè)務下的方法
canRun = false
setTimeout(() => {
canRun = true
}, wait)
}
}
}
2、在業(yè)務板塊里面聲明使用
methods: {
@throttle(400) // 裝飾器(節(jié)流)
a() {
// 執(zhí)行業(yè)務邏輯
//此時會發(fā)現點擊效果跟上面寫法一樣
console.log('執(zhí)行業(yè)務')
},
}
//現在看到代碼是不是就沒有那么膿腫了,就一行指令3、裝飾器能干啥
現實開發(fā)中經常遇到節(jié)流,防抖,日志,按鈕權限等等一些業(yè)務執(zhí)行之前的攔截操作
以下是我平時使用的一些裝飾器,希望對看到這里的你有幫助!
// utils/decorator.js
import { Dialog } from 'vant';
/**
* loading 開關裝飾器
* @param {String} loading 當前頁面控制開關的變量名字
* @param {Function} errorCb 請求異常的回調 返回error 一般不用寫
* 如果 errorCb 為 function 為你綁定 this 如果是箭頭函數 則第二個參數為this
* @example
* @loading('pageLoading',function(){that.demo = '123123'})
* async getTable(){
* this.table = this.$apis.demo()
* }
* @example
* @loading('pageLoading',(error,that)=>{that.demo = '123123'})
* async getTable(){
* this.table = this.$apis.demo()
* }
*/
export function loading (loading, errorCb = Function.prototype) {
return function (target, name, descriptor) {
const oldFn = descriptor.value;
descriptor.value = async function (...args) {
try {
this[loading] = true;
await oldFn.apply(this, args);
} catch (error) {
errorCb.call(this, error, this);
} finally {
this[loading] = false;
}
};
};
}
/**
* 日志注入
* @export
* @param {Function} fn - 運行函數
* @param {data} 日志需要的參數
* @returns
*/
export function log(data) {
return function(target, name, descriptor) {
const fn = descriptor.value;
descriptor.value = async function(...args) {
await logApi(data) // 自己的日志接口
await fn.apply(this, args);
}
}
}
// utils/decorator.js
/**
* 節(jié)流,一定時間內,只能觸發(fā)一次操作
* @export
* @param {Function} fn - 運行函數
* @param {Number} wait - 延遲時間
* @returns
*/
export function throttle(wait= 2000) {
return function(target, name, descriptor) {
const fn = descriptor.value
let canRun = true
descriptor.value = async function(...args) {
if (!canRun) return
await fn.apply(this, args)
canRun = false
setTimeout(() => {
canRun = true
}, wait)
}
}
}
// utils/decorator.js
/**
* 防抖,連續(xù)操作時,只在最后一次觸發(fā)
* @export
* @param {Function} fun - 運行函數
* @param {Number} wait - 延遲時間
* @returns
*/
export function debounce(wait= 2000) {
return function(target, name, descriptor) {
const fn = descriptor.value
let timer = null
descriptor.value = function(...args) {
const _this = this._isVue ? this : target
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(_this, args)
}, wait)
}
}
}
/**
* 表單校驗
* @param {String} formElKey - 表單el
*/
export const formValidation = (formElKey = 'formEl') => {
return (target, name, descriptor) => {
const method = descriptor.value
descriptor.value = async function() {
const _this = this._isVue ? this : target
const isValidate = _this[formElKey]?.validate
if (isValidate) {
const [, res] = await to(isValidate())
if (!res) return false
}
return method.apply(_this, arguments)
}
}
}
// utils/decorator.js
/**
* 確認框
* @param {String} title - 標題
* @param {String} concent - 內容
* @param {String} confirmButtonText - 確認按鈕名稱
* @returns
*/
export const alertDecorator = ({title = '提示', message = '請輸入彈窗內容', confirmButtonText = '我知道了'}) => {
return (target, name, descriptor) => {
const fn = descriptor.value;
descriptor.value = function (...args) {
Dialog.alert({title, message, confirmButtonText}).then(() => {
fn.apply(this, args);
});
}
}
}
/**
* 緩存計算結果
* @export
* @param {Function} fn
* @returns
*/
export function cached() {
return function(target, name, descriptor) {
const method = descriptor.value
const cache = new Map()
descriptor.value = function() {
const _this = this._isVue ? this : target
const key = JSON.stringify(arguments)
if (!cache.has(key)) {
cache.set(key, method.apply(_this, arguments))
}
return cache.get(key)
}
}
}
既然看到了這里,先收藏一下,如果實戰(zhàn)劃水時間提高了,別忘了回來點個贊哦
如果覺得有用,就分享給你的小伙伴吧!接下來就是快樂的劃水了 O(∩_∩)O哈哈~

評論
圖片
表情
