当前位置:   article > 正文

uniapp中列表(list)组件封装_uniapp list

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
三、组件使用

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

<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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
四、文件目录结构及其效果展示

在这里插入图片描述

五、参考链接地址

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/963703
推荐阅读
相关标签
  

闽ICP备14008679号