Vue 中使⽤装饰器的⽅法详解
装饰器是⼀种与类相关的语法糖,⽤来包装或者修改类或者类的⽅法的⾏为,其实装饰器就是设计模式中装饰者模式的⼀种实现⽅式,下⾯这篇⽂章主要给⼤家介绍了关于Vue中使⽤装饰器的相关资料,需要的朋友可以参考下
前⾔
相信各位在开发中⼀定遇到过⼆次弹框确认相关的需求。不管你使⽤的是UI框架的⼆次弹框组件,还是⾃⼰封装的弹框组件。都避免不了在多次使⽤时出现⼤量重复代码的问题。这些代码的积累导致项⽬的可读性差。项⽬的代码质量也变得很差。那么我们如何解决⼆次弹框代码重复的问题呢?使⽤装饰器
什么是装饰器?
Decorator是ES7的⼀个新语法。Decorator通过对类、对象、⽅法、属性进⾏修饰。对其添加⼀些其他的⾏为。通俗来说:就是对⼀段代码进⾏⼆次包装。
装饰器的使⽤
使⽤⽅法很简单 我们定义⼀个函数
装饰器的⽬的旨在对代码进⾏复⽤。下⾯我们先来⼀个⼩例⼦看看
js 中使⽤装饰器
不使⽤装饰器const  decorator =  (target, name, descriptor) => { var oldValue = descriptor.value ; descriptor.value = function(){    alert ('哈哈')    return oldValue.apply (this ,agruments )      }  return descriptor }// 然后直接@decorator 到函数、类或者对象上即可。
1
2
3
4
5
6
7
8
9//定义⼀个装饰器 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 ;}  //计算类  class Calculate  {    //使⽤装饰器  @log ()  function  subtraction (a ,b ){    return  a - b    } }  const operate  = new Calculate ()  operate.subtraction (5,2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这样⼀对⽐你会发现使⽤装饰器后代码的可读性变强了。装饰器并不关⼼你内部代码的实现。
vue 中使⽤装饰器
如果你的项⽬是⽤vue-cli搭建的 并且vue-cli的版本⼤于2.5 那么你⽆需进⾏任何配置即可使⽤。如果你的项⽬还包含eslit 那么你需要在eslit中开启⽀持装饰器相关的语法检测
//在 eslintignore中添加或者修改如下代码:
加上这段代码之后eslit就⽀持装饰器语法了。
通常在项⽬中我们经常会使⽤⼆次弹框进⾏删除操作: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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15parserOptions: {    ecmaFeatures:{      // ⽀持装饰器      legacyDecorators : true    }  }
1
2
3
4
5
6
如上代码 confirm⽅法⾥执⾏了⼀个element-ui中的MessageBox组件 当⽤户取消时 Message组件会提⽰⽤户取消了操作。我们在test()⽅法上⽤装饰器修饰⼀下
tips: ⽤户取消了操作.被修饰的test⽅法不会执⾏。
⼀些常⽤的装饰器
1. 函数节流与防抖
函数节流与防抖应⽤场景是⽐较⼴的,⼀般使⽤时候会通过throttle或debounce⽅法对要调⽤的函数进⾏包装,现在就可以使⽤上⽂说的内容将这两个函数封装成装饰器, 防抖节流使⽤的是lodash提供的⽅法,⼤家也可以⾃⾏实现节流防抖函数哦
//decorator.js //假设项⽬中已经安装了 element-ui import  { MessageBox , Message } from 'element-ui'/** * 确认框 * @param {String} title - 标题 * @param {String} content - 内容 * @param {String} confirmButtonText - 确认按钮名称 * @param {Function} callback - 确认按钮名称 * @returns    **/export function confirm(title, content, confirmButtonText = '确定') {  return function(target, name, descriptor) {    const originValue = descriptor.value    descriptor.value = function(...args) {      firm(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 de
scriptor  }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import  { confirm } from '@/util/decorator'import axios form 'axios'export default  {name:'test',data(){return  {  delList : '/merchant/storeList/commitStore'    }  }},methods:{ @confirm ('删除门店','请确认是否删除门店?')  test (id ){  const  {res ,data } = axios.post(this.delList,{id })  if (res.rspCd + '' === '00000') this.$message.info ('操作成功!')  }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
封装完之后,在组件中使⽤
2. loading
在加载数据的时候,为了个⽤户⼀个友好的提⽰,同时防⽌⽤户继续操作,⼀般会在请求前显⽰⼀个loading,然后在请求结束之后关掉loading,⼀般写法如下
我们可以把上⾯的loading的逻辑使⽤装饰器重新封装,如下代码
import  { throttle , debounce } from 'lodash'/** * 函数节流装饰器 * @param {number} wait 节流的毫秒 * @param {Object} options 节流选项对象 * [options.leading=true] (boolean): 指定调⽤在节流开始前。
* [ailing=true] (boolean): 指定调⽤在节流结束后。 */export const throttle =  function(wait, options = {}) {  return function(target, name, descriptor) {    descriptor.value = throttle (descriptor.value , wait , options )  }}/** * 函数防抖装饰器 * @param {number} wait 需要延迟的毫秒数。 * @param {Object} options 选项对象 * [options.leading=false] (boolean): 指定在延迟开始前调⽤。 * [options.maxWait] (number): 设置 func 允许被延迟的最⼤值。 * [ailing=true] (boolean): 指定在延迟结束后调⽤。 */export const debounce = function(wait, options = {}) {  return function(target, name, descriptor) {    descriptor.value = debounce (descriptor.value , wait , options )  }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25import  {debounce } from '@/decorator'export default  {  methods:{    @debounce (100)    resize (){}  }}
1
2
3
4
5
6
7
8export default  {  methods:{    async getData() {      const loading = Toast.loading()      try {        const data = await loadData ()        // 其他操作      }catch(error){        // 异常处理        Toast.fail ('加载失败');      }finally {        loading.clear ()      }      }  }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
然后改造上⾯的组件代码
3. 确认框
当你点击删除按钮的时候,⼀般都需要弹出⼀个提⽰框让⽤户确认是否删除,这时候常规写法可能是这样的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) {        // 在调⽤失败,且⽤户⾃定义失败的回调函数时,则执⾏        errorFn && errorFn.call (this , error , ...rest )        (error )      } finally  {        loading.clear ()      }    }  }}
lodash有哪些方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27export default  {  methods:{    @loading ('加载中')    async getData () {      try {        const data = aw
ait loadData ()        // 其他操作      }catch(error){        // 异常处理        Toast.fail ('加载失败');      }      }  }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14import  { Dialog } from 'vant'export default  {  methods: {    deleteData() {      firm({        title : '提⽰',        message : '确定要删除数据,此操作不可回退。'      }).then(() => {        console.log ('在这⾥做删除操作')      })    }  }}1
2
3
4
5
6
7
8
9
10
11
12
13
14

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。