乐趣区

关于前端:三步带你玩转前端装饰器

  • 什么是装璜器
  • 装璜器怎么封装
  • 装璜器无能啥

1、什么是装璜器

看个例子就懂了 eg:
失常开发是这样的:1、先定义节流办法: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、而后执行 A 办法:
        methods: {a() {this.throttle(()=>{// 执行业务逻辑}, 400)
            }
        }

反正就是各种嵌套,看起来代码很脓肿, 接下来看看【装璜器】怎么写↓

// 应用装璜器过后的写法
import {throttle} from "@/utils/decorator";

methods: {@throttle(400)  // 装璜器(节流)a() {
    // 执行业务逻辑
    // 此时会发现点击成果跟下面写法一样
    console.log('执行业务')
  },
}

当初看到的写法是不是凉爽了很多,没有多层嵌套

2、装璜器怎么封装

    1、在工具文件创建 decorator.js
    // utils/decorator.js
    /**
     * 节流,肯定工夫内,只能触发一次操作
     * @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) {
          // 具体的装璜器业务在这外面编写    
          if (!canRun) return
          await fn.apply(this, args) // 执行业务下的办法
          canRun = false
          setTimeout(() => {canRun = true}, wait)
        }
      }
    }
    2、在业务板块外面申明应用
       methods: {@throttle(400)  // 装璜器(节流)a() {
            // 执行业务逻辑
            // 此时会发现点击成果跟下面写法一样
            console.log('执行业务')
          },
        }
    // 当初看到代码是不是就没有那么脓肿了,就一行指令

3、装璜器无能啥

事实开发中常常遇到节流,防抖,日志,按钮权限等等一些业务执行之前的拦挡操作

以下是我平时应用的一些装璜器,心愿对看到这里的你有帮忙!

// 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
/**
 * 节流,肯定工夫内,只能触发一次操作
 * @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
/**
 * 防抖,间断操作时,只在最初一次触发
 * @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)
    }
  }
}
既然看到了这里,先珍藏一下,如果实战划水工夫进步了,别忘了回来点个赞哦

如果感觉有用,就分享给你的小伙伴吧!
接下来就是高兴的划水了 O(∩_∩)O 哈哈~

退出移动版