技术栈: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