共计 6818 个字符,预计需要花费 18 分钟才能阅读完成。
vue3-h5-table
介绍
适用于 vue3 + ts 的 h5 移动端项目 table 组件
支持 左侧固定 滑动 每行点击回调 支持 指定列排序
链接:https://github.com/duKD/vue3-h5-table
效果
props | 说明 |
---|---|
minTableHeight | 表格最小高度 可选 默认 600 |
rowNum | 表格显示几行 可选 默认 6 |
headerHeight | 头部默认高度 可选 默认 60 |
rowHeight | 每行数据的默认高度 默认 100 |
column | 每列数据说明 见下文 |
tableDatas | 表格数据 |
fixedHeader | 是否固定表头 默认 true |
export type columnItemType = {
title:string
dataIndex?:string
width?:number
slotKey?:string
sortable?:boolean
align?: 'left'|'center'|'right'
key?:string
render?:(h:renderType,row:any)=>void
}
type propsType = {
minTableHeight?: number;
rowNum?: number;
headerHeight?: number;
rowHeight?: number;
column: ArraycolumnItemType>;
tableDatas: Arrayany>;
isClick?: boolean;
disable?: boolean;
error?: boolean;
loading?: boolean;
finish?: boolean;
loadingText?: string;
errorText?: string;
finishedText?: string;
offset?: number;
rootValue?: number;
};
使用 实例:
template>
div class="position">
section style="height: 200px">section>
h5-table
ref="h5TableRef"
:column="column"
:table-datas="tableDatas"
@row-click="rowClick"
@handle-head-sort-click="handleHeadSortClick"
v-model:error="error"
:is-click="true"
v-model:loading="loading"
:finish="finish"
@load="onload"
>
template #titleSlot>
section class="nameAndMarkValueTitle">
div>
span class="name_1"> 班费 span>/span class="name_2">
总和
span>
div>
section>
template>
template #title="item">
section class="nameAndMarkValue">
div class="name">
{{item.select}}
span class="type">{{item.type === 1 ? "深" : "沪"}}span>
div>
div class="markValue">{{item.markValue}}=={{item.id}}div>
section>
template>
template #positionAndUse="item">
section class="positionAndUse">
div class="position">
{{item.position}}
div>
div class="use">{{item.use}}div>
section>
template>
template #curAndCost="item">
section class="curAndCost">
div class="cur">
{{item.cur}}
div>
div class="cost">{{item.cost}}div>
section>
template>
template #floatAndProfit="item">
section class="floatAndProfit">
div class="float">{{item.float}}div>
div class="profit">{{item.profit}}div>
section>
template>
template #rowDownMark>
section class="rowDownMark">
div class="rowDownMark-item" @click="handelSell">买入div>
div class="rowDownMark-item">卖出div>
div class="rowDownMark-item">行情div>
section>
template>
h5-table>
div>
template>
script setup lang="ts">
import { H5Table } from "../lib/h5-table";
import type { columnItemType, sortStatusType } from "../lib/h5-table/types";
import { ref, watch } from "vue";
const column: ArraycolumnItemType> = [
{
title: "班费 / 总值",
key: "id",
dataIndex: "nameAndMarkValue",
width: 250,
slotKey: "title",
slotTitleKey: "titleSlot",
align: "left",
},
{
title: "持仓 / 可用",
slotKey: "positionAndUse",
dataIndex: "positionAndUse",
sortable: true,
width: 200,
align: "right",
},
{
title: "现价 / 成本",
slotKey: "curAndCost",
dataIndex: "curAndCost",
width: 200,
align: "right",
},
{
title: "浮动 / 盈亏",
width: 200,
slotKey: "floatAndProfit",
align: "right",
},
{
title: "账户资产",
dataIndex: "count",
width: 200,
},
];
const datas = [
{
id: 0,
select: "三年二班",
type: 1,
position: "27000",
use: "5,000",
markValue: "500,033.341",
cur: "30.004",
cost: "32.453",
newPrice: 20,
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 1,
select: "四年一班",
type: 1,
markValue: "23,933.341",
position: "28000",
use: "5,000",
newPrice: 20,
cur: "30.004",
cost: "32.453",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 2,
select: "三年二班",
markValue: "500,033,341",
newPrice: 20,
cur: "30.004",
cost: "32.453",
position: "27300",
use: "5,000",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 3,
select: "五年二班",
markValue: "500,033,341",
position: "27000",
use: "5,000",
cur: "30.004",
cost: "32.453",
newPrice: 20,
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 4,
select: "一年二班",
markValue: "500,033,341",
position: "27000",
use: "5,000",
newPrice: 20,
cur: "30.004",
cost: "32.453",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 5,
select: "六年三班",
markValue: "500,033,341",
position: "37000",
use: "5,000",
newPrice: 20,
cur: "30.004",
cost: "32.453",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 6,
select: "六年二班",
markValue: "500,033,341",
position: "37000",
use: "5,000",
newPrice: 20,
cur: "30.004",
cost: "32.453",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
{
id: 7,
select: "六年五班",
markValue: "500,033,341",
position: "37000",
use: "5,000",
newPrice: 20,
cur: "30.004",
cost: "32.453",
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
},
];
const temp = Array.from({ length: 300 }).map((item, index) => {
return {
id: index,
select: "三年二班",
type: 1,
position: "27000",
use: "5,000",
markValue: "500,033.341",
cur: "30.004",
cost: "32.453",
newPrice: 20,
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
};
});
const tableDatas = refArrayany>>(JSON.parse(JSON.stringify(temp)));
const h5TableRef = reftypeof H5Table | null>(null);
const loading = refboolean>(false);
const error = refboolean>(false);
const finish = refboolean>(false);
const onload = () => {
console.log("loading====");
setTimeout(() => {
tableDatas.value = tableDatas.value.concat(
Array.from({ length: 100 }).map((item, index) => {
return {
id: new Date().getTime() + index,
select: "三年二班",
type: 1,
position: "27000",
use: "5,000",
markValue: "500,033.341",
cur: "30.004",
cost: "32.453",
newPrice: 20,
float: "+18,879.09",
profit: "-5.45%",
count: "120,121",
};
})
);
loading.value = false;
}, 1000);
};
const rowClick = (item: any, index: number) => {
if (h5TableRef.value) {
h5TableRef.value.handleDom(60, index);
}
};
const handleHeadSortClick = (propsKey: string, type: sortStatusType) => {
if (type === 0) {
tableDatas.value.splice(0, tableDatas.value.length, ...datas);
return;
}
if (propsKey === "positionAndUse") {
if (type === 1) {
tableDatas.value.sort((a, b) => Number(b.position) - Number(a.position));
} else {
tableDatas.value.sort((a, b) => Number(a.position) - Number(b.position));
}
}
};
watch(tableDatas.value, () => {
console.log("watch====", tableDatas);
});
const handelSell = () => {
console.log("handelSell====");
};
script>
style>
body {
padding: 0;
margin: 0 !important;
}
style>
style lang="scss" scoped>
.position {
font-size: 24px;
.nameAndMarkValueTitle {
display: flex;
}
.nameAndMarkValue {
padding: 10px;
.name {
display: inline-block;
position: relative;
color: #222;
font-size: 32px;
.type {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: -40px;
display: inline-block;
font-size: 24px;
border: 1px solid #ff858d;
padding: 0 4px;
color: #ff858d;
}
}
.markValue {
color: #999;
font-size: 24px;
}
}
.positionAndUse {
font-size: 28px;
.position {
color: #222;
}
.use {
color: #999;
}
}
.curAndCost {
font-size: 28px;
.cur {
color: #222;
}
.cost {
color: #999;
}
}
.floatAndProfit {
color: red;
}
.rowDownMark {
width: 100%;
display: flex;
height: 60px;
background-color: #fcfcfc;
align-items: center;
.rowDownMark-item {
flex-grow: 1;
color: #309fea;
text-align: center;
}
}
}
style>
具体使用参考 github 项目中 app.vue 文件
更新日志
2023.9.27
- 修改 transform 渲染方式 不经过 vue 派发更新(数据量过大 会有卡顿),直接用原生 js 去控制
具体表现如下图(1000 条列表数据)
在左右滑动 1s 内 有 300 多 ms 消耗到 vue3 的派发更新上,但是我们人为是知道只有组件样式需要改变,所以可以考虑优化,将更新的操作用原声 js 实现,不走 vue 响应更新
vue 派发更新时间就省略了,响应速度提高了 200 多 ms。就基本不会卡顿了
- 增加 rootValue 配置 默认 75(基于 rootValue 去将 props 中的 一些 长度单位 传化成 rem)修复 pad 样式问题(保持和 postCssPxToRem 插件配置一致)
postCssPxToRem({
// 自适应,px>rem 转换
rootValue: 75, // 75 表示 750 设计稿,37.5 表示 375 设计稿
propList: [“*”], // 需要转换的属性,这里选择全部都进行转换
selectorBlackList: [“norem”], // 过滤掉 norem- 开头的 class,不进行 rem 转换
}), - 优化一些参数命名
- 将点击 显示操作栏目的操作 更多内置化,便于使用
2023.10.7
处理了 屏幕尺寸变化(一般生产环境 用户屏幕尺寸不会发生变化)引发一些问题
2023.10.10
表头 固定优化 处理 ios fixed 滑动问题
2023.10.20
cell 组件 改为函数组件 加快渲染速度
2023.10.31
解决 cloumn 修改宽带导致表格宽度改变引发的空白问题
2024.1.8
修复滚动过快 无法触发 load 事件问题
原文地址: 一个 适用 vue3 ts h5 移动端 table 组件
正文完