vue-mount —— 一个动态加载 Vue 组件并维护组件树的工具库。
中文文档 | English
你可以通过 npm
来安装。
npm i vue-mount -S
或者通过 yarn
安装:
yarn add vue-mount
还可以直接使用 CDN
方式引入
先决条件:该方式必须先要引入完整
Vue
,或者在window
对象上暴露出Vue
构造函数。
<!-- 首先要引入 Vue -->
<!-- 可以在 `window.Vue` 中拿到 `Vue` 构造函数 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<!-- 引入 vue-mount -->
<script src="https://cdn.jsdelivr.net/npm/vue-mount/dist/vue-mount.min.js"></script>
<script>
var mount = window['VueMount'].mount;
var Mount = window['VueMount'].default;
</script>
// 引入 mount 方法
import { mount } from "vue-mount";
// 引入 Alert 组件
import Alert from "./alert.vue";
// 动态挂载 Alert 组件实例并返回
const alert = mount(Alert);
// 暴露出的方法 `mount(cmp, opt)` 相当于 `new Mount(cmp, opt).mount()`的一个快捷语法糖
import Mount from "vue-mount";
import Alert from "./alert.vue";
const mountAlert = new Mount(Alert, {
// 挂载目标
// 特殊值 `new` 表明去创建并挂载到一个新的 Vue 根实例上
target: 'new',
// 需要传入组件 props 参数的数据对象
props: {
content: 'Mount alert component to a new Vue root instance'
},
// 可以修改组件内部的 响应式数据
data: {
someInnerData: 'modified'
},
// 添加事件监听器
on: {
'some-event'(eventData, vm, mnt) {
// 每个处理函数都会追加传入两个辅助参数
// eventData 是原来的事件监听器参数(根据组件发射的事件,参数可能不存在也可能存在多个)
// vm 是当前挂载的组件实例
// mnt(mount的缩写)是当前创建挂载组件的 vue-mount 实例
}
},
watch: {
content: {
immediate: true,
handler(newValue, oldValue, vm, mnt) {
console.log('Content has changed: ' + newValue);
// 取消 watch
// 当 `immediate` 为 true 时,需要确保取消函数存在
if (mnt.unwatchMapper.content) {
mnt.unwatchMapper.content();
}
}
}
}
});
// 拿到 Alert 组件的实例
let alertVm = mountAlert.getInstance();
// 挂载实例
// 另外,在 Mount 实例上调用多次 mount 方法只会挂载组件一次
alertVm = mountAlert.mount();
// 挂载后动态设置组件的 props 属性值
mountAlert.set({
props: { content: 'Props changed' }
});
// 完全销毁一个实例,并且移除组件对应的 DOM。
mountAlert.destroy();
// 销毁之后新的组件实例会被重新挂载
alertVm = mountAlert.mount();
- 类型: { string | Element | Vue | VNode }
- 默认值:
new
- 说明: 你可以传入
css selector
,Element
,Vue instance
,VNode
或者是包括new
和root
的特殊预设值。new
: 默认特殊预设值. Vue 组件实例会被挂载到一个新创建的 Vue 根实例上。root
: Vue 组件实例将被挂载到现有的 Vue 根实例上。 如果在MountOption.root
选项下找不到根实例或根元素,组件实例将被挂载到一个新的 Vue 根实例上,其行为将与选项new
相似。- 当传入一个
Vue 实例对象
时,新的组件实例将会替换/追加到传入的实例(具体参见MountOption.mode
配置),并且在 Vue 组件树上更新。 当新的组件实例挂载时,传入的实例将会被销毁。
- 用例:
mount(Alert, { target: "root" }; mount(Alert, { target: "#target" }; mount(Alert, { target: document.querySelector('.list') }; mount(Alert, { target: this.$refs.component }; mount(Alert, { target: this.$refs.component.$slots.default[0] };
特别注意:当配置为
new
时,挂载的组件无法访问到创建根实例时传入的配置,导致在挂载的组件内无法访问this.$router
等在根组件上全局注册的配置(原因是创建了一个新的根实例,但是存在替代方案);其他情况下,vue-mount
会自动查询并加入组件树上下文。
- 类型: { string }
- 默认值:
replace
- 备选项:
replace
,append
- 说明: 指定挂载方式:
替换
和追加
模式。对应到其组件树上的行为。 - 用例:
// Alert 组件实例将会被追加挂载到当前组件(this)上。 mount(Alert, { target: this, mode: 'append' });
值得注意的是:当配置项
target
值为new
或者root
时,mode
将被忽略并重置成append
。
- 类型: { string | Element | Vue }
- 默认值:
#app
- 说明: 指定当前应用的根元素.(所有给出的值在内部都将被解析为HTML元素)。
- 类型: { VueOptions }
- 默认值:
{}
- 说明: 允许指定在创建新的 Vue 根实例时的构造选项。
- 用例:
mount(Alert, { rootOptions: { data: { root: 'new root instance' }, methods: { ... }, ... } };
- 类型: { Object }
- 说明: 指定传入组件的 props 值。
- 类型: { Object }
- 说明: 指定的值将会在实例创建完毕(也可能未挂载)时修改组件内部响应式数据。
- 类型: { [event: string]: Function | Object }
- 说明: 将事件侦听器附加到组件实例。
-
内置 事件:
mount:mount
: 在调用mount
方法或准备挂载组件时触发。mount:destroy
: 触发何时(底层)调用destroy
方法
-
当传入配置对象:
once
{ Boolean }: 是否在第一次触发时删除侦听器(只触发一次)。handler
{ Function }: 事件触发回调函数.与 Vue 的事件回调函数 (vm.$on/$once)相比,会在参数列表后追加两个辅助参数,当前组件实例
和当前 Mount 实例
。
回调函数的
this
指向为当前的 Mount 实例,当然你可以使用箭头函数来避免这一行为。
-
- 用例:
mount(Alert, { on: { 'mount:mount'(vm, mnt) { console.log('mount:mount'); vm.doSomething(); }, 'mount:destroy'() { console.log('mount:destroy') }, remove: { once: true, handler: (vm, mnt) => { console.log('remove'); } }, 'remove-with-data'(...args) { console.log(args); } } })
- 类型: { [key: string]: Function | Object }
- 说明: 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。
-
当传入配置对象:
immediate
{ Boolean }: Passing inimmediate: true
in the option will trigger the callback immediately with the current value of the expression.deep
{ Boolean }: 为了发现对象内部值的变化,可以在选项参数中指定 deep: true 。注意监听数组的变动不需要这么做。handler
{ Function }: 值更改时的回调函数。与 Vue 的回调函数(vm.$watch)相比,此回调函数通常有4个参数,如:newValue、oldValue、vm、mnt。最后两个辅助参数是:当前组件实例
和当前 Mount 实例
。
回调函数的
this
指向为当前的 Mount 实例,当然你可以使用箭头函数来避免这一行为。 -
Unwatch: 传给
watch
选项每个键都将添加到 Mount 实例的属性unwatchMapper
中,您可以调用类似mnt.unwatchMapper.attr()
的方法来取消监听。
-
- 用例:
mount(Alert, { watch: { otherAttr(newV) { console.log(newV); } attr: { handler(newValue, oldValue, vm, mnt) { console.log(args); // 取消 watch // 当 `immediate` 为 true 时,需要确保取消函数存在 if (mnt.unwatchMapper.content) { mnt.unwatchMapper.content(); } }, immediate: true, }, } })
注意:只有在
data
选项中提前声明数据,值变化时监听回调函数才能被正常调用。
- 参数: { MountOptions }
- 返回: { Vue }
- 说明: 返回一个 vue 组件实例。多次调用该方法只会创建实例一次,且将返回相同的实例。
注意:当选项
target
的值是root
, 且没有找到根实例/元素时(这种情况将导致创建一个新的 Vue 根实例)或者当值为new
时,两种情况都将导致组件实例会被立即挂载。
值得注意:为了确保行为一致性,推荐优先使用
#mount
方法。
- 参数: { MountOptions }
- 返回: { Vue }
- 说明: 挂载 Vue 组件、更新组件树并返回 Vue 组件实例。
若在组件已被
destroy
之后再次调用该方法将重新装载该组件(你可以认为 mount 实例为组件工厂)。
多次调用该方法只会挂载实例一次,且将返回相同的实例。
- 参数: { MountDataOptions }
- 返回: { Mount } 当前
Mount
实例。 - 说明: 动态设置组件实例的
props
、data
和listeners
。
- 返回: { Vue }
- 说明: 销毁 Vue 组件实例并删除关联的元素,并更新组件树。与 Vue 的 $destroy 方法不同,销毁整个组件与其 DOM。
- 返回: { Element | Node }
- 说明: 返回组件实例相关联的 DOM。
- 返回: { VueMount }
- 说明: 返回组件实例相关联的 VueMount 实例。
-
当 VueMount 将组件挂载到新的 Vue 根实例上时,该组件将无法获取到在原根组件配置的
$router
/$store
等属性(原因),当然也有以下方式来解决该问题。mount(Component, { ... data: { $store: this.$store, // 为什么不是 $router? VueRouter 在内部使用了 Object.defineProperty 方法并只设置了 getter 属性,故在该组件无法覆盖这个值 router: this.$router, ... }, ... });
随后可在组件内部使用
this.$store
/this.router
来得到该值。 -
当组件已经挂载在原根实例上,但在组件的
created
/mounted
等生命周期内获取不到该值时,需要使用 VueMount 内置的事件 来解决:mount(Component, { ... on: { 'mount:mount'(vm) { vm.$router; vm.$store; } }, ... }
原因是现版本 VueMount 在内部统一在组件挂载之后才计算父组件取值。