Skip to content

类组件正如在模板项目中使用的那样,是一个由 @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 选项后,可以通过组件对象获取。

javascript
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;

打印组件对象:

image-20230804145924502

基础选项 components

使用 components 选项注册当前组件实例可使用的组件,如:为 HelloWorld 组件注册 Card 组件。

javascript
// 定义 Card 组件
@Component
class CardComponent extends Vue {
  
}
javascript
@Component({
  components: {
    CardComponent	// 注册 Card 组件
  }
})
class HelloWorldComponent extends Vue {
  @Prop
  msg: string;

  count: number = 0;
}
export default HelloWorldComponent;

打印组件对象:

image-20230804151652794

基础选项 directives

使用 directives 选项注册当前组件可使用的指令,如:为 template 中的 input 输入框增加获取焦点的指令。

javascript
// 定义获取焦点指令
const focus = {
  mounted(el) {
    el.focus();
  },
};
javascript
@Component({
  directives: {
    focus, // 注册获取焦点指令
  },
})
class HelloWorldComponent extends Vue {
  @Prop
  msg: string;

  count: number = 0;
}
export default HelloWorldComponent;
html
<template>
  <input v-focus/>
</template>

打印组件对象:

image-20230804151600603

基础选项 inheritAttrs

使用 inheritAttrs 选项来禁用或启用默认的组件属性透传行为,默认为启用状态,但仅当子组件为单根节点时发生。

首先变更 HelloWorld 组件的 template ,为其内部节点添加公共的跟节点:

HTML
<template>
  <div>
    <h1>{{ msg }}</h1>
    省略其它节点
  </div>
</template>

在使用 HelloWorldApp 父组件中为其透传 style 属性,增加一个1像素的红色边框:

HTML
<template>
  <HelloWorld style="border: 1px solid red" msg="Vite + Vue" />
</template>

启用透传的效果:

image-20230804153904163

增加 inheritAttrs 选项,关闭这一默认的透传行为:

image-20230804163408617

组合选项 provide

使用 provide 选项用于用于提供可以被后代组件注入的值,通过引入 computed(),同样支持响应式的数据传递。

vue
<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 组件。

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>

[^注]: 混入的 BaseComponent 组件的 mounted 生命周期会优先与 App 的 mounted 执行。

状态选项 emits

使用 emits 选项用于声明由组件触发的自定义事件,如:通过组件中按钮点击触发 result 事件。

vue
<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>
vue
<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>

打印组件对象及事件派发:

image-20230804172614780

状态选项 expose

使用 expose 选项用于声明对外暴露的公共属性,如:HelloWorld 组件仅对外暴露 handleClick 函数。

在默认情况下,当通过组件$parent$root 或模板引用访问组件时,组件会暴露所有的实例属性,如下图,counthandleClickmsg 均被暴露,我们应该尽可能的保证组件实例属性的私有化,让必须暴露的属性暴露出去即可。

image-20230804175932271

javascript
import { Component, Vue } from 'vue-facing-decorator';

@Component({
  expose: ['handleClick'] // 暴露 handleClick 方法/函数
})
class HelloWorldComponent extends Vue {
  handleClick() {
    console.log('hw handleClick');
  }
}
export default HelloWorldComponent;
vue
<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 函数:

image-20230804180446812

渲染选项 template

使用 template 选项可以用来声明组件的字符串模板,同样需要使用包含模板编译器的 Vuejs 版本。

typescript
@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 版本。

typescript
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文件中添加以下配置:

typescript
resolve: {
  alias: {
    'vue$': 'vue/dist/vue.esm-bundler.js'
  }
}

如果你使用的是Vue CLI,你可以在vue.config.js文件中添加以下配置:

typescript
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        'vue$': 'vue/dist/vue.esm-bundler.js'
      }
    }
  }
}

渲染选项 render

使用 render 选项用于编程式地创建组件虚拟 DOM 树的函数。

typescript
import { h } from 'vue';

@Component({
  render: () => {
    return h('div', 'CardComponent')
  }
})
class CardComponent extends Vue {}

独有选项 options

optionsvfd 的独有选项,用于在 modifier 执行前为组件赋值,如:在options选项中为 CardComponent 组件设置 name 属性。

typescript
@Component({
  options: {
    name: 'Card'
  },
  modifier: (option: any) => {
    option.methods.customMethod = () => {}
  }
})
class CardComponent extends Vue {}

打印组件对象:

image-20230807112000981

独有选项 modifier

modifiervfd 的独有选项,用于直接修改生成的 vue option 组件,如:在 modifier 选项中为 CardComponent 组件增加 customMethod 函数。

typescript
@Component({
  modifier: (option: any) => {
    option.methods.customMethod = () => {}
  }
})
class CardComponent extends Vue {}

打印组件对象:

image-20230807111423435