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小时内删除。
发表评论