手机端自封装table组件
子组件:commonTable
<template>
<div class="table-box-content">
<div class="table-header" :style="{ width: headerWidth + 'px' }">
<div v-for="(col, index) in columns" :key="index" :style="getColumnStyle(col)">
<slot v-if="$scopedSlots[col.titleSlot]" :name="col.titleSlot"></slot>
<span v-else>{{ col.name }}</span>
</div>
</div>
<div class="list-container" :style="{ width: headerWidth + 'px' }">
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" :class="{ nodatawrap: tableData.length == 0 && finished }" >
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<div
class="table-body-item"
:class="[typeof rowClassName === 'function' ? rowClassName(item) : rowClassName]"
:style="{ width: headerWidth + 'px' }"
v-for="item in tableData"
:key="item.id"
@click="handleClick(item)"
>
<div v-for="(col, idx) in columns" :key="idx" :style="getColumnStyle(col)">
<slot v-if="$scopedSlots[col.slot]" :name="col.slot" :data="item"></slot>
<span v-else>{{ item[col.key] || '--' }}</span>
</div>
</div>
</van-list>
</van-pull-refresh>
</div>
</div>
</template>
<script>
export default {
name: "commonTable",
props: {
rowClassName: {
type: [String, Function],
default: null
},
columns: {
type: Array,
default: () => [
// {
// key: 'discountNo', name: '折扣配置编码'
// },
// {
// key: 'discountNo123', name: '折扣配置编码123', slot: 'discountNo123', width: 100, titleSlot: 'discountNo123'
// },
]
},
tableData: {
type: Array,
default: () => []
}
},
data() {
return {
headerWidth: 0,
loading: false, // 是否加载中
finished: false,
refreshing: false, // 是否刷新中, false表示加载完成
pageIndex: 1,
pageSize: 20
}
},
methods: {
getColumnStyle(col) {
return {
width: col.width ? `${col.width}px` : 'auto',
minWidth: col.minWidth ? `${col.minWidth}px` : '80px'
}
},
onLoad() {
if (this.refreshing) {
this.pageIndex = 1;
this.finished = false;
}
this.loading = true;
// 抛出事件并附带分页参数
this.$emit('load', {
page: this.pageIndex,
pageSize: this.pageSize,
complete: (hasMore) => {
this.loading = false;
this.finished = !hasMore;
this.refreshing = false;
this.pageIndex++;
},
refresh: () => {
this.loading = false;
this.refreshing = false;
}
});
},
onRefresh() {
this.refreshing = true;
this.onLoad();
},
handleClick(item) {
this.$emit('row-click', item)
},
setWidth() {
const headerCols = document.querySelectorAll('.table-header > div')
let width = 0
headerCols.forEach((col) => {
width += col.offsetWidth
})
this.headerWidth = width
},
},
mounted() {
this.$nextTick(() => {
this.setWidth()
})
},
}
</script>
<style lang="less" scoped>
.table-box-content {
position: relative;
height: 100%;
overflow: auto;
&::-webkit-scrollbar {
display: none; /* 隐藏滚动条 */
}
.table-header {
height: 40px;
border-radius: 8px 8px 0 0;
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: #ffffff;
white-space: nowrap;
background: #3d7cfe;
> div {
display: inline-block;
min-width: 80px;
height: 40px;
line-height: 40px;
padding-left: 10px;
}
}
.list-container {
position: absolute;
top: 40px;
left: 0;
right: 0;
bottom: 0px;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
display: flex;
flex-direction: column;
.table-body-item {
height: 38px;
white-space: nowrap;
&.gray {
background: rgba(80, 87, 102, 0.1);
}
&.grayd {
background: rgba(80, 87, 102, 0.2);
}
&.pink {
background: rgba(255, 245, 231, 1);
}
> div {
display: inline-block;
min-width: 80px;
height: 40px;
line-height: 40px;
font-size: 12px;
color: #333333;
padding-left: 10px;
white-space: nowrap;
overflow: hidden;
overflow-x: auto;
&::-webkit-scrollbar {
display: none; /* 隐藏滚动条 */
}
&:active {
opacity: 0.8;
}
}
}
.van-pull-refresh {
overflow: auto !important;
width: 100%;
}
.nodatawrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
::v-deep .van-pull-refresh__track {
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
</style>
使用方法:
<template>
<div class="listnew-container">
<div class="listnew-content">
<div class="listnew-content-title">箱单详情</div>
<van-search
v-model="keyword"
shape="round"
background="#ffffff"
placeholder="请输入项目号/物料编码"
@search="onSearch"
/>
<div class="table-box">
<commonTable
ref="commonTable"
:columns="columns"
:tableData="list"
:row-class-name="getRowClassName"
@load="handleLoad"
>
<template #boxCode="{ data }">
<span @click="boxCodeClick(data)">{{ data.boxCode || '--' }}</span>
</template>
<template #totalLackAmount="{ data }">
<span>{{ data.totalLackAmount }}元</span>
</template>
</commonTable>
</div>
</div>
</div>
</template>
<script>
import { queryPage } from '@/api/user'
import commonTable from '@/components/commonTable'
export default {
components: { commonTable },
data() {
return {
keyword: '',
list: [], // 列表数据
columns: [
{key: 'projectCode', name: '项目号', width: 120},
{key: 'boxCode', name: '箱号', width: 80, slot: 'boxCode'},
{key:'signStatus', name: '发运状态', slot:'signStatus', width: 100},
{key: 'partCode', name: '图号', width: 80},
{key: 'partName', name: '名称', width: 80},
{key: 'partNo', name: '件码', width: 140},
{key: 'smallBoxCode', name: '小箱码', width: 140},
{key: 'bigBoxCode', name: '大箱码', width: 140},
{key: 'netWeight', name: '净重(kg)', width: 100},
{key: 'grossWeight', name: '毛重(kg)', width: 80},
]
}
},
methods: {
boxCodeClick() {
},
handleLoad({ page, pageSize, complete }) {
this.fetchData(page, pageSize)
.then(res => {
const hasMore = res.rows.length > 0 && page < res.pageTotal;
this.list = page === 1 ? [...res.rows] : [...this.list, ...res.rows];
complete(hasMore);
})
.catch(() => {
complete(false); // 加载失败时停止加载
});
},
getRowClassName(row) {
if (row.packagePlanStatus === '锁产') return 'pink';
if (row.packagePlanStatus === '预排') return 'gray';
return '';
},
onSearch() {
// 清空列表数据
this.list = []
this.$refs.commonTable && this.$refs.commonTable.onRefresh()
},
async fetchData(page, pageSize) {
const params = {
data: {
projectNo: this.$route.query.projectNo
},
page: {
pageIndex: page,
pageSize: pageSize
}
};
const res = await queryPage(params);
if (res && res.data) {
return {
rows: res.data.rows,
pageTotal: res.data.pageTotal
};
}
return { rows: [], pageTotal: 0 };
},
},
mounted() {
this.$nextTick(() => {
this.$refs.commonTable && this.$refs.commonTable.onLoad()
})
},
}
</script>
<style lang="less" scoped>
.listnew-container {
min-height: 100vh;
background-color: #fff;
.listnew-content {
display: flex;
flex-direction: column;
padding-top: 24px;
height: 100vh;
.listnew-content-title {
line-height: 1;
font-family: PingFangSC-Semibold;
font-weight: 500;
font-size: 18px;
color: #111111;
padding-left: 16px;
padding-bottom: 4px;
}
.table-box {
flex: 1;
padding: 0 16px 20px;
overflow: hidden;
}
}
}
.status-wrap {
display: flex;
justify-content: center;
align-items: center;
width: 44px;
height: 22px;
color: #ffffff;
font-size: 12px;
font-weight: 500;
border-radius: 2px;
margin-top: 10px;
&.statusReceived {
opacity: 0.5;
background: #3498ff;
}
&.statusLocked {
background: #f55f4e;
}
&.statusCompleted {
background: #17ccac;
}
&.status-fully-arrived {
background: #3498ff;
}
}
</style>
<template>
<div class="table-box-content">
<div class="table-header" :style="{ width: headerWidth + 'px' }">
<div v-for="(col, index) in columns" :key="index" :style="getColumnStyle(col)">
<slot v-if="$scopedSlots[col.titleSlot]" :name="col.titleSlot"></slot>
<span v-else>{{ col.name }}</span>
</div>
</div>
<div class="list-container" :style="{ width: headerWidth + 'px' }">
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" :class="{ nodatawrap: tableData.length == 0 && finished }" >
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<div
class="table-body-item"
:class="[typeof rowClassName === 'function' ? rowClassName(item) : rowClassName]"
:style="{ width: headerWidth + 'px' }"
v-for="item in tableData"
:key="item.id"
@click="handleClick(item)"
>
<div v-for="(col, idx) in columns" :key="idx" :style="getColumnStyle(col)">
<slot v-if="$scopedSlots[col.slot]" :name="col.slot" :data="item"></slot>
<span v-else>{{ item[col.key] || '--' }}</span>
</div>
</div>
</van-list>
</van-pull-refresh>
</div>
</div>
</template>
<script>
exportdefault {
name:"commonTable",
props: {
rowClassName: {
type: [String, Function],
default:null
},
columns: {
type:Array,
default: () => [
// {
// key: 'discountNo', name: '折扣配置编码'
// },
// {
// key: 'discountNo123', name: '折扣配置编码123', slot: 'discountNo123', width: 100, titleSlot: 'discountNo123'
// },
]
},
tableData: {
type:Array,
default: () => []
}
},
data() {
return {
headerWidth:0,
loading:false, // 是否加载中
finished:false,
refreshing:false, // 是否刷新中, false表示加载完成
pageIndex:1,
pageSize:20
}
},
methods: {
getColumnStyle(col) {
return {
width:col.width ? `${col.width}px` : 'auto',
minWidth:col.minWidth ? `${col.minWidth}px` : '80px'
}
},
onLoad() {
if (this.refreshing) {
this.pageIndex = 1;
this.finished = false;
}
this.loading = true;
// 抛出事件并附带分页参数
this.$emit('load', {
page:this.pageIndex,
pageSize:this.pageSize,
complete: (hasMore) => {
this.loading = false;
this.finished = !hasMore;
this.refreshing = false;
this.pageIndex++;
},
refresh: () => {
this.loading = false;
this.refreshing = false;
}
});
},
onRefresh() {
this.refreshing = true;
this.onLoad();
},
handleClick(item) {
this.$emit('row-click', item)
},
setWidth() {
constheaderCols = document.querySelectorAll('.table-header > div')
letwidth = 0
headerCols.forEach((col) => {
width += col.offsetWidth
})
this.headerWidth = width
},
},
mounted() {
this.$nextTick(() => {
this.setWidth()
})
},
}
</script>
<stylelang="less"scoped>
.table-box-content {
position: relative;
height: 100%;
overflow: auto;
&::-webkit-scrollbar {
display: none; /* 隐藏滚动条 */
}
.table-header {
height: 40px;
border-radius: 8px8px00;
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: #ffffff;
white-space: nowrap;
background: #3d7cfe;
> div {
display: inline-block;
min-width: 80px;
height: 40px;
line-height: 40px;
padding-left: 10px;
}
}
.list-container {
position: absolute;
top: 40px;
left: 0;
right: 0;
bottom: 0px;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
display: flex;
flex-direction: column;
.table-body-item {
height: 38px;
white-space: nowrap;
&.gray {
background: rgba(80, 87, 102, 0.1);
}
&.grayd {
background: rgba(80, 87, 102, 0.2);
}
&.pink {
background: rgba(255, 245, 231, 1);
}
> div {
display: inline-block;
min-width: 80px;
height: 40px;
line-height: 40px;
font-size: 12px;
color: #333333;
padding-left: 10px;
white-space: nowrap;
overflow: hidden;
overflow-x: auto;
&::-webkit-scrollbar {
display: none; /* 隐藏滚动条 */
}
&:active {
opacity: 0.8;
}
}
}
.van-pull-refresh {
overflow: auto!important;
width: 100%;
}
.nodatawrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
::v-deep .van-pull-refresh__track {
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
</style>

浙公网安备 33010602011771号