vue3封装移动端table组件

table组件示例

table组件大概长这样,总计行不需要可以删除

CustomTable.vue 子组件

<template>
  <div class="report_table">
    <!-- 表头 -->
    <div class="table_columns">
      <div
        class="cell"
        v-for="item in props.columns"
        :key="item.prop"
        :style="{ width: item.width }"
      >
        {{ item.lable }}
      </div>
    </div>
    <!-- 汇总 -->
    <div class="summary">
      <slot name="summary"></slot>
    </div>

    <!-- 内容区域 -->
    <div
      class="table_source"
      @scroll="
        () => {
          if (props.tableType === 1) {
            handleScroll();
          }
        }
      "
      ref="tableRef"
      v-if="props.dataSource.length"
    >
    <!-- 下拉刷新  -->
      <van-pull-refresh
        v-model="props.refreshLoading"
        @refresh="emits('onRefresh')"
      >
        <div class="row" v-for="record in props.dataSource" :key="record.id">
          <div
            class="cell"
            v-for="items in columns"
            :key="items"
            :style="{ width: items.width }"
          >
            <div class="cell_item" v-if="items.moneyType">
              ¥{{ record[items.prop] }}
            </div>
            <div class="cell_item" v-else>{{ record[items.prop] }}</div>
          </div>
        </div>
      </van-pull-refresh>
    </div>
    <!-- 暂无内容区域 -->
    <div class="no_data" v-else>
      <span class="data_text">暂无内容</span>
    </div>
  </div>
</template>


<script setup>
import { ref } from "vue";

const props = defineProps({
  // 当前加载的table类型,  1.  滚动动态请求数据  2. 滚动不请求数据
  tableType: {
    type: Number,
    default: null,
  },
  // 列表数据
  dataSource: {
    type: Array,
    default: () => [],
  },
  // 列表字段
  columns: {
    type: Array,
    default: () => [],  // width 参数建议设置 百分比,设置百分比可自适应
  },
  refreshLoading: {
    type: Boolean,
    default: false,
  },
  total: {
    type: Number,
    default: 0,
  },
});

const emits = defineEmits(["onRefresh", "onTableScroll"]);

const tableRef = ref(null);

// 上拉刷新
const handleScroll = () => {
  // 变量scrollTop是滚动条滚动时,距离顶部的距离
  const scrollTop = tableRef.value.scrollTop;
  // 变量scrollHeight是滚动条的总高度
  const scrollHeight =
    tableRef.value.scrollHeight;
  // 变量clientHeight是滚动条可视区域的高度
  const clientHeight =
    tableRef.value.clientHeight;

  // 当滚动条到达底部,并且距离底部小于10px时,加载数据
  if (scrollTop + clientHeight >= scrollHeight) {
    if (props.total > props.dataSource.length) {
      emits('onTableScroll')
    }
  }
};
</script>

<style lang="scss" scoped>
.report_table {
  width: 100%;
  height: 0;
  flex: 1;
  background: #fff;
  .table_columns {
    width: 100%;
    height: 50px;
    font-weight: 400;
    font-size: 15px;
    color: #989898;
    display: flex;

    .cell {
      height: 100%;
      line-height: 50px;
      text-align: center;
    }
  }

  .summary {
    width: 100%;
    height: 50px;
    border-top: 1px solid #efefef;
    box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.13);

    display: flex;
    color: #2c2c2c;
    font-size: 15px;
  }

  .table_source {
    height: calc(100% - 100px);
    overflow: auto;
    .row {
      display: flex;
      padding: 15px 0;
      border-bottom: 1px solid #efefef;

      .cell {
        font-weight: 400;
        font-size: 15px;
        color: #2c2c2c;
        text-align: center;

        .cell_item {
          width: 100%;
          word-break: break-all;
        }
      }
    }
  }

  .no_data {
    width: 100%;
    height: calc(100% - 100px);
    background: #F6F6F6;
    text-align: center;

    .data_text {
      display: inline-block;
      margin-top: 50px;
    }
  }
}
</style>

index.vue 父组件

<template>
  <div class="booking">
    <!-- 导航栏 -->
    <van-sticky>
      <NavBar :title="title" @on-back="handleBack"></NavBar>
    </van-sticky>
    <div class="report_table_container">
      <!-- 检索组件 -->
      <Search :searchList="searchList" @on-search="handleSearch"/>
      <!-- table组件 -->
      <Table :total="page.total" :columns="columns" :dataSource="dataSource" :tableType="tableType" @onRefresh="handleRefresh" :refreshLoading="refreshLoading" @onTableScroll="handleTableScroll">
        <!--插槽部分-->
        <template #summary>
          <div class="report_table_summary" style="width: 12%">总计</div>
          <div class="report_table_summary" style="width: 44%">0台</div>
          <div class="report_table_summary" style="width: 22%">¥0</div>
          <div class="report_table_summary" style="width: 22%">¥0</div>
        </template>
      </ReportTable>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";

import Search  from "./components/Search.vue";
import Table from "./components/Table.vue";

// 
const tableType = ref(1);
const router = useRouter();
const searchList = ref([
  {
    placeholder: "请输入姓名",
    value: "username",
  },
  {
    placeholder: "别名",
    value: "nickname",
  },
]);
// 列表下拉loading
const refreshLoading = ref(false);
// 表头 
const columns = ref([
    {
        lable: "编号",
        prop: "id",
        width: '12%',
    },
    {
        lable: "姓名",
        prop: "username",
        width: '22%',
    },
    {
        lable: "别名",
        prop: "nickname",
        width: '22%',
    },
    {
        lable: "金额",
        prop: "money",
        width: '22%',
        moneyType: true
    },
    {
        lable: "余额",
        prop: "balance",
        width: '22%',
        moneyType: true
    },
]);
// table内容
const dataSource = ref([])
// 分页参数
const page = ref({
  pageNum: 1,
  pageRow: 20,
  total: 0,
});

onMounted(() => {
  // 获取明细数据
  getList()
})


// 检索
const handleSearch = (formData) => {
  getList(formData)
}

// 滚动加载
const handleTableScroll = () => {
   page.value.pageNum++;
   getList()
}

// 获取table列表
const getList = (searchParams) => {
   const params = {
      ...page.value,   // 分页数据
     ...searchParams  // search组件参数
   }

    .............
}

// 下拉刷新
const handleRefresh = () => {
  page.value.pageNum = 1
  refreshLoading.value = true
  // 请求数据  ......
  getList()
}

const handleBack = () => {
  router.go(-1);
};
</script>t pa


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容