Vue ES6装饰器在实战应用
柠檬百香果 人气:0前言
在面向对象(OOP)的设计模式中,装饰器的应用非常多,比如在 Java 和 Python 中,都有非常多的应用。ES6 也新增了装饰器的功能,本文会介绍 ES6 的装饰器的概念、作用以及在 Vue + ElementUI 的项目实战中的应用。
装饰模式(Decorator)
装饰模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。 这种模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
优点:
- 不需要通过创建子类的方式去拓展功能(不需要子类化),这样可以避免代码臃肿的问题
- 装饰类的方法复用性很高
- 不会影响到原对象的代码结构
ES6 也开始有了装饰器,写法与其他语言的写法保持了统一,就是使用@ + 函数名的方式
ES6 装饰器
关于ES6 装饰器的用法可以参考阮老师的 ECMAScript 6 入门,这里从中展示一下两种用法。
- 类的装饰
装饰器方法:给对象添加一个 isTestable
属性
function testable(isTestable) { return function(target) { target.isTestable = isTestable; } }
使用的时候直接用 @ + 函数名,就可以为对象添加 isTestable
属性了
@testable(true) class MyTestableClass {} MyTestableClass.isTestable // true
- 方法的装饰
日志装饰器
function 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 Math { @log add(a, b) { return a + b; } } const math = new Math(); // Calling add with arguments math.add(2, 4);
从上面两个简单例子可以看出,装饰器应用在类和类的方法上时非常的方便,有几个优点:
- 语义化,可以非常清晰看出装饰器为对象添加了什么功能
- 装饰器不改变原对象的结构,原对象代码简洁、易维护。
接下来将介绍一下我在 Vue 项目中,利用装饰器的功能做的代码优化。
装饰器应用
目前我们了解到,装饰器可以用来注释或修改类和类方法。而且装饰器使用起来非常灵活,只需要用@ + 函数名就可以修改类,可以改善代码结构。那么在做项目的时候,编写代码时是否有些功能可以抽象成装饰器,提高复用性和改善代码结构。
下面的例子所用到的技术栈是 Vue2 + ElementUI + TypeScript + vue-property-decorator
Validate
在很多 UI 组件库中,都有表单组件,其中表单重要的功能之一就是表单校验,以 ElementUI 的 form 举例,首先校验表单是否通过,如果通过,就将表单数据提交给后台,
完整的代码如下:
submitForm() { this.$refs['formName'].validate(async (valid) => { if (valid) { try { // 调用接口 await this.handleTest(); this.$message.success('Submit Successfully!') } catch(error) { console.log(error); } } else { console.log('error submit!!'); return false; } }); },
这里有几个问题:
- 这个代码嵌套到第三层才开始进入主逻辑代码,嵌套太多了,万一在主要业务逻辑代码还有很多嵌套,看起来就十分的难受。
- 记不住,在实际开发中,一般不回特意去记触发校验的写法,通常要去找文档或者找别人的代码,最后抄过来
- 此功能很常用,每做一个表单都要写一遍,重复写这份代码
分析上面代码,其实主要的代码是在 if (valid)
的条件下,而触发表单校验的代码是可以抽象出来的,因为它非常常用,而且这部分代码是无关业务逻辑的。抽象出去,可以更好地关注到业务逻辑代码。
export function Validate(refName: string) { return function (target: any, name: string, descriptor: PropertyDescriptor) { const fn = target[name]; // 被装饰的方法 descriptor.value = function (...args: any[]) { // 将触发校验的代码封装在此 (this as any).$refs[refName].validate((valid: boolean) => { if (valid) { fn.call(this, ...args); // 在这里调用“被装饰的方法” } else { console.log('error submit!!'); return false; } }); }; }; }
然后在使用的时候就非常简单了,只需要在提交方法上方写上 @Validate('refName')
,传入表单组件的 ref 名,就可以实现了触发表单校验的功能,这样不但大大优化了代码结构,而且使用起来非常简单,
加载全部内容