概述
首先,这里提到的骨架屏组件并不是指一个显示为骨架屏的组件,指的是一个容器 fallback,骨架屏和真实的组件作为两个 slot 置于 fallback 中。fallback 监听 fallback:show
事件,用于控制显示某个 slot。
实现
初版
这个需求实现起来是很简单的,通常会写成这样:
1 | <template> |
已知问题
但这种写法并不完美,因为外层元素已经写明了是 div
,考虑一种情况,比如我要给 nav
中选项设置 fallback,那么这样就直接在 nav
中多加了一层 div
,从 HTML 语义的角度来看是不对的,语义被改变了:
1 | <nav> |
还有一种情况,比方说有个 Flex 容器,我要给他的 item 设置 fallback,那么 fallback 加的一层 div
直接就破坏了 Flex 布局的结构:
1 | <div flex="main:center"> |
当然了,解决方法还是有的,那就是移除最外层的 Flex 容器,将 fallback 变成一个 Flex 容器,但这又回到了问题 1 上。
改版
为了将初版整合进项目,我改了很多容器元素的样式,我觉得这不是一个很好的解决方案,所以我又对他进行了改进。
理想的状态是,不要外层 div
元素,因为元素类型在开发环境中是不确定的,起到关键作用的只是两个 slot,所以只需要在两个 slot 之间切换就行了,但是这种写法在 template 中肯定无法实现,因为根元素只能有一个(即时用了 v-if 和 v-else 二选一),同时 template 也不能成为根元素。
这个时候就需要使用 render 函数了,通过 createElement 动态构建一个模版:
1 | render (h) { |
与单文件组件中的 template 不一样,这里是可以作为根元素使用的,并且实现了 v-if 与 v-else 的效果,还不会被编译器理解成要设置多个根元素。
1 | <fallback> |