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

2023-07-0208:49:18WEB前端开发Comments581 views字数 2534阅读模式

引出

在vue的日常开发当中,我们可能会遇到这样的一种情况:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

某一部分的模版需要重复利用, 但又不至于到新开1个组件的地步。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

比如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

<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> 都是可以复用的,但为此新开俩组件又没有必要。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

那么又有什么解决方案呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

来自react的提示

在react 当中啊,碰到这种情况,可以定义1个 局部的函数式组件文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

示例:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

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当中能不能实现呢? 答案显然是可以的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

其实在Vue3当中,可以支持在.vue文件即SFC当中去使用jsx/tsx语法的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

看看文档文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

是不是很熟悉,这不就是react当中的函数式组件么文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

也就是说,可以将上面的例子改写成这样文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

<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去实现了一个组件内的小组件,进而达到了组件内模版复用的效果。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

ps: 当然这里只是举例了可以复用<p>的例子,你也可以更加优雅的去实现,比如把整个v-for都用jsx写一下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

大概的代码结构会是这样文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

当然,这里只是给大家提供一个思路,jsx与template的结合是相当灵活的,不过相信聪明的看官们能够轻松应对。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

也许有看官还不了解jsx

回顾

首先回顾一下vue模版语法的编译产物文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

它其实是将模版也解析成渲染函数的形式文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

这里的createElementVNode其实就是h函数,作用是创建VNode文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

那么整一个渲染函数的作用就是结合 上下文对象 生成VNode文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

VNode就是用对象去描述DOM节点(WEB端)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

比如这样一个真实DOM文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

对应的虚拟VNode的核心描述文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

const vnode = {
  tag: 'div', // 标签名为 'div'
  data: {},   // 无属性、样式和事件等信息
  children: [
    {
      tag: undefined, // 文本节点没有标签名
      data: {},       // 无属性、样式和事件等信息
      children: undefined,
      text: 'Hello JetTsang' // 文本内容为 'Hello JetTsang'
    }
  ],
  text: undefined
  //。。。省略
};

当然,在Vue和React中,对于VNode结构的描述存在一些区别,包括不同的属性等等。然而,它们的本质都是以一种数据结构来描述真实节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

这例子当中VNode就是外面的这个div(当然忽略_openBlock这个块级容器 )文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

jsx

其实JSX和模版语法一样,借助@vue/babel-plugin-jsx,也能转换成渲染函数文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

拿一个最简单的例子🌰文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

渲染模版<h1>Hello JetTsang</h1> Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

可以看到无论是生成的VNode还是渲染函数都是一样的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

你说它有什么缺点吗? ??文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

还记得vue3对模版编译是有做优化的,如果你用jsx的话,应该是 有一部分模板编译优化是无法用在jsx里面的。当然vue3团队对jsx应该也是有一些编译优化的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

这里先埋个坑,后续再填~~文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

另一种选择

当然啰,可能有些看官不是很喜欢Jsx,我就想在模版里面去复用又不想重新封装组件,那么还有其他的解决方案吗?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

既然我都这么问了,当然是有的啰文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

在这里推荐VueUse 里面的组件 createReusableTemplate文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

是这么去使用的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

更多的用法就看官们自己去研究啦~文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

写在最后

在vue当中使用jsx和react还是有一些区别的,比如使用到插槽事件修饰符指令等等文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

Vue 3 神奇技巧:让模板复用达到极致 具体可以查阅官方文档文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

相信读完会更加了解vue当中的模版语法和jsx的本质。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html

作者:JetTsang
来源:稀土掘金
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/49204.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/49204.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定