类组件正如在模板项目中使用的那样,是一个由 @Component 装饰器描述的 继承自 Vue 基类的类。在 @Component 装饰器中还提供了多个选项的支持,接着一起来熟悉一下这些选项。
支持选项&分类
基础选项 | |
---|---|
name | 用于显式声明组件展示时的名称 |
components | 用于注册对当前组件实例可用的组件 |
directives | 用于注册对当前组件实例可用的指令 |
inheritAttrs | 用于控制是否启用默认的组件 attribute 透传行为 |
组合选项 | |
provide | 用于提供可以被后代组件注入的值 |
mixins | 用于将一个组件的选项混入到当前组件实例 |
状态选项 | |
emits | 用于声明由组件触发的自定义事件 |
expose | 用于声明对外暴露的公共属性 |
渲染选项 | |
template | 用于声明组件的字符串模板 |
render | 用于编程式地创建组件虚拟 DOM 树的函数 |
其他选项 | |
setup | 用于组件的初始化设置和逻辑编写,同【14组合式API应用】 |
独有选项 | |
options | 用于在 modifier 执行前为组件赋值 |
modifier | 用于直接修改生成的 vue option 组件 |
基础选项 name
当为组件增加 name
选项后,可以通过组件对象获取。
import { Component, Prop, Vue } from 'vue-facing-decorator';
@Component({
name: 'HelloWorld', // 设置 name 选项
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
import { Component, Prop, Vue } from 'vue-facing-decorator';
@Component({
name: 'HelloWorld', // 设置 name 选项
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
打印组件对象:
基础选项 components
使用 components
选项注册当前组件实例可使用的组件,如:为 HelloWorld
组件注册 Card
组件。
// 定义 Card 组件
@Component
class CardComponent extends Vue {
}
// 定义 Card 组件
@Component
class CardComponent extends Vue {
}
@Component({
components: {
CardComponent // 注册 Card 组件
}
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
@Component({
components: {
CardComponent // 注册 Card 组件
}
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
打印组件对象:
基础选项 directives
使用 directives
选项注册当前组件可使用的指令,如:为 template
中的 input
输入框增加获取焦点的指令。
// 定义获取焦点指令
const focus = {
mounted(el) {
el.focus();
},
};
// 定义获取焦点指令
const focus = {
mounted(el) {
el.focus();
},
};
@Component({
directives: {
focus, // 注册获取焦点指令
},
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
@Component({
directives: {
focus, // 注册获取焦点指令
},
})
class HelloWorldComponent extends Vue {
@Prop
msg: string;
count: number = 0;
}
export default HelloWorldComponent;
<template>
<input v-focus/>
</template>
<template>
<input v-focus/>
</template>
打印组件对象:
基础选项 inheritAttrs
使用 inheritAttrs
选项来禁用或启用默认的组件属性透传行为,默认为启用状态,但仅当子组件为单根节点时发生。
首先变更 HelloWorld 组件的 template
,为其内部节点添加公共的跟节点:
<template>
<div>
<h1>{{ msg }}</h1>
省略其它节点
</div>
</template>
<template>
<div>
<h1>{{ msg }}</h1>
省略其它节点
</div>
</template>
在使用 HelloWorld 的 App 父组件中为其透传 style
属性,增加一个1
像素的红色边框:
<template>
<HelloWorld style="border: 1px solid red" msg="Vite + Vue" />
</template>
<template>
<HelloWorld style="border: 1px solid red" msg="Vite + Vue" />
</template>
启用透传的效果:
增加 inheritAttrs
选项,关闭这一默认的透传行为:
组合选项 provide
使用 provide
选项用于用于提供可以被后代组件注入的值,通过引入 computed()
,同样支持响应式的数据传递。
<script lang="ts">
import { computed } from 'vue';
import CardWapper from './components/CardWapper.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
components: {
CardWapper,
},
provide() {
return {
title: computed(() => this.title),
footers: this.footers,
}
}
})
export default class App extends Vue {
title = '相册集';
footers = [
{
name: 'copy',
link: 'http://www.baidu.com',
},
{
name: 'jump',
link: 'https://juejin.cn',
},
];
update() {
this.title = '相册集' + Date.now();
}
}
</script>
<template>
<div>
<button @click="update">更新标题</button>
<CardWapper></CardWapper>
</div>
</template>
<script lang="ts">
import { computed } from 'vue';
import CardWapper from './components/CardWapper.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
components: {
CardWapper,
},
provide() {
return {
title: computed(() => this.title),
footers: this.footers,
}
}
})
export default class App extends Vue {
title = '相册集';
footers = [
{
name: 'copy',
link: 'http://www.baidu.com',
},
{
name: 'jump',
link: 'https://juejin.cn',
},
];
update() {
this.title = '相册集' + Date.now();
}
}
</script>
<template>
<div>
<button @click="update">更新标题</button>
<CardWapper></CardWapper>
</div>
</template>
组合选项 mixins
mixins
是一个在 Vuejs3.x 中不再被推荐的一个选项,在 @Component
中使用 mixins
选项用于将一个组件的选项混入到当前组件实例。如果待混入的组件为类组件,那么必须使用 toNative()
转换为原生 Vue 组件。
<script lang="ts">
import { Component, toNative, Vue } from 'vue-facing-decorator';
@Component({
name: 'BaseComponent',
})
class BaseComponent extends Vue {
mounted() {
console.log('BaseComponent mounted');
}
}
@Component({
mixins: [toNative(BaseComponent)]
})
export default class App extends Vue {
mounted() {
console.log('AppComponent mounted');
}
}
</script>
<script lang="ts">
import { Component, toNative, Vue } from 'vue-facing-decorator';
@Component({
name: 'BaseComponent',
})
class BaseComponent extends Vue {
mounted() {
console.log('BaseComponent mounted');
}
}
@Component({
mixins: [toNative(BaseComponent)]
})
export default class App extends Vue {
mounted() {
console.log('AppComponent mounted');
}
}
</script>
[^注]: 混入的 BaseComponent 组件的 mounted 生命周期会优先与 App 的 mounted 执行。
状态选项 emits
使用 emits
选项用于声明由组件触发的自定义事件,如:通过组件中按钮点击触发 result
事件。
<script lang="ts">
import { Component, Emit, Vue } from 'vue-facing-decorator';
@Component({
emits: ['result'] // 定义自定义事件名
})
class HelloWorldComponent extends Vue {
handleClick() {
// 通过 $emit 执行自定义事件
this.$emit('result', 'hello world~')
}
}
export default HelloWorldComponent;
</script>
<template>
<button @click="handleClick">按钮</button>
</template>
<script lang="ts">
import { Component, Emit, Vue } from 'vue-facing-decorator';
@Component({
emits: ['result'] // 定义自定义事件名
})
class HelloWorldComponent extends Vue {
handleClick() {
// 通过 $emit 执行自定义事件
this.$emit('result', 'hello world~')
}
}
export default HelloWorldComponent;
</script>
<template>
<button @click="handleClick">按钮</button>
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
// 接收子组件派发的自定义事件
const onResult = (value) => {
console.log(value);
};
</script>
<template>
<HelloWorld msg="Vite + Vue" @result="onResult" />
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
// 接收子组件派发的自定义事件
const onResult = (value) => {
console.log(value);
};
</script>
<template>
<HelloWorld msg="Vite + Vue" @result="onResult" />
</template>
打印组件对象及事件派发:
状态选项 expose
使用 expose
选项用于声明对外暴露的公共属性,如:HelloWorld 组件仅对外暴露 handleClick
函数。
在默认情况下,当通过组件$parent
、$root
或模板引用访问组件时,组件会暴露所有的实例属性,如下图,count
、handleClick
、msg
均被暴露,我们应该尽可能的保证组件实例属性的私有化,让必须暴露的属性暴露出去即可。
import { Component, Vue } from 'vue-facing-decorator';
@Component({
expose: ['handleClick'] // 暴露 handleClick 方法/函数
})
class HelloWorldComponent extends Vue {
handleClick() {
console.log('hw handleClick');
}
}
export default HelloWorldComponent;
import { Component, Vue } from 'vue-facing-decorator';
@Component({
expose: ['handleClick'] // 暴露 handleClick 方法/函数
})
class HelloWorldComponent extends Vue {
handleClick() {
console.log('hw handleClick');
}
}
export default HelloWorldComponent;
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
import { ref } from 'vue';
const hw = ref();
const handleClick = () => {
hw.value.handleClick();
};
</script>
<template>
<button @click="handleClick">按钮</button>
<HelloWorld ref="hw" msg="Vite + Vue" @result="onResult" />
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
import { ref } from 'vue';
const hw = ref();
const handleClick = () => {
hw.value.handleClick();
};
</script>
<template>
<button @click="handleClick">按钮</button>
<HelloWorld ref="hw" msg="Vite + Vue" @result="onResult" />
</template>
此时的在父组件就仅能获取到 handleClick
函数:
渲染选项 template
使用 template
选项可以用来声明组件的字符串模板,同样需要使用包含模板编译器的 Vuejs 版本。
@Component({
template: '<div>CardComponent</div>'
})
class CardComponent extends Vue {}
@Component({
template: '<div>CardComponent</div>'
})
class CardComponent extends Vue {}
如果你在控制台见到了这段提示:Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js". 那么目前你使用的 Vuejs 版本将不包含模板编译器。
在模板项目中通过在 vite.config.ts
切换 不同的 Vuejs 版本。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'vue': 'vue/dist/vue.esm-bundler.js'
}
},
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'vue': 'vue/dist/vue.esm-bundler.js'
}
},
})
如果你使用的是Webpack,你可以在webpack.config.js文件中添加以下配置:
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm-bundler.js'
}
}
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm-bundler.js'
}
}
如果你使用的是Vue CLI,你可以在vue.config.js文件中添加以下配置:
module.exports = {
configureWebpack: {
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm-bundler.js'
}
}
}
}
module.exports = {
configureWebpack: {
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm-bundler.js'
}
}
}
}
渲染选项 render
使用 render
选项用于编程式地创建组件虚拟 DOM 树的函数。
import { h } from 'vue';
@Component({
render: () => {
return h('div', 'CardComponent')
}
})
class CardComponent extends Vue {}
import { h } from 'vue';
@Component({
render: () => {
return h('div', 'CardComponent')
}
})
class CardComponent extends Vue {}
独有选项 options
options
是 vfd 的独有选项,用于在 modifier
执行前为组件赋值,如:在options
选项中为 CardComponent 组件设置 name
属性。
@Component({
options: {
name: 'Card'
},
modifier: (option: any) => {
option.methods.customMethod = () => {}
}
})
class CardComponent extends Vue {}
@Component({
options: {
name: 'Card'
},
modifier: (option: any) => {
option.methods.customMethod = () => {}
}
})
class CardComponent extends Vue {}
打印组件对象:
独有选项 modifier
modifier
是 vfd 的独有选项,用于直接修改生成的 vue option 组件,如:在 modifier
选项中为 CardComponent 组件增加 customMethod
函数。
@Component({
modifier: (option: any) => {
option.methods.customMethod = () => {}
}
})
class CardComponent extends Vue {}
@Component({
modifier: (option: any) => {
option.methods.customMethod = () => {}
}
})
class CardComponent extends Vue {}
打印组件对象: