您好,欢迎来到年旅网。
搜索
您的当前位置:首页Vue3: 单文件(SFC)输出多组件解决方案.理解defineComponent及如何使用

Vue3: 单文件(SFC)输出多组件解决方案.理解defineComponent及如何使用

来源:年旅网

今天看到vue组件部分的知识.就想顺手写一个组件集合的文件.类似于

const ComponentA () => {
   //xxxxx
}

const ComponentB () => {
   //xxxxx
}

const ComponentC () => {
   //xxxxx
}

export {
    ComponentA,
    ComponentB,
    ComponentC
}

可以封装函数式组件或者函数式方法的这么个函数集合.这种写法在React中是很常见的.但是今天切换到Vue可让我重新了认识了vue的组件的复杂度了.首先并不是写起来多复杂,而是有不同的写法,写法不一样,效果也不一样,也不同...

那怎么能写出跟React风格一样的这种组合式的函数集呢.

为什么要写这个集合

首先聊下为什么要写这种集.就我个人习惯而言,习惯把工具函数单独放到一个文件下,而组件呢也是相同的或者有关联的小的共同组件放到一个文件,例如一些像input 带 icon, tooltip,  v model这些使用频率比较多的小组件放到一起. 正如我上面说的在React下很轻松的一件事.但是在vue中,因为vue是SFC.与其说是推荐更是强制一个文件一个组件的方式.但是十几行代码的组件放一个文件,当项目文件越来越多后,这些共用小组件一个个的散落在不同文件下显然对整个项目的文件架构有一定影响.写2+个import 和写一个import区别有目共睹.

解决方案

那有没有办法一个文件里写多个组件然后输出呢。

其实关键点就是export,如果export多个组件就是解决问题的关键.网上翻看了一些资料,然后结合官网又看找了下,构建组件的defineComponent 方法提供了export的功能.于是开始实践.

网上很多资料没有提到具体的实现,csdn上很多小伙伴的讲解也都是些文字的概念有头无尾的.说了一堆概念,最后还得落实到代码上.毕竟没有结果的说明不知道是否真的使用过.

首先defineComponent 这个函数,从名字就可以看出可以构建出一个组件.但是这个组件不支持set up 这种组合式的编写(吐槽下哈 vue的组合式和选项式,真是对新手太不友好,一套语言2中写法)
 

构建defineComponent方法

// 子组件 child component
<script  lang="ts">
import {defineComponent, h } from 'vue'

 export default defineComponent({
         props:{
            txt:String,
         },
         name: "ComponentA",
         setup(props, ctx) {
            const count = ref(0)
            const add = () => {
                 count.value++
            }
            return { state,increment }
         },
 })

<template>
        <div>
               <button @click="increment">{{ state }}</button> 
        </div>
</template>


首先用defineComponet声明一个的函数组件,

接受父组件的传过来的参数txt, 并且设置组件名称ComponentA
设置setup的方法进行一些逻辑的计算,这里可以用计算模式
输出最后组件模版。

父组件中

// 父组件


<script setup lang="ts">
import * as Children from './children.vue'
import {ref, defineModel} from 'vue'
</script>
<template>
    <div>
        <KeepAlive>
            <div>
                <Children txt="from parent component ref"/>
            </div>
        </KeepAlive>
    </div>
</template>

开到这里,你可能会问,着不就是一个单文件一个组件吗.的确,这就是关于defindeComponent网上的一些使用的写法,只不过没这么具体

接下来我们要改成我们的多组件形式

多组件形式

<script  lang="ts">
import {defineComponent, h, ref } from 'vue'

        const ComponentA = defineComponent({
                props: { txt:String},
                setup(props, ctx) {
                   const count = ref(0)
                   const increment = () => {
                        count.value++
                   }
                   return () => h('div', {id: 'foo'},
                    ['', h('div',{onClick: increment} ,props.txt),
                          h('div', count.value)])
                },
        })
 
        const ComponentB = defineComponent ({
                props:{
                  title: String,
                  cut:() => {}
                },
                setup(props, ctx) {
                const {cut} = props
                  return () => h('div', ['ddd', h('div',{onClick: cut}, props.title)])      
                },
        })

        export {ComponentA, ComponentB}
</script>


这里首先我们删掉了template标签,因为在多组件文件中,并不知道你具体选用的哪个一个模版

但是组件函数是必须要有模版输出的,其实defineComponet中提供一个template的属性,可以编写

template: `<div> you ref value </div>`

但是加了这个就会马上有一个警告需要你去更改vue的build配置,原因就是解析不到template下能够抓换成html的vue代码,有点难懂是吧.说白了没法转译,可能在单组件下可行吧,但是单组件下写defineComponent这种不是很麻烦吗?vue真是提供了好多方法去实现一个东西.

回到上面的代码来.既然模版不能用template那怎么输出?


模版输出


这里的模版输出是在setup 的return中使用h库进行的jsx方式输.说实话写jsx虽然很易懂但是很容易写错,而且易懂性真的不高,但是执行的效率上,编码速度上有很大优势.

    return () => h('div', {id: 'foo'},
                    ['', h('div',{onClick: increment} ,props.txt),
                          h('div', count.value)])
                },

这样就生成了一个

这种结构的dom树

然后在父组件我们就可以按照我喜欢的react风格引用

import {ComponentA, ComponentB} from './com2.vue'

<template>
    <ComponentA txt="222"/>
// 这里还可以传递事件函数,对象数组,在子组件中用propos接受就可以
    <ComponentB title="multi component" />
</template>

输出结果

当我点击子组件ComponentA的button ->222 (222其实这是个按钮名),下面的0会调用子组件++的逻辑开始执行,这里我点了4下

至此解决了单文件多组件的问题。但是写到着我也理解为什么了vue不这么写组件集了.太费劲了,下不说jsx写起来就挺费劲的.如果组件传递参数多样,加上expend的扩展, 各自事件绑定和自定义事件 .还有加上emit 又可能遇到透传.真就是改起来不入写一个新的单组件了.

最后还是给出另一个方法如果想用就单独写个uitls文件自己整合下,如下
还可以放函数表达式

// list.js
import ComponentA form './ComponentA.vue'
import ComponentB form './ComponentB.vue'

export {
    ComponentA,
    ComponentB
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- oldu.cn 版权所有 浙ICP备2024123271号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务