关于Vue组件化的疑惑

请花15秒观察下图,后续将对部分 UI 实现组件化:
图片描述

通过分析以上UI图,可以发现“我的家人”、“家庭必备保障” 的UI 具有很强的相似性。
于是,我打算将这块封装成一个组件,名为 ItemBoard.vue(项目面板),对应下图绿色框。

图片描述

这个组件可配置的地方就在于面板标题和包含的列表项。可见,传给该组件的数据便是一个标题字符串和一个数组,我将这两个数据作为它的props传进来。它承担的UI功能是遍历展示列表项,并决定列表项间的间距,以及是否需要在列表项下面显示一条细线。

为了灵活性考虑,我将单个列表项也封装成了一个组件,名为 Item.vue,对应上图的红色框。该组件的UI可以分成左右两部分,如上图黑线分隔。左边部分对于所有用例来说都是完全一样的:头像、名称、描述。唯独右边部分有的是文字,有的是箭头>,有的是垃圾桶图标。所以,该组件的右侧具体显示成什么,应该由使用 Item 的组件来决定,即由 ItemBoard 决定。Vue 提供了 slot 语法让父组件向子组件传递 UI 内容。
Item.vue UI实现大致为:
<template>

<div class="left”>…...</div>
<div class=“right”>
    <slot name=“right”></slot>
</div>

</template>

现在问题来了,ItemBoard 作为一个通用组件,它真的知道应该给 Item 的 right slot 传什么 UI 成分吗?
它其实是不知道的,因为具体传什么 UI 成分取决于 ItemBoard 展现的是什么数据。如果展现的是1号区块,那么应该根据列表数据的保单数展示文字;如果展现的是2号区块,那么应该全部展示右箭头(>)。。。

此时,似乎不得不把具体展现什么UI的逻辑写在 ItemBoard 中了,通过传入的数据告诉 ItemBoard 具体展现的是几号区块,然后 ItemBoard 决定展现什么 UI 给 Item。但是,这样一来,ItemBoard 的展现就和它的数据紧密耦合了,要是以后列表项的右侧部分又多了一种 UI,那么不得不修改 ItemBoard 的代码以满足新增的需求。

我对 React 也有接触。在 React 中,这种情况很好解决,JSX语法使得将看起来像组件声明式的组件实例作为数据放在 JS 对象中。如
{
title: ‘’,
desc: ‘’,
rightComponent: <Delete />
}
这样的话,ItemBoard 只需要取传入数据的 rightComponent 属性便可以了。将具体展现什么的任务交给了注入的数据,具有很大的灵活性。

所以,我的问题就是, Vue 对于这种情况应该如何处理?

阅读 5.1k
7 个回答

关键字 slot

感觉你的抽象上,实际上你的ItemBoard应该是继承于item组件,对应于vue的话,应该是用mixin来操作。

新手上路,请多包涵

个人看法:
分别做成三个组件, 最外层-list层-右侧icon(数据层)
最外层负责上下标题, 整个面板的padding,margin等布局
中间层负责传递数据,同时负责左边的图标, 图标主题, 图标说明
右侧icon(数据)做成一个组件,展示icon传icon,展示数据的话, 从中间层继承

两层slot不用关心数据传递以及事件广播问题

list.vue:

<div>
    <p>{{title}}</p>
    <list-item :item="item" v-for="item in arr">
        <div slot="iconDelete" v-if="item.operationType==='delete'" class="iconDelete"></div>
        <div slot="iconEdit" v-if="item.operationType==='edit'" class="iconEdit"></div>//还可以再拓展操作类型
    </list-item>
<div>

item.vue:
flex 布局

<div style="flex">
    <div class="headImg">
        <img :src="item.headImg">
    </div>
    <div class="personInfo flex-box-1">
        <div class="relation">{{item.relation}}</div>
        <div class="name">{{item.name}}</div>
    </div>
    <div class="count" v-if="item.count!==undefined">
       <div class="bold" v-if="item.count>0">{{item.count}}张保单</div>
       <div class="grey" v-else>还没有保单</div>
    </div>
    <slot name="iconDelete"></slot>
    <slot name="iconEdit"></slot>//还可以再拓展操作类型
</div>

reac使用props或者children,vue使用slot,能达到的效果应该差不多。
就算是react,rightComponent: <Delete />,这里ItemBoard是一个通用组件吗,不是吧。
ItemBoard真的需要做成非常通用吗,就算ItemBoard是通用组件,可以有ItemBoard1,ItemBoard2,里面包含ItemBoard和slot不是可以吗。

如果对于变动性不确定的可以使用自定义DOM内容,在组建里面使用v-html="xxxx"进行绑定即可,不需要做过多的判断,而且灵活性完全取决于自定义。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题