Open gowiny opened 3 years ago
我把createDecorator方法里的源代码修改了一下,请参考
原代码:
export function createDecorator(
factory: (options: ComponentOptions, key: string, index: number) => void
): VueDecorator {
return (
target: VueBase | VueConstructor<VueBase>,
key?: any,
index?: any
) => {
const Ctor =
typeof target === 'function'
? target
: (target.constructor as VueConstructor)
if (!Ctor.__d) {
Ctor.__d = []
}
if (typeof index !== 'number') {
index = undefined
}
Ctor.__d.push((options) => factory(options, key, index))
}
}
修改后的新代码:
export function createDecorator(
factory: (options: ComponentOptions, key: string, index: number) => void
): VueDecorator {
return (
target: VueBase | VueConstructor<VueBase>,
key?: any,
index?: any
) => {
const Ctor:any =
typeof target === 'function'
? target
: (target.constructor as VueConstructor)
if (!Ctor.__d) {
Ctor.__d = []
Ctor.__d.__n = Ctor.name
}else if(Ctor.__d.__n !== Ctor.name){
Ctor.__d = [].concat(Ctor.__d)
Ctor.__d.__n = Ctor.name
}
if (typeof index !== 'number') {
index = undefined
}
Ctor.__d.push((options:any) => factory(options, key, index))
}
}
就是把原来的 if (!Ctor.d) { Ctor.d = [] }
改为了
if (!Ctor.d) { Ctor.d = [] Ctor.d.n = Ctor.name }else if(Ctor.d.n !== Ctor.name){ Ctor.d = [].concat(Ctor.d) Ctor.d.n = Ctor.name }
Had to use google translate to understand what is going on but this does solve the problem with inherited classes. @gowiny Perhaps you can make a PR on the main branch?
There is a release final date for support vue 3 ?
I don't know how to PR
这里说中文,外国人看到懂吗。。。
代码文件:prop.ts
import { createDecorator } from 'vue-class-component'
function createProp(params:any, target: any, propertyKey: string,descriptor?: PropertyDescriptor){ createDecorator(function (options, key) { if(!options.props){ options.props = {} } const props = options.props if(descriptor && typeof params.default === 'undefined'){ params.default = function(){ return descriptor.value } if(options.methods){ delete options.methods[key] } } //添加新的prop 到 options.props里 props[key] = params })(target, propertyKey); }
export function Prop(params?:any):any; export function Prop(target: any, propertyKey: string):void; export function Prop(target: any, propertyKey: string,descriptor: PropertyDescriptor):void; export function Prop(target: any={}, propertyKey="",descriptor?: PropertyDescriptor):void | any { if(propertyKey){ createProp({},target,propertyKey,descriptor) }else{ const params = target; return function (target: any, propertyKey: string,descriptor?: PropertyDescriptor) { createProp(params,target,propertyKey,descriptor) } } }
代码文件:my-test-input.vue
<template>
<div></div>
</template>
<script lang="ts">
import { Vue} from 'vue-class-component'; import { Prop } from '@/lib-ref/vue-class'; class MyTestSuper extends Vue { @Prop({ type:String, default:'MyTestSuper' }) declare readonly label:string }class MyTestBase1 extends MyTestSuper { @Prop({ type:String, default:'MyTestBase1' }) declare readonly label:string }
export default class MyTestInput extends MyTestSuper {
}
</script>
测试文件:Test.vue
<template>
<div class="test">
<my-test-input ref="testComp" ></my-test-input>
<el-button @click="test">测试</el-button>
</div>
</template>
<script lang="ts">
import { Options,Vue } from 'vue-class-component';
import { refs} from '@/utils/app-utils';
import MyTestInput from '@/components/my/my-test/my-test-input.vue';
@Options({
components:{
MyTestInput
}
})
export default class Test extends Vue {
test(){
const testComp = refs(this,'testComp')
console.log('testComp label',testComp.label)
}
}
</script>
使用createDecorator方法定义了一个新的装饰器:Prop
MyTestSuper 类是基类 MyTestBase1 和 MyTestInput 都继承MyTestSuper 类 MyTestBase1 类里覆盖了MyTestSuper 类的 label属性定义
在测试页面点击按钮测试。 实际输出的 label 值 是 'MyTestBase1' 期望输出的 label 值应该是 MyTestInput 的父类MyTestSuper 里定义的 默认值:'MyTestSuper'
经过调试源码发现,createDecorator 方法里 是把 工厂函数 factory,添加到 类的构造函数的 d 属性里, 但因为多重继承的原因,createDecorator 里取到的 Ctor.d 都是基类 MyTestSuper 的引用,而非重新创建的数组。 所以,所有子类 使用 自定义装饰器 都 添加了一条记录到 基类的 d里了。而子类是引用的 基类 d,导致 MyTestSuper 的所有子类里定义的prop 都应用到所有子类,即便是非直接继承的类。
附上源代码文件: bug-src.zip