大部分场景下我们都可以通过这样的方式进行组件化的开发。这种模式的有一个特点: 组件的引入通过组件注册和模板中写入对应的组件的标签来完成。模板中通过标签来引入组件这一步必不可少,这个特点在某些业务场景下可能给开发者带来了一定的重复工作量。
API 式的调用
API 式的调用指的是手动创建子组件的实例,业务逻辑中无需引入组件和模板标签占位,在暴露的 API 中控制组件的实例化与显示。
一、使用方式
功能模块提供一个入口 js 来控制该功能模块下单文件实例的所有功能逻辑
其他组件中使用该功能模块时,调用功能模块下的 js,传入部分参数
操作手法:
Confirm.vue
<template> <el-dialg title="test" :visible.sync="visible"> {{content}} <el-button @click="handleCancelClick">cancel</el-button> <el-button @click="handleOkClick">ok</el-button> </el-dialg> </template> <script> export default { name: 'Confirm', data() { return { visible: false, content: '这是一个confirm dialog', callback: null, }; }, methods: { handleCancelClick() { this.callback('cancel'); }, handleOkClick() { this.callback('confirm'); }, }, }; </script>
confirm.js
import Vue from 'vue'; import Confirm from './confirm'; const ConfirmConstructor = Vue.extend(Confirm); const confirm = (content) => { let confirmInstance = new ConfirmConstructor({ data: { content, }, }); confirmInstance.vm = confirmInstance.$mount(); confirmInstance.vm.visible = true; // 手动插入目的 dom document.body.appendChild(confirmInstance.vm.$el); confirmInstance.vm.callback = action => { return new Promise((resolve, reject) => { resolve(action); }); }; return confirmInstance.vm; };
如上所示,给出的是一个确认弹框的场景实现。确认弹框在很多用户交互中是一个必须的交互形式。很多组件库也采用上面这种 API 式的组件调用。调用方仅仅通过 api 的调用,就能实现该功能模块的引用。这样就避免了在 template 中通过标签占位的方式引用。实现原理就是手动接管单文件组件的实例化,通过 Vue.extend 获得该组件对应的 Vue 的子类,在暴露给调用的 api 中去实例化这个组件。这个过程中我们可能还要完成一些组件数据的注入,逻辑相关以及手动将该组件插入到目的 dom 中。手动的注入 dom 是该种方式的一个很大特点,通过在 api 中动态的注入目的 dom,避免我们在各个业务组件中调用该功能模块时重复性的在业务组件 template 中手写组件标签。
二、适用场景
功能聚合度高,组件内逻辑简单,输入输出较为单一,比如一些功能较为独立的弹框
一些特殊的自定义指令开发,比如在一些特殊场景的指令,可以复用一些单文件组件,通过在指令的钩子中实例化组件对应的 vue 子类,按照特定的逻辑插入到目的 dom 中(例如:element-ui的v-loading)
区别和共性
共性:通过实例化对应组件完成组件的功能逻辑
区别:实例化的时机和方式不同。模板式的引入通过组件注册和标签引入的方式来使用单文件组件。标签引入解决了子组件插入的 dom 位置问题,开发者无需关心。API 式的单文件组件使用,在 API 调用时手动实例化组件,需要手动控制插入到目的 dom。
总结
vue 的单文件组件提供了 vue 的组件化开发思路,其本质在导出 vue 的一些关键属性,比如生命周期函数,methods,computed, watch,props等。我们可以通过上述两种方式来使用单文件组件,目的在于工程内部尽量减少重复的模板代码,组件解耦。