Vue模板中使用vnode

现在的项目都是以 vue 为主的技术栈,而 vue 的模板语法在大多数情况下使用体验都还算不错,但在某些情况下则有些不尽人意。

其实起因很简单,就是自己作 😄。

需求是根据不同的条件渲染出不同视图,这样的需求大家都见怪不怪了,也没什么难度。不过就是这条件多了点,多写一些模板而已。但我是什么人,美特斯·邦威(不走寻常路)。写大量的模板这种 Low B 行为配的上我么,所以我一点模板都不想写。

归其原因是我认为大量的模板太影响可读性了,不具备良好的可维护性。那么接下来有两个解决办法(虽然归根结底只能算一个):

  1. 通过计算属性(方法函数都一样),为需要显示的内容添加到 vue 的依赖收集里面,再经过模板渲染
  2. 定义一个 render 函数,然后再模板中使用这个 render 函数。

作为一个喜欢作死的人,我毫不犹豫的选择了第二种,毕竟 render 函数里面再写一点 jsx,瞬间就可以拉开我与菜 B 的差距,想到这里我情不自禁的微微上扬了嘴角。说做就做吧,毕竟我是一个行动派,于是写出了下面的四不像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
{{ renderFun() }}
</div>
</template>
<script>
export default {
methods: {
renderFun() {
return <div>xxx</div>;
},
},
};
</script>

是不是有一点熟悉又陌生的感觉,我天真的以为就这么简单。事实上这是一个错误的写法,在 vue 中 vnode 只会在 render 函数中出现,其余地方没有意义。

现实给了我当头一棒,可我会是一个向困难屈服的人吗,明显不是的,我就琢磨这这么让我这种风骚的语法变为现实。在 baidu 一番后,发现还是有不少人和我一样被困于此。终于在segmentfault上找到了答案。下面就总结一下怎么实现模板中实现 render 函数。

当你一个组件参数传递过来是 vnode 的时候,就涉及到 template 上使用 vnode 的情况。
如果你举例 element 的话,可以看看 element 的 message-box 组件,它的 message 参数就可以传递 vnode,作为内容扩展组件。

另外,可以看看 https://github.com/ElemeFE/el… 第 96 行,也是跟我回答的答案几乎是一样的做法,把 vnode 赋予给 slot 在 template 上使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
<slot></slot> //此处修改为slot
</div>
</template>

<script>
export default {
methods: {
renderChild() {
return <div>Child</div>; //在vue jsx插件 3.4.0 之后, h 会自动注入
},
},
created() {
this.$slots.default = [this.renderChild()]; //其实原理就是手动给slot赋值。
},
};
</script>

参考文章:vue template 如何可以使用 vnode ?

[越努力,越幸运!]