自己封装的移动端可横向滚动表格组件,可实现滚动加载

<template>
  <div ref="table">
    <div :style="tableStyle" v-scrollX="this">
      <div>
        <div class="thead">
          <div
            v-for="(item, index) in columns"
            :key="item + index"
            class="thead-item"
          >
            <div
              :style="{
                left: left + 'px',
                background: '#ccc'
              }"
            >
              <div>{{ item.lable }}</div>
            </div>
          </div>
        </div>
      </div>
      <div class="tbody" :style="tbodyStyle" v-if="dataList.length >= 0">
        <div
          v-for="(item, index) in dataList"
          :key="item + index"
          class="tbody-item"
        >
          <div
            v-for="(items, indexs) in columns"
            :key="items + indexs"
            :style="styleObject(items, 1)"
            @click="lineClick(indexs, index)"
          >
            <div
              :style="{
                ...styleObject(items, 2),
                left: left + 'px'
              }"
            >
              <div
                v-if="!items.render"
                style="white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;"
              >
                {{ item[items.key] }}
              </div>
              <!-- <render-template
                v-if="items.render"
                :render="items.render"
                :row="item"
                :index="index"
                :column="items"
              ></render-template> -->
            </div>
          </div>
        </div>
        <div v-if="downLoad" class="downLoad">{{ down_load_text }}</div>
        <!--infinite-loading这个组件要放在列表的底部,滚动的盒子里面-->
        <infinite-loading
          spinner="spiral"
          :on-infinite="infiniteHandler"
          :distance="200"
          class="infinite-loading-wrap"
          ref="infiniteLoading"
        >
          <div
            slot="spinner"
            style="text-align:left;margin-left:12%;margin-bottom:10px"
          >
            加载中...
          </div>
          <div
            slot="no-more"
            style="text-align:left;margin-left:12%;margin-bottom:10px"
          >
            无更多数据!
          </div>
          <div
            slot="no-results"
            style="text-align:left;margin-left:40%;margin-bottom:10px"
          >
            无数据
          </div>
          <div slot="error" slot-scope="{ trigger }">
            Error Data, click
            <a href="javascript:;" @click="trigger">here</a> toretry
          </div>
        </infinite-loading>
        <div
          v-if="dataList.length < 1"
          class="tbody noData"
          :style="noDataStyle"
        >
          <span style="display: block;width:100%;margin-right:25rem"></span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import InfiniteLoading from "vue-infinite-loading";
import { Toast } from "mint-ui";
Vue.component("render-template", {
  name: "renderTemplate",
  functional: true,
  props: {
    render: {
      type: Function
    },
    row: {
      type: Object
    },
    index: {
      type: [String, Number]
    },
    column: {
      type: Object
    }
  },
  render: (h, ctx) => {
    const params = {
      row: ctx.props.row,
      index: ctx.props.index
    };
    if (ctx.props.column) params.column = ctx.props.column;
    return ctx.props.render(h, params);
  }
});
export default {
  data() {
    return {
      left: "0",
      lastScrollTop: "0",
      downLoad: false,
      down_load_text: "加载中...",
      page: 1
    };
  },
  components: {
    InfiniteLoading
  },
  props: {
    selectedValue: {
      type: String,
      default: ""
    },
    findInput: {
      type: String,
      default: ""
    },
    width: {
      //table的宽度
      type: [String, Number],
      default: "100%"
    },
    height: {
      //table的高度
      type: [String, Number],
      default: 490
    },
    border: {
      //是否显示下边框
      type: Boolean,
      default: false
    },
    columns: Array,
    dataList: Array,
    noDataText: {
      type: String,
      default: "暂无数据"
    },
    offset: {
      type: [String, Number],
      default: "0"
    }
  },
  computed: {
    tableStyle() {
      const { width, height, dataList, downLoad } = this;
      let style = {
        overflowX: "scroll",
        overflowY: "hidden",
        position: "relative"
      };
      if (isNaN(Number(width))) {
        style.width = width;
      } else {
        style.width = width + "px";
      }
      if (isNaN(Number(height))) {
        style.height = `calc(${height} + 36px)`;
      } else {
        style.height = Number(height) + 36 + "px";
      }
      if (dataList.length < 1 || downLoad) style.overflowX = "hidden";
      return style;
    },
    tbodyStyle() {
      const { height } = this;
      let style = {};
      if (isNaN(Number(height))) {
        style.height = height;
      } else {
        style.height = height + "px";
      }
      return style;
    },
    noDataStyle() {
      const { height } = this;
      let style = { height: "100px", lineHeight: "100px" };
      if (!isNaN(Number(height))) {
        style.height = height + "px";
        style.lineHeight = height + "px";
      }

      return style;
    }
  },
  created() {},
  mounted() {
    // Toast("Upload Complete");
  },
  methods: {
    resetLoad() {
      this.getDataList(this.page);
    },
    relResetLoad() {
      this.dataList.splice(0); //置空数组
      this.page = 1;
      this.$refs.infiniteLoading.$emit("$InfiniteLoading:reset");
    },
    lineClick(Columnindex, lineIndex) {
      console.log(Columnindex);
      // index = 0 为第一列点击   index = 1 为第二列点击
      if (Columnindex == 0) {
        this.$router.push({
          path: "/aq/orderAdd",

          query: { lineData: this.dataList[lineIndex], operate: "编辑" }
        });
      } else if (Columnindex == 1) {
        //执行删除逻辑  http://192.168.194.24:8082/form/formDefData/removeData/ss_order/0d1afb926fcb06be7dafc80ca1f49c6e
        let url =
          Vue.__ctx +
          "/form/formDefData/removeData/ss_order/" +
          `${this.dataList[lineIndex].id}`;
        var get = Vue.baseService.get(url);
        get.then(data => {
          Toast(data.msg);
          this.dataList.splice(0); //置空数组
          this.page = 1;
          this.getDataList(this.page);
        });
      }
    },
    infiniteHandler() {
      setTimeout(() => {
        this.page++;
        this.getDataList(this.page);
      }, 600);
    },
    async getDataList(page) {
      const list = await this.common.getDataList(
        page,
        5,
        this.selectedValue,
        this.findInput
      );
      if (list.length == 0) {
        this.$refs.infiniteLoading.$emit("$InfiniteLoading:complete");
      } else {
        this.dataList.push(...list);
        this.dataList.forEach(item => {
          item.edit = "修改";
          item.del = "删除";
        });
        this.$refs.infiniteLoading.$emit("$InfiniteLoading:loaded");
      }
    },
    styleObject(item = {}, type = 1) {
      let style = {};
      if (type == 2) {
        style = {
          textAlign: "center"
        };
        if (Boolean(item.align)) style.textAlign = item.align;
        if (Boolean(item.fixed)) {
          style.position = "absolute";
          style.zIndex = "10";
        }
      }
      if (Boolean(item.width) && isNaN(Number(item.width)))
        style.width = item.width;
      if (Boolean(item.width) && !isNaN(Number(item.width)))
        style.width = (type == 1 ? Number(item.width) + 20 : item.width) + "px";
      return style;
    }
  },
  watch: {
    dataList: {
      handler(value) {
        console.log(value);
        this.down_load_text = "加载完成";
        setTimeout(() => {
          this.downLoad = false;
          this.down_load_text = "加载中...";
        }, 2000);
      },
      deep: true
    }
  },
  directives: {
    scrollX: {
      inserted: function(el, binding, vnode) {
        el.addEventListener("scroll", function(e) {
          const that = vnode.context;
          that.left = e.srcElement.scrollLeft;
        });
      }
    }
  }
};
</script>
<style scoped>
.thead {
  display: flex;
  width: auto;
  border: 1px solid black;
  border-bottom: none;
  border-top: none;
}
.thead > div {
  background: white;
  position: relative;
  border-right: 1px solid black;
  border-top: 1px solid black;
  font-weight: 555;
  text-align: center;
}

.thead .thead-item > div {
  width: 110px;
}
.thead .thead-item:nth-child(1) > div {
  width: 60px;
}
.thead .thead-item:nth-child(2) > div {
  width: 60px;
}
.tbody {
  width: fit-content;
  overflow-x: hidden;
  overflow-y: scroll;
  position: relative;
  background: white;
  border-right: none;
}
.tbody .tbody-item {
  display: flex;
  width: max-content;
}
.tbody .tbody-item > div {
  position: relative;
  background: white;
  border-bottom: 1px solid black;
  border-left: 1px solid black;
  padding: 5px;
  height: 30px;
  width: 100px;
}
.tbody .tbody-item > div:nth-child(1) {
  width: 50px;
}
.tbody .tbody-item > div:nth-child(1) > div {
  display: block;
  width: 45px;
  height: 25px;
  background-color: #409eff !important;
  border-radius: 5px;
  color: white;
  font-size: 14px;
}
.tbody .tbody-item > div:nth-child(2) {
  width: 50px;
}
.tbody .tbody-item > div:nth-child(2) > div {
  display: block;
  width: 45px;
  height: 25px;
  background-color: #409eff !important;
  border-radius: 5px;
  color: white;
  font-size: 14px;
}
.tbody .tbody-item > div:last-child {
  border-right: 1px solid black;
}
.noData {
  width: 100%;
  background: white;
  text-align: center;
}
.downLoad {
  width: 100%;
  line-height: 36px;
  background: #f7f8fa;
  text-align: center;
}
</style>

在需要引用的界面 import Table from "@/utils/table.vue";

<Table
      :dataList="dataList"
      :columns="columns"
      ref="table"
    >
    </Table>

dataList为表格数据

columns为表格列例:

 columns: [
        { lable: "修改", key: "edit" },
        { lable: "删除", key: "del" },
        {
          lable: "订货单号",
          key: "order_code"
        },
        {
          lable: "订货重量",
          key: "order_weight"
        },
        {
          lable: "产品类型",
          key: "product_type"
        },
        {
          lable: "存货编码",
          key: "invcode"
        },
        {
          lable: "存货名称",
          key: "invname"
        },
        {
          lable: "规格",
          key: "invspec"
        },
        {
          lable: "型号",
          key: "invtype"
        },
        {
          lable: "订货日期",
          key: "order_date"
        },
        {
          lable: "创建人",
          key: "create_by"
        },
        {
          lable: "创建日期",
          key: "create_date"
        }
      ],