侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

使用 vue-property-decorator 进行类组件编程的一些记录

barwe
2021-06-18 / 0 评论 / 0 点赞 / 717 阅读 / 3,345 字
温馨提示:
本文最后更新于 2022-07-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

导入

import { Vue, Options } from 'vue-property-decorator';

@Options({})
export default class extends Vue {}

计算属性

使用 get 关键字,定义为组件类的 getter 方法:

@Options({})
export default class extends Vue {
	get computedValRef() {
		return something;
	}
}

@Emit 装饰器

emit 实现了在调用一个函数时自动执行另一个函数。

导入 @Emit 装饰器:

import { Emit } from 'vue-property-decorator';

@Emit 装饰器接受一个字符串参数,代表在执行它装饰的那个函数后需要触发执行的另一个函数。

@Emit 装饰器无参时,触发的额外函数就是其修饰的同名函数,驼峰函数名会被转化为连字符函数名

@Emit 装饰器触发的额外函数总是在其修饰的函数执行之后执行,并将其修饰的函数的参数作为参数。

下面是一个例子:

import { Vue, Options, Emit } from 'vue-property-decorator';

@Options({})
export default class extends Vue {
    mounted() {
        // 使用$on挂载一个事件emit-something
        this.$on('emit-something', function(s: string) {
            console.log(s);
        });
        this.emitSomething('world');
    }
    
    // 无参的@Emit装饰器,触发同名函数emit-something
    @Emit()
    emitSomething(s: string) {
        console.log('hello');
    }
}

在上面的例子中,emit-something 是组件的一个自定义 事件,在使用这个组件时,可以通过 @emit-something="func" 来执行父组件中的 func() 事件函数,func() 函数的参数应当与子组件 emitSomething() 函数的参数一致。

下面是一个具体例子:

  • 父组件:

    <template>
    	<ChildComponent @emit-message="handleEmitSomething" />
    </template>
    <script>
        import { Vue, Options } from 'vue-property-decorator';
        @Options({})
        export default class extends Vue {
            handleEmitSomething(s: string) {
                console.log('Receive from child:', s);
            }
        }
    </script>
    
  • 子组件

    <template>
    	<button @click="() => emitSomething('hello father')">Click</button>
    </template>
    <script>
        import { Vue, Options, Emit } from 'vue-property-decorator';
        @Options({})
        export default class extends Vue {
            @Emit('emit-message')
            emitSomething(s: string) {
                console.log('ChildComponent: run emitSomething');
            }
        }
    </script>
    

子组件只提供了一个按钮,点击按钮执行子组件中的 emitSomething() 函数。

emitSomething() 函数被 @Emit装饰器 修饰,自动触发子组件的 emit-message 事件。

子组件的(自定义)事件需要父组件进行处理,父组件的 handleEmitSomething() 函数处理此事件。

handleEmitSomething() 函数的参数应该与子组件的 emitSomething() 函数保持一致。

emitSomething() 函数的 实参 会赋给 handleEmitSomething() 函数的 形参

最后点击子组件的按钮,打印的结果如下:

ChildComponent: run emitSomething
Receive from child: hello father

@Model 装饰器

@Model装饰器 实现了父子组件数据的 双向绑定

父组件中,通过指定子组件的 v-model 属性对变量进行双向绑定。

下面的例子中,父组件的 content 变量与 Child 子组件双向绑定:

<template>
	<Child v-model="content"></Child>
</template>
<script>
    import { Vue, Options } from 'vue-property-decorator';
    @Options({})
    export default class extends Vue {
        content: string;
    }
</script>

子组件中也需要定义一个变量,来实现双向绑定:

<template>
	<input type="text" :value="str" @input="$emit('update:modelValue', $event.target.value)" />
</template>
<script>
    import { Vue, Options, Model } from 'vue-property-decorator';
    @Options({})
    export default class extends Vue {
        @Model('modelValue', String) str!: string;
    }
</script>

在 Vue3 中,@Model 装饰器接受两个参数:

  • propName: string:调用子组件时 v-model:xxx 使用的标志 xxxv-model 则使用默认标志 modelValue
  • propOptions?: Constructor | Constructor[] | PropOptions<any, any> | undefined

上面的例子中,子组件使用 @Model('modelValue', String) 修饰了 str 变量,意味着 str 变量绑定的属性名称是 v-model,从而与父组件的 conetenr 变量实现双向绑定。

但是,@Model装饰器只是声明了父子组件中用于双向绑定的两个变量,并没有指明触发数据同步的事件。

在 Vue3 中,子组件通过 update:xxx 事件来触发数据同步,因此上面的子组件调用等价于:

<template>
	<Child :str="content" @update:modelValue="(val) => content = val"></Child>
</template>

v-model 其实是一种特殊的值传递:

  • 通过 v-bind 指令将值传递给子组件
  • 通过子组件上的 update:xxx 事件将子组件的值更新回父组件

所以子组件必须要对 update:xxx 事件作出定义,即使用 $emit 或者 @Emitupdate:xxx 进行触发绑定。

在例子中子组件的定义中可以看到,update:xxx 事件被绑定到了子组件的 input 组件上。

当 input 组件的值发生变化时,触发子组件的 update:xxx 事件,并将 input 组件的值传递给 update:xxx 事件。

触发子组件的 update:xxx 事件即意味着接着执行父组件中 `@update:xxx 指定的函数,从而实现值的回传。

@Model装饰器 还可以指定其他负责回传的事件名,无论如何都需要子组件使用 emit 进行触发绑定。

0

评论区