uniapp中列表(list)组件封装

技术栈:uniapp的vue3+vite2+ts版本
前言:在uview中没有列表相关的组件,对于有很多页面都是差不多类似于列表的,为了复用性比较高,所以自己封装了一个列表(list)组件

一、组件分析

列表分为左/中/右三个部分,分别对应标题/内容/操作,通过props将父组件定义的内容传进来,可设置宽度、行与行的间距、颜色、外边距等,通过作用域插槽也可以进行每行的内容自定义

二、组件设计

由于微信小程序不支持插槽默认值,所以通过按环境编译结合v-if实现功能,H5中支持插槽默认值直接使用即可

<template>
    <view class="info">
        <view class="info-item" v-for="(item, index) in listField" :key="index"
            :style="{ '--margin-bottom': marginBottom }">
            <view class="item-title" :style="titleStyle">
                <!-- 左侧标题 -->
                <slot name="type">{{ item.value }}</slot>
            </view>
            <view class="item-content" :style="contentStyle">
                <!-- 中间内容 -->
                <view class="item-text">
                    <!-- #ifdef MP-WEIXIN -->
                    <view class="slot" v-if="item.isObj">
                        <slot :key="String(item.key)" :value="listData[item.key]" name="current"></slot>
                    </view>
                    <view v-else>
                        {{ item.isPrice ? '¥' + listData[item.key] : listData[item.key] }}
                    </view>
                    <!-- #endif -->

                    <!-- #ifdef H5 -->
                    <slot :key="String(item.key)" :value="listData[item.key]" name="current">
                        <view :style="{ 'width': item.width ? item.width : '' }">{{ item.isPrice ? '¥' + listData[item.key] :
                                listData[item.key]
                        }}</view>
                    </slot>
                    <!-- #endif -->
                </view>
            </view>
            <view class="item-action">
                <!-- 右侧标签及操作 -->
                <slot :key="String(item.key)" :value="listData[item.key]" name="action"></slot>
            </view>
        </view>
    </view>
</template>

<script lang='ts' setup>
import { ref, reactive, computed, onMounted } from 'vue'
/**
 * @titleStyle 标题样式
 * @listData 数据列表
 * @contentStyle 标题右侧内容样式
 * @marginBottom item间距
 * @listField 字段名称,用于生成列表结构,必须有key/value
 */
const props = defineProps(
	['listData', 'listField', 'titleStyle', 'contentStyle', "marginBottom"]
)
</script>

<style lang='scss' scoped>
.info {
    margin: 0 auto;

    .info-item {
        display: flex;
        position: relative;

        .item-title {
            text-align: right;
            min-width: 180rpx;
            padding-right: 10rpx;
        }

        .item-content {
            max-width: 450rpx;
            display: flex;
            align-items: flex-end;
        }

        .item-action {
            position: absolute;
            right: 0;
        }
    }

    .info-item:not(:last-child) {
        margin-bottom: var(--margin-bottom);
    }
}

.slot:empty {
    display: none;
}
</style>
三、组件使用

此处使用包含了宽度、颜色、行与行间距、每行自定义等内容,可自行对照进行参照,根据所需进行修改

<template>
    <view class="content-box">
        <list v-for="(item, index) in listData" :key="index" :listField="listField" :titleStyle="titleStyle"
            :marginBottom="marginBottom" :listData="item">
            <template #current="{ key, value }">
                <view v-if="key === 'address'">
                    {{ value.people }}<br>{{ value.detail }}
                </view>
            </template>
            <template #action="{ key, value }">
                <!-- <u-icon name="copy" v-if="key === 'orderNo'" custom-prefix="custom-icon" size="25"></u-icon> -->
                <view v-if="key === 'serviceRrmark'" @click="handleClickAction">联系客服</view>
            </template>
        </list>
    </view>
</template>

<script lang='ts' setup>
import { ref, reactive, computed, onMounted } from 'vue'
import list from '@/components/list/index.vue'

const listData = [{
    id: 'SN3765456783764',
    createTime: '2022-07-10 17:00',
    address: { people: '某先生 13512345678', detail: '浙江省 杭州市 西湖区xxx路xx小区' },
    totalprice: '1099',
    serviceRrmark: '该商品将通过顺丰快递发放,请注意查收'
}]
const listField = [
    { key: 'id', value: '编号' },
    { key: 'createTime', value: '时间' },
    { key: 'address', value: '收货地址', isObj: true },
    { key: 'totalprice', value: '商品总额', isPrice: true },
    { key: 'serviceRrmark', value: '客服备注', width: '400rpx' },
]

const titleStyle = { minWidth: '110rpx', color: 'Green' }
const marginBottom = '20rpx'

const handleClickAction = () => {
    console.log('执行了此处的方法')
}
</script>

<style lang='scss' scoped>
.content-box {
    margin: 30rpx 40rpx;
}
</style>
四、文件目录结构及其效果展示

在这里插入图片描述

五、参考链接地址

1、关于微信小程序不支持slot默认值得讨论:https://developers.weixin.qq.com/community/develop/doc/0008a04f2b0f289fa907b450b56000
2、另一种解决方案,使用:empty伪类来解决,但是我测试后有局限性,不适合我需要的情况,但是也是个思路:https://blog.csdn.net/weixin_45747310/article/details/122305928
3、文章上述内容的demo案例,我放在了gitee上,有需要自行提取,若有用并且方便的话请收藏点赞一下,谢谢:https://gitee.com/zasulan/csdn-item/tree/master/uni-demo-item-vite

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值