Vue组件内的方法如何添加装饰器Decorator

想要给Vue组件内的某方法增加Decorator,发现并不能很好支持。

<template>
  <div id="app">
    <img src="./assets/logo.png" @click="foo">
    <hello></hello>
  </div>
</template>

<script>
import Hello from './components/Hello'
import Vue from 'vue'
import Component from 'vue-class-component'

const log = (target, name, descriptor) => {
  const method = descriptor.value
  descriptor.value = (...args) => {
    console.log(target, descriptor)
    method.apply(target, args)
  }
  return descriptor
}

@Component({
  components: {
    Hello
  }
})
class App extends Vue {

  str = 'Hello'

  @log
  foo () {
    console.log(this.str)
  }
}

console.info('App', App)
export default App
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

foo添加装饰器log之后,this不能正确的指向Component本身。。

回答:

问题在于log方法里面。

//descriptor.value = (...args) => {
//    console.log(target, descriptor)
//    method.apply(target, args)
//  }
//修改如下:

descriptor.value = function(...args){ //这里不要用箭头函数, 会在执行环境中丢失正确的this指向
    console.log(target, descriptor)
    method.apply(this, args) //因为descriptor.value的运行环境是在Class App中,所以这里的this会指向App。如果写成箭头那this就是log了
  }

正常的Class在加装饰器的时候使用method.apply(target, args)是没有问题的。但是vue在注册组件的时候会进行初始化,this在这个时候被改变了(class内部的的this变了,此时 this !== target了

回答:

稍微改造一下就好了,针对vue实例做一下适配

const log = (target, name, descriptor) => {
  const method = descriptor.value
  descriptor.value = (...args) => {
    // 判断一下应该使用的this指向
    const _this = this.isVue ? this : target;
     
    console.log(target, descriptor)
    method.apply(_this, args)
  }
  return descriptor
}

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注