vue 可视化滚动表格组件

131 阅读3分钟

实现的功能简介

自定义的table表格实现无限滚动

上代码(子组件定义)

<template>
  <div
    class="container"
    :id="id"
  >
    <!-- 容器 -->

    <div>
      <!-- 表头 -->
      <div class="header">
        <div
          :style="{ width: IndexWidth }"
          v-if="config.isRequiredIndex"
        >
          #
        </div>
        <div
          class="header_item"
          v-for="(item, index) in headerList"
          :key="item"
          :style="{ width: otherWidth + 'px', height: '40px' }"
        >
          {{ item }}
        </div>
      </div>
      <div class="inner">
        <!-- base-scroll-list-text -->
        <!-- <div class="row_area"> -->
        <div
          v-for="(item, index) in currentInnerList"
          :key="item.rowIndex"
          class="inner_container base-scroll-list-text"
          :style="{
            height: rowHeights[index] + 'px',
            lineHeight: rowHeights[index] + 'px',
            backgroundColor: item.rowIndex % 2 === 0 ? oddBc[0] : oddBc[1]
          }"
        >
          <div
            class="inner_column"
            v-for="(item2, index2) in item.data"
            :key="index2"
            :style="{
              width: otherWidth + 'px',
              color: index2 === 0 ? config.columuCorlo : ''
            }"
          >
            {{ item2 }}
          </div>
        </div>
        <!-- </div> -->
      </div>
    </div>
  </div>
</template>

<script>
//import dom from './index'
import { v4 as uuidv4 } from 'uuid'
import cloneDeep from 'lodash/cloneDeep'

export default {
  name: 'MyTable',
  components: {},
  props: {
    config: {
      type: Object,
      default: () => ({
        headerList: [],
        isRequiredIndex: false,
        row: [],
        columuCorlo: '',
        openOddSty: false
      })

      // headerList: []
    }
  },
  data() {
    return {
      headerList: [],
      innerList: [],
      // 容器的宽高
      style: {
        width: '',
        height: ''
      },
      // id: uuidv4(),
      id: '',
      //序号列的宽度
      IndexWidth: '80px',
      otherWidth: 0,
      row: [],
      //  columnHeight: 0,
      //假设一页10条
      pagesize: 5,
      //当前界面实际要展示的数量(滚动动画)
      currentInnerList: [],
      //指针
      currentIndex: 0,
      //步进器指数
      moveNum: 1,
      // 所有行高的数组
      rowHeights: 0
      //  newRowList:[]
    }
  },
  created() {
    this.id = `base-scroll-list-${uuidv4()}`
  },
  mounted() {
    console.log('mytable')
    this.getStyle()
    const { config } = this
    this.headerList = config.headerList
    this.row = config.row.map((v, index) => ({
      data: v,
      rowIndex: index
    }))
    // 其它列的宽度
    const _IndexWidth = +this.IndexWidth.replace('px', '')
    this.otherWidth =
      (this.style.width - (this.config.isRequiredIndex ? _IndexWidth : 0)) /
      this.headerList.length
    this.animationStart()
  },
  computed: {
    // 行高
    columnHeight() {
      const result = (this.style.height - 40) / this.pagesize
      return result
    },
    // 奇偶列样式
    oddBc() {
      if (this.config.openOddSty) {
        return ['blue', 'orange']
      } else {
        // 相当于没设置
        return ['white', 'white']
      }
    }
  },
  methods: {
    getStyle() {
      const dom = window.document.getElementById(this.id)
      this.style.width = dom.clientWidth
      this.style.height = dom.clientHeight
    },
    // 动画开始
    async animationStart() {
      //  { currentIndex, moveNum } = this
      // 指针
      //  currentIndex = 0
      // 每次向下移动几个
      //   moveNum = 1
      //当前实际传了几个数据过来
      let totalLength = this.row.length
      if (totalLength < this.pagesize) {
        return
      }
      // 克隆一份row数据
      const _row = cloneDeep(this.row)
      // 实际要显示的数据
      const rows = _row.slice(this.currentIndex)
      rows.push(..._row.slice(0, this.currentIndex))
      //  console.log(this.currentIndex, 'currentIndex')
      this.currentInnerList = rows
      //  debugger
      // 把所有的高度以数组的形式展示
      this.rowHeights = new Array(totalLength).fill(this.columnHeight)
      //[72, 72, 72, 72, 72, 72, 72, 72, 72, 72, __ob__: Observer]
      // console.log(this.rowHeights, ' this.rowHeights')
      const waitTime = 300
      await new Promise((res) => setTimeout(res, waitTime))
      this.rowHeights.splice(
        0,
        this.moveNum,
        ...new Array(this.moveNum).fill(0)
      )
      //  console.log(this.rowHeights, ' this.rowHeights')
      this.currentIndex += this.moveNum
      // 是否到达最后一组数据
      const isLast = this.currentIndex - totalLength
      if (isLast >= 0) {
        this.currentIndex = isLast
      }
      await new Promise((resolve) => setTimeout(resolve, 2000 - waitTime))
      await this.animationStart()
    }
  }
}
</script>

<style lang="scss">
.container {
  // width: 800px;
  position: relative;
  height: 100%;
  width: 100%;
  overflow: hidden;
  .header {
    background-color: #ccc;
    display: flex;
    align-items: center;
    .header_item {
      height: 40px;
      line-height: 40px;
      font-size: 15px;
      color: white;
    }
  }
  .inner {
    height: 360px;
    overflow: hidden;

    .base-scroll-list-text {
      //    padding: 0 10px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      box-sizing: border-box;
    }
    .inner_container {
      display: flex;
      color: white;
      transition: all 0.3s linear;
      //  text-align: center;
    }

    // height: 320px;
    // background-color: #ccc;
  }
}
</style>

如何让列表滚动起来?

每隔一定时间删除数组最前面一个值,然后把这个值再push到数组的最后面去,接着定义一个数组,这个数组的值是所有高度区间组成的数组,接着每次让这个数组的第一项的值变成0就可以了,加上transtion,就会让我们肉眼看见那种卷去头部第一项的效果,后面的逻辑就比较简单了

一些小细节

const arr = [72, 72, 72, 72, 72, 72, 72, 72, 72, 72]
arr.splice(0, 1, ...new Array(1).fill(0))
//  [0, 72, 72, 72, 72, 72, 72, 72, 72, 72]
console.log(arr)

父组件使用

<template>
  <div
    class="container"
    style="width: 500px; height: 400px"
  >
    <my-table v-bind:config="config"></my-table>
  </div>
</template>

<script>
export default {
  components: {},
  data() {
    return {
      headerList: [],
      innerList: [],
      config: {
        headerList: [],
        isRequiredIndex: false,
        row: [],
        columuCorlo: 'red',
        //是否开始奇偶列样式
        openOddSty: true
      }
    }
  },
  created() {
    this.config.headerList = ['姓名', '年龄', '收入']
    const data = []
    for (let index = 0; index < 10; index++) {
      data.push([
        '同学' + (index + 1),
        Math.floor(Math.random() * 10 + 20),
        Math.floor(Math.random() * 10000 + 20000)
      ])
    }
    this.config.row = data
  },
  mounted() {
    //this.headerList.push({})
  },
  methods: {}
}
</script>

<style scoped>
.container {
  width: 500px;

  height: 400px;
}
</style>