解锁 Vue 3 神奇技巧:让模板复用达到极致
写在最前
看官们好,我叫JetTsang,之前都是在掘金潜水来着,现在偶尔做一些内容输出吧。
如果你觉得本文对你有所帮助,不妨给我一个点赞和收藏,这将是对我最大的鼓励。
引出
在vue的日常开发当中,我们可能会遇到这样的一种情况:
某一部分的模版需要重复利用, 但又不至于到新开1个组件的地步。
比如:
<template>
<div v-for="item in list">
// 条件渲染
<div v-if="isCase1(item.id)" class="case1Class ...">
<h2>{{ item.title }}</h2>
<p class="...">{{ item.content }}</p>
<span> {{ item.cases }} </span>
</div>
<p v-else-if="isCase2(item.id)" class="case2Class ...">{{ item.content }}</p>
<span v-else="isCase3(item.id)"> {{ item.cases }} </span>
// 条件可能有更多....
</div>
</template>
这里面的<p>
<span>
都是可以复用的,但为此新开俩组件又没有必要。
那么又有什么解决方案呢?
来自react的提示
在react 当中啊,碰到这种情况,可以定义1个 局部的函数式组件
示例:
function Com () {
// 局部组件
const ReuseP = ({content,className})=> (<p className={`${className} ...其余复用class`}>{ content }</p> )
return (
list.map(i=>{
if(isCase1(i.id)){
return (
<div>
{/* ... */}
{/* 在这里去复用 */}
<ReuseP {...i} className="case2Class" />
</div>
)
}
})
)
}
回到vue
那么在Vue当中能不能实现呢? 答案显然是可以的
其实在Vue3当中,可以支持在.vue
文件即SFC
当中去使用jsx/tsx
语法的
看看文档
是不是很熟悉,这不就是react当中的函数式组件么
也就是说,可以将上面的例子改写成这样
<template>
<div v-for="item in list">
// 条件渲染
<div v-if="isCase1(item.id)" class="case1Class ...">
<h2>{{ item.title }}</h2>
- <p class="...">{{ item.content }}</p>
+ <reuseP v-bind="item"/>
<span> {{ item.cases }} </span>
</div>
- <p v-else-if="isCase2(item.id)" class="case2Class ...">{{ item.content }}</p>
+ <reuseP v-else-if="isCase2(item.id)" v-bind:content="item.content" v-bind:your-class="'case2Class'" ></reuseP>
<span v-else> {{ item.cases }} </span>
// 条件可能有更多....
</div>
</template>
+ // ⚠️ 注意这里的lang
+ <script setup lang="jsx">
+ const reuseP = ({ content }) => (
+ <p className={`${args['your-class']} ...其余复用class`}>{ content }</p>
+ )
+ </script>
可以清晰的看到在.vue文件即Vue但文件组件(SFC)
里面通过jsx去实现了一个组件内的小组件
,进而达到了组件内模版复用的效果。
ps: 当然这里只是举例了可以复用
<p>
的例子,你也可以更加优雅的去实现,比如把整个v-for都用jsx写一下
大概的代码结构会是这样
当然,这里只是给大家提供一个思路,jsx与template的结合是相当灵活的,不过相信聪明的看官们能够轻松应对。
也许有看官还不了解jsx
回顾
首先回顾一下vue模版语法的编译产物
它其实是将模版也解析成渲染函数
的形式
这里的createElementVNode
其实就是h函数
,作用是创建VNode
那么整一个渲染函数的作用就是结合 上下文对象
生成VNode
VNode就是用对象去描述DOM节点(WEB端)
比如这样一个真实DOM
对应的虚拟VNode的核心描述
const vnode = {
tag: 'div', // 标签名为 'div'
data: {}, // 无属性、样式和事件等信息
children: [
{
tag: undefined, // 文本节点没有标签名
data: {}, // 无属性、样式和事件等信息
children: undefined,
text: 'Hello JetTsang' // 文本内容为 'Hello JetTsang'
}
],
text: undefined,
//。。。省略
};
当然,在Vue和React中,对于VNode结构的描述存在一些区别,包括不同的属性等等。然而,它们的本质都是以一种数据结构来描述真实节点。
这例子当中VNode就是外面的这个div(当然忽略_openBlock
这个块级容器 )
jsx
其实JSX和模版语法一样,借助@vue/babel-plugin-jsx
,也能转换成渲染函数
拿一个最简单的例子🌰
渲染模版<h1>Hello JetTsang</h1>
可以看到无论是生成的VNode还是渲染函数都是一样的
你说它有什么缺点吗? ??
还记得vue3对模版编译是有做优化的,如果你用jsx的话,应该是
有一部分模板编译优化
是无法用在jsx里面的。当然vue3团队对jsx应该也是有一些编译优化的。
这里先埋个坑,后续再填~~
另一种选择
当然啰,可能有些看官不是很喜欢Jsx,我就想在模版里面去复用又不想重新封装组件,那么还有其他的解决方案吗?
既然我都这么问了,当然是有的啰
在这里推荐VueUse 里面的组件 createReusableTemplate
是这么去使用的
更多的用法就看官们自己去研究啦~
写在最后
在vue当中使用jsx和react还是有一些区别的,比如使用到插槽
、事件修饰符
、指令
等等
具体可以查阅官方文档
相信读完会更加了解vue当中的模版语法和jsx的本质。
如果你觉得本文对你有所帮助,不妨给我一个点赞和收藏,这将是对我最大的鼓励。
转载自:https://juejin.cn/post/7250503852817547324