利用装饰器(decorator)对vue组件中的methods实现切面(aop)编程,进行日志监控、入参校验等

利用装饰器(decorator)对vue组件中的methods实现切面(aop)编程,进行日志监控、入参校验等

近期在做一个模块,需求是对vue组件的方法调用加日志监控,于是想到了在写java的时候用到了spring的aop,达到对原代码无污染的做日志的方法,于是搜索了一些资料企图在vue中实现这个效果,在这里记录一下。
实现原理是使用ES6中新增的对象装饰器(decorator),对原对象的方法进行包装,加入想要前置执行或后置执行的方法,如写日志。

1、在vue开发中使用装饰器(decorator)

由于大多数浏览器不支持decorator,开发时需安装babel及相应的插件。

npm install babel-core babel-plugin-transform-decorators

然后配置文件.babelrc(如不存在则在项目跟目录新建)

"plugins": [
        [
            "@babel/plugin-proposal-decorators",
            {
                "legacy": true
            }
        ]
    ]

2、编写“切面”注册方法

首先编写一个基础方法,逻辑是遍历装饰的vue对象的methods(当然你也可以试试拦截其他对象),对需要加切面的方法进行包装,让方法在执行前先执行“前置方法”,执行后再执行“后置方法”。

//decorator-base.js
/**
 * 封装了装饰器decorator逻辑的基类,自定义装饰器通过创建此对象后改写对应属性和方法来为指定方法增加aop功能
 * @param filter:需要增加aop方法名数组,如果只需要对部分方法起效就重写这个属性
 * @param doBefore(fn,args):在执行原方法前要执行的逻辑,需返回一个bool值决定程序是否执行,默认返回true;
 *          fn对象是封装后的function对象,添加了自定义属性aspectInfo方便获取一些组件信息,结构如下:
 *          {
               targetName:组件名,
               funcName:方法名
            }
 * @param doAfter(fn,args,result):在执行原方法后要执行的逻辑。
 * @returns {*}
 */
function decoratorBase(filter, doBefore, doAfter) {
    return function (target, funName, descriptor) {
        let oriMethods = Object.assign({}, target.methods),
            oriTarget = Object.assign({}, target);
        if (target.methods) {
            for (let name in target.methods) {
                if (filter && (filter[0] == '*' || filter.indexOf(name) > -1)) {
                    let fn = function fn(...arg) {
                        if (doBefore && !doBefore(fn, arg)) {
                            return null;
                        }
                        let result = oriMethods[name].call(this, ...arg);
                        if (result instanceof Promise) {
                            result.then(function () {
                                doAfter(fn, arg, result);
                                return result
                            })
                        }
                        doAfter && doAfter(fn, arg, result);
                        return result;
                    }
                    fn.aspectInfo = {
                        targetName: target.name,
                        funcName: name
                    }
                    target.methods[name] = fn;
                }
            }
        }
        return descriptor;
    }
}

然后创建一个“切面”定义类用来统一定义我们的“切面”。

//decorator.js

import decoratorBase from './decorator-base.js'

export function log(methods) {
    let bfn = decoratorBase([methods], function (fn, args) {
        console.log(`我在${fn.aspectInfo.targetName}--${fn.aspectInfo.funcName}方法前执行${args}`)
        return true;
        // console.log(`${fn.aspectInfo.funcName}方法被拦截,不会往下走`)
        // return false;
    }, function (fn, args, result) {
        console.log(`我在${fn.aspectInfo.targetName}--${fn.aspectInfo.funcName}方法后执行${args},结果是${result}`)
    })
    return bfn;
}

3、在vue对象中使用已注册的“切面”

对一个测试方法login做一下日志

  @log("login")
  methods: {
    login() {
      if (
        localStorage.getItem("name") === this.name &&
        localStorage.getItem("password") === this.password
      ) {
        this.name = "";
        this.password = "";
        this.$router.push("/home/list");
      } else {
        alert("账号密码不正确");
      }
    },

示例

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值