likes
comments
collection
share

解锁 Vue 3 神奇技巧:让模板复用达到极致

作者站长头像
站长
· 阅读数 16

写在最前

看官们好,我叫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语法的

看看文档

解锁 Vue 3 神奇技巧:让模板复用达到极致

是不是很熟悉,这不就是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写一下

大概的代码结构会是这样

解锁 Vue 3 神奇技巧:让模板复用达到极致

当然,这里只是给大家提供一个思路,jsx与template的结合是相当灵活的,不过相信聪明的看官们能够轻松应对。

也许有看官还不了解jsx

回顾

首先回顾一下vue模版语法的编译产物

解锁 Vue 3 神奇技巧:让模板复用达到极致

它其实是将模版也解析成渲染函数的形式

这里的createElementVNode其实就是h函数,作用是创建VNode

解锁 Vue 3 神奇技巧:让模板复用达到极致

那么整一个渲染函数的作用就是结合 上下文对象 生成VNode

VNode就是用对象去描述DOM节点(WEB端)

比如这样一个真实DOM

解锁 Vue 3 神奇技巧:让模板复用达到极致

对应的虚拟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> 解锁 Vue 3 神奇技巧:让模板复用达到极致

可以看到无论是生成的VNode还是渲染函数都是一样的

你说它有什么缺点吗? ??

还记得vue3对模版编译是有做优化的,如果你用jsx的话,应该是 有一部分模板编译优化是无法用在jsx里面的。当然vue3团队对jsx应该也是有一些编译优化的。

这里先埋个坑,后续再填~~

另一种选择

当然啰,可能有些看官不是很喜欢Jsx,我就想在模版里面去复用又不想重新封装组件,那么还有其他的解决方案吗?

既然我都这么问了,当然是有的啰

在这里推荐VueUse 里面的组件 createReusableTemplate

是这么去使用的

解锁 Vue 3 神奇技巧:让模板复用达到极致

更多的用法就看官们自己去研究啦~

写在最后

在vue当中使用jsx和react还是有一些区别的,比如使用到插槽事件修饰符指令等等

解锁 Vue 3 神奇技巧:让模板复用达到极致 具体可以查阅官方文档

相信读完会更加了解vue当中的模版语法和jsx的本质。

如果你觉得本文对你有所帮助,不妨给我一个点赞和收藏,这将是对我最大的鼓励。