0

0

Vue3复用组件怎么使用

PHPz

PHPz

发布时间:2023-05-20 19:25:13

|

1571人浏览过

|

来源于亿速云

转载

    前言

    无论是 vue 还是 react,当遇到多处重复代码的时候,我们都会想着如何复用这些代码,而不是一个文件里充斥着一堆冗余代码。

    实际上,vue 和 react 都可以通过抽组件的方式来达到复用,但如果遇到一些很小的代码片段,你又不想抽到另外一个文件的情况下,相比而言,react 可以在相同文件里面声明对应的小组件,或者通过 render function 来实现,如:

    const Demo: FC<{ msg: string}> = ({ msg }) => {
      return 
    demo msg is { msg }
    } const App: FC = () => { return ( <> ) }
    /** render function的形式 */
    const App: FC = () => {
      const renderDemo = (msg : string) => {
        return 
    demo msg is { msg }
    } return ( <> {renderDemo('msg1')} {renderDemo('msg2')} ) }

    但对于 .vue 模板 来说,没法像 react 一样在单个文件里面声明其他组件,如果你要复用代码,那就只能通过抽离组件的方式。

    可是啊可是啊!就如上面 Demo 组件,就零零散散两三行代码,抽成一个组件你又觉得没太必要,那唯一的解决方案就是 CV 大法?(当然,如果是诸如 list 之类的,可以用 v-for 代码,但这里介绍的不是这种场景)

    我知道你很急,但你先别急。如果我们可以通过在组件范围内将要复用的模板圈起来,跟 vue 说,喂,这代码是我圈起来的,因为我有好几处要用到,虽然目前你看起来好像不支持这功能,不过,没事,你实现不了的,我来实现

    立即学习前端免费学习笔记(深入)”;

    那大致实现方案就是这样子啦:

    Vue3复用组件怎么使用

    可是,这种方案究竟如何实现呢?毕竟牛都已经吹上天了,实现不了也要硬着头皮折腾。好了,不卖关子,antfu 大佬实际上已经实现了,叫做createReusableTemplate,且放到 VueUse 里面了,具体可以点击文档看看。

    用法

    通过 createReusableTemplate 拿到定义模板和复用模板的组件

    然后在你要复用代码的地方,将其用DefineTemplate包起来,之后就可以通过ReuseTemplate在单文件 template 的任意地方使用了:

    ⚠️ DefineTemplate 务必在 ReuseTemplate 之前使用

    我们看到,createReusableTemplate 返回了一个 Tuple,即 define 和 reuse 的组件对,然后,通过上面的例子就可以在单文件里面复用多处代码了。

    还有,实际上还可以通过对象解构的方式返回一个 define 和 reuse(很神奇吧,这篇文章就不展开了,有兴趣下次再分享下),用法同上,例子如下

    
    

    Vue3复用组件怎么使用

    真是神奇,那咋实现呢

    上面我们介绍了用法,相信应该没人看不懂,上手成本确实为 0,那接下来我们一起看看是如何实现的。

    我们知道,Vue3 定义组件除了通过 script setup 的方式之外, 还可以通过defineComponent的方式

    const Demo = defineComponent({
      props: {
        ...,
      },
      setup(props, { attrs, slots }) {
        return () => {
          ...
        }
      }
    })

    然后我们观察下是如何定义模板的

    
        
    Foo: {{ msg }}

    好像似曾相识?v-slot?,诶,卧槽,这不是插槽吗!还有,模板代码看起来就是放在默认插槽的。

    好,我们接下来看下如何实现 Define 的功能。

    实现 Define

    我们刚才说,模板是定义在默认插槽里面,那我们可以定义个局部变量 render,之后当在 template 里面使用 Define 时会进入 setup,这时候拿到 slot.default,放在 render 上不就好?,代码如下

    let render: Slot | undefined
    const Define = defineComponent({
      setup(props, { slots, }) {
        return () => {
          /** 这里拿到默认插槽的渲染函数 */
          render = slots.default
        }
      }
    })

    对的,就是这么简单,对于 Define 来说,核心代码就是这两三行而已

    实现 Reuse

    上面拿到 render function 了,那我们在使用 Reuse 的地方,将所得到的 v-slot、attrs 等传给 render 不就好?

    同样,当我们在 template 使用 Reuse 的时候,就会进入 setup,然后将得到的参数都传给 render,并 return render 的结果即可

      const reuse = defineComponent({
        setup(_, { attrs, slots }) {
          return () => {
            /**
             * 没有render,有两种可能
             * 1. 你没Define
             * 2. Define写在Reuse后面
             **/
            if (!render && process.env.NODE_ENV !== 'production')
              throw new Error(`[vue-reuse-template] Failed to find the definition of template${name ? ` "${name}"` : ''}`)
            return render?.({ ...attrs, $slots: slots })
          }
        },
      })

    上面的 attrs 也就是你在 Reuse 上传的 prop 了

    而为啥还要传个$slots?

    珑大极简商城系统
    珑大极简商城系统

    珑大极简商城系统,北京珑大钜商科技有限公司使用PHP语言基于laminas + doctrine2 组合框架开发完成。系统如其名称 极简,从DBShop商城系统衍生而来。去掉复杂的功能,只保留基础在线销售功能,提供给商家免费使用。需要建立在线商城的商家分为两种 1)需要复杂的在线商城系统处理各种商品销售及促销(DBShop商城系统); 2)只需要一个简单的在线商品展示或者在线订货系统,不需要那么复

    下载

    上面实际上有个例子,模板里面还可以通过动态组件的方式来拿到插槽的真正内容

    
        
    Biz: {{ msg }}
    This is a slot from Reuse
    This is another one

    Vue3复用组件怎么使用

    当然,不只默认插槽啦,其他具名插槽都可以

    
        
        
    Biz: {{ msg }}
    This is a slot from Reuse
    This is another one

    Vue3复用组件怎么使用

    具体怎么玩出花,你来定~

    类型支持,提升开发体验

    我们定义了模板,但模板接收什么参数,传入什么参数,你得告诉我对不对,如果没有类型的提示,那么开发体验会极其糟糕,不过,不用担心,大佬这些都考虑好了。

    createReusableTemplate 支持泛型参数,也就是说你要复用的模板需要什么参数,只需要通过传入对应类型即可,比如你有个 msg,是 string 类型,那么用法如下

    const [DefineFoo, ReuseFoo] = createReusableTemplate<{ msg: string }>()

    然后你就会发现,DefineFoo, ReuseFoo 都会对应的类型提示了

    添加类型支持

    我们上面说是用 defineComponent 得到 Define 和 Reuse,而 defineComponent 返回的类型就是 DefineComponent 呀

    type DefineComponent

    假设模板参数类型为 Bindings 的话,那么对于 Reuse 来说,其既支持传参,也支持添加插槽内容,所以类型如下

    type ReuseTemplateComponent<
      Bindings extends object,
      Slots extends Record,
      /** Bindings使之有类型提示 */
    > = DefineComponent & {
     /** 插槽相关 */
      new(): { $slots: Slots }
    }

    而对于 Define 类型来说,我们知道其 v-slot 也有对应的类型,且能通过$slots 拿到插槽内容,所以类型如下

    type DefineTemplateComponent<
     Bindings extends object,
     Slots extends Record,
     Props = {},
    > = DefineComponent & {
      new(): { $slots: { default(_: Bindings & { $slots: Slots }): any } }
    }

    小结一下

    ok,相信我开头说的看懂只需要 1 分钟不到应该不是吹的,确实实现很简单,但功能又很好用,解决了无法在单文件复用代码的问题。

    我们来小结一下:

    • 通过 Define 来将你所需要复用的代码包起来,通过 v-slot 拿到传过来的参数,同时支持渲染其他插槽内容

    • 通过 Reuse 来复用代码,通过传参渲染出不同的内容

    • 为了提升开发体验,加入泛型参数,所以 Define 和 Reuse 都有对应的参数类型提示

    • 要记住使用条件,Define 在上,Reuse 在下,且不允许只使用 Reuse,因为拿不到 render function,所以会报错

    加个彩蛋吧

    实际上多次调用 createReusableTemplate 得到相应的 DefineXXX、ReuseXXX 具有更好的语义化Vue3复用组件怎么使用

    Vue3复用组件怎么使用

    也就是说,我不想多次调用 createReusableTemplate 了,直接让 define 和 reuse 支持 name 参数(作为唯一的 template key),只要两者都有相同的 name,那就意味着它们是同一对

    如何魔改

    实际上也很简单,既然要支持 prop name来作为唯一的 template key,那 define 和 reuse 都添加 prop name 不就好?

      const define = defineComponent({
        props {
          name: String
        }
      })
      const reuse = defineComponent({
        props {
          name: String
        }
      })

    然后之前不是有个 render 局部变量吗?因为现在要让一个 Define 支持通过 name 来区分不同的模板,那么我们判断到传入了 name,就映射对应的的 render 不就好?

    这里我们通过 Map 的方式存储不同 name 对应的 render,然后 define setup 的时候存入对应 name 的 render,reuse setup 的时候通过 name 拿到对应的 render,当然如果没传入 name,默认值是 default,也就是跟没有魔改之前是一样的

    const renderMap = new Map()
    const define = defineComponent({
        props: {
          /** template name */
          name: String,
        },
        setup(props, { slots }) {
          return () => {
            const templateName: string = props.name || 'default'
            if (!renderMap.has(templateName)) {
              // render = slots.default
              renderMap.set(templateName, slots.default)
            }
          }
        },
      })
      const reuse = defineComponent({
        inheritAttrs: false,
        props: {
          name: String,
        },
        setup(props, { attrs, slots }) {
          return () => {
            const templateName: string = props.name || 'default'
            const render = renderMap.get(templateName)
            if (!render && process.env.NODE_ENV !== 'production')
              throw new Error(`[vue-reuse-template] Failed to find the definition of template${templateName}`)
            return render?.({ ...attrs, $slots: slots })
          }
        },
      })

    相关专题

    更多
    string转int
    string转int

    在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

    315

    2023.08.02

    typedef和define区别
    typedef和define区别

    typedef和define区别在类型检查、作用范围、可读性、错误处理和内存占用等。本专题为大家提供typedef和define相关的文章、下载、课程内容,供大家免费下载体验。

    107

    2023.09.26

    define的用法
    define的用法

    define用法:1、定义常量;2、定义函数宏:3、定义条件编译;4、定义多行宏。更多关于define的用法的内容,大家可以阅读本专题下的文章。

    335

    2023.10.11

    堆和栈的区别
    堆和栈的区别

    堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

    389

    2023.07.18

    堆和栈区别
    堆和栈区别

    堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

    571

    2023.08.10

    golang map内存释放
    golang map内存释放

    本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

    75

    2025.09.05

    golang map相关教程
    golang map相关教程

    本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

    32

    2025.11.16

    golang map原理
    golang map原理

    本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

    59

    2025.11.17

    Golang gRPC 服务开发与Protobuf实战
    Golang gRPC 服务开发与Protobuf实战

    本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

    8

    2026.01.15

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Vue3.x 工具篇--十天技能课堂
    Vue3.x 工具篇--十天技能课堂

    共26课时 | 1.4万人学习

    Vue3.x 核心篇--十天技能课堂
    Vue3.x 核心篇--十天技能课堂

    共30课时 | 1.5万人学习

    Vue3.x新特性篇--十天基础课堂
    Vue3.x新特性篇--十天基础课堂

    共20课时 | 1.2万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号