在阅读这篇文章之前,建议先阅读这篇文章 r{{ changeThemeOnce({primary: '#39C5BB', secondary: '#92E8C6', accent: '#BCFF64'}) }}
在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法。递归一词还较常用于描述以自相似方法重复事物的过程。递归不仅可以被用于函数中,许多事物的结构就是递归的,例如,数据结构中树的结构就是一个典型的递归的结构;其子树本身也是树。
这样的结构可以简单地描述为:
type Tree<T> = {
value: T
children: Tree<T>[]
}
为了制造一个递归的DOM,最朴素的想法便是使用一个递归函数Comment => Node,然而遗憾的是,在Vue中最小的复用单位是组件。
当然,这难不倒我们睿智的YYX大神,你只用给一个组件定义好Props,然后给予一个适当的名字就好了嘛。
说实话,it sucks<template>
<div>
{{ tree.value }}
<ul>
<li v-for="child in tree.children" :key="child.value">
<recursive :tree="child"></recursive>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'recursive',
props: {
tree: {
type: Object
}
}
}
</script>
我为此必须使用一个文件,我使用递归组件的理由可能有许多,有时可能不需要复用,但是如果一直逼着我要创建一个相对较重组件,总是十分糟心的。
当然你可以不用创建文件,使用Vue.component等方法将会污染全局命名空间,这个过程是不可控的(因为有时候我偷懒想要取一个简单的名字) 这个过程本身也比较糟心
总之,为了递归使用一个组件,其中的语法噪音太多。
看见 Component => Node
这个type的函数,自然会想到Vue的JSX写法,虽然需要组件,但是组件本身可以有很多的递归函数,可以灵活地组合,不必每一个递归组份都额外写一个组件。
比起原本的template写法,JSX写法只用写出组件中的render: (CreateElement, RenderContext<Props>) => VNode
方法即可。
之前中了React 和 TSX的毒,故这里直接介绍TSX写法,但是不得不吐槽Vue对TS的支持真的不是十分理想。
比起单文件组件,JSX写法的官方文档很少,更不用说TSX&Class写法了。
现在Component的写法也有很多,有class写法和原本的plain object写法。
class 写法需要一个辅助的依赖vue-tsx-support
export default tsx.componentFactoryOf<{
tree: Tree<string>
}>().create({
props: {
tree: Object
},
render() {
return this.renderTree(this.tree as Tree<string>)
},
methods: {
renderTree<T>(tree: Tree<T>) {
return (
<div>
{tree.value}
<ul>
{
tree.children.map((t, i) => (
<li key={i}>{this.renderTree(t)}</li>
))
}
</ul>
</div>
)
}
}
})
这个蛋疼的是Props是一个Value,而TS不支持类型为一等公民,因此必须传入Object,在使用的时候再转换成对应类型;为了在写的时候有友好的类型提示,这个Props你还必须写两遍,这个是最糟糕的。而且目前大多数Vue的库对TSX的支持还是不友好,我写代码的时候是全程没有type hint的,十分糟心。
希望有一天能够支持函数组件,组件可以是一个函数,像react那样。那么Vue就成了
Roselia{{ btn('哦,我喜欢这个主题!', saveCurrentTheme, 'primary') }}