Vue2创建虚拟节点的方法

有一个项目是用Vue2和Ant Design Vue搭建的,其中一个需求是在main.js中发送一个请求,然后根据响应判断需不需要弹出一个Ant Design Vue的Modal弹窗。

Antd的Modal支持直接调用函数来显示弹窗,但是需求中里弹窗里面的内容不仅仅是纯文字,因此只能在Modal里的content里传入h函数或者虚拟节点了。

在Vue3中,这个需求可以直接通过引入h函数创建虚拟节点实现,但是在Vue2中是不可以的,需要用另外的写法来实现。

在Vue2中,如果像Vue3那样引入h函数来创建虚拟节点,是会报错的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Vue, { h } from "vue";
import Antd, { Modal } from "ant-design-vue";
import App from "./App.vue";
import "ant-design-vue/dist/antd.css";

Vue.config.productionTip = false;
Vue.use(Antd);

// Vue2中会报错!!
var content = h("h1", "Hello World!");

new Vue({
render: (h) => h(App),
}).$mount("#app");

Modal.warning({
content: content,
});

报错内容:

1
[Vue warn]: globally imported h() can only be invoked when there is an active component instance, e.g. synchronously in a component's render or setup function.

意思是全局引入的h函数,h函数只能用在组件实例里的render函数或者setup函数,像上面那样在全局上下文中调用h函数是不支持的。

解决办法十分简单,只要改变h函数调用时的上下文即可,办法就是类似上面创建Vue实例的render函数一样,将content的值写成一个对象,里面包含一个render函数,函数接收h函数作为参数,返回h函数创建的虚拟节点即可。

1
2
3
4
5
6
7
Modal.warning({
content: {
render(h) {
return h("h1", "666");
},
},
});

还可以简化成这样:

1
2
3
Modal.warning({
content: (h) => h("h1", "666"),
});

当然也可以写成这样:

1
2
3
4
5
var vnode = (h) => h("h1", "Hello World!");

Modal.warning({
content: vnode,
});

完美解决问题。