一个 适用 vue3 ts h5移动端 table组件

14,775次阅读
没有评论

共计 6818 个字符,预计需要花费 18 分钟才能阅读完成。

vue3-h5-table

介绍

适用于 vue3 + ts 的 h5 移动端项目 table 组件

支持 左侧固定 滑动 每行点击回调 支持 指定列排序

链接:https://github.com/duKD/vue3-h5-table

效果

一个 适用 vue3 ts 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

  1. 修改 transform 渲染方式 不经过 vue 派发更新(数据量过大 会有卡顿),直接用原生 js 去控制
    具体表现如下图(1000 条列表数据)
    一个 适用 vue3 ts h5 移动端 table 组件
    在左右滑动 1s 内 有 300 多 ms 消耗到 vue3 的派发更新上,但是我们人为是知道只有组件样式需要改变,所以可以考虑优化,将更新的操作用原声 js 实现,不走 vue 响应更新

一个 适用 vue3 ts h5 移动端 table 组件

vue 派发更新时间就省略了,响应速度提高了 200 多 ms。就基本不会卡顿了

  1. 增加 rootValue 配置 默认 75(基于 rootValue 去将 props 中的 一些 长度单位 传化成 rem)修复 pad 样式问题(保持和 postCssPxToRem 插件配置一致)
    postCssPxToRem({
    // 自适应,px>rem 转换
    rootValue: 75, // 75 表示 750 设计稿,37.5 表示 375 设计稿
    propList: [“*”], // 需要转换的属性,这里选择全部都进行转换
    selectorBlackList: [“norem”], // 过滤掉 norem- 开头的 class,不进行 rem 转换
    }),
  2. 优化一些参数命名
  3. 将点击 显示操作栏目的操作 更多内置化,便于使用

2023.10.7

处理了 屏幕尺寸变化(一般生产环境 用户屏幕尺寸不会发生变化)引发一些问题

2023.10.10

表头 固定优化 处理 ios fixed 滑动问题

2023.10.20

cell 组件 改为函数组件 加快渲染速度

2023.10.31

解决 cloumn 修改宽带导致表格宽度改变引发的空白问题

2024.1.8

修复滚动过快 无法触发 load 事件问题

原文地址: 一个 适用 vue3 ts h5 移动端 table 组件

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-10-06发表,共计6818字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)