本篇文章列表可用于vue项目-大屏数据展示类-滚动表格模块,可配置slot插槽、单元格点击事件。

表格效果图如下:
在这里插入图片描述

一、安装vue-seamless-scroll

安装:

npm install vue-seamless-scroll --save

main.js文件全局引入注册:

// 滚动组件
import vueSeamlessScroll from 'vue-seamless-scroll'
Vue.component('vListScroll', vueSeamlessScroll)

二、公共组件:

创建一个listScroll.vue文件存放在components文件夹下:
在这里插入图片描述

完整代码:

  1. 表头与表格数据分为两个容器,表格数据部分使用vue-seamless-scroll组件,实现表头固定,表格滚动效果;
  2. noData部分暂无数据部分可按照自己项目需求,加入loading等待效果;
<template>
  <div ref="listScroll" class="listScroll">
    <ul class="title-ul">
      <li ref="listTit">
        <span :class="item.class || ''" :key="index" v-for="(item, index) in list.title"
              :style="[item.width ? { width: item.width } : { flex: 1 },
              		  {'text-align': item.align || 'left'}]">
          {{ item.name }}
        </span>
      </li>
    </ul>
    <template v-if="list.data && list.data.length">
      <v-list-scroll class="scroll_box"
                     style="overflow: hidden;"
                     :data="list.data"
                     :class-option="classOption"
                     @click.native="handleClick">
        <ul>
          <li class="row"
              v-for="(item, index) in list.data"
              :key="index"
              :data-ind="index"
              :item="JSON.stringify(item)">
            <span v-for="(it, ind) in list.title" :key="ind" class="col"
                  :style="[it.width ? { width: it.width } : { flex: 1 },
                  		  {'text-align': it.align || 'left'}]">
              <template v-if="it.slot">
                <slot :name="it.slot" :item="JSON.stringify(item)"></slot>
              </template>
              <template v-else>
                {{ item[it.key] }}
              </template>
            </span>
          </li>
        </ul>
      </v-list-scroll>
    </template>
    <template v-else>
      <div class="no_data">{{ option.noData || '暂无数据' }}</div>
    </template>
  </div>
</template>
  1. classOption 的属性可自由替换为可配置属性,如step属性,可取父组件传参:
  2. 因为vue-seamless-scroll组件的滚动效果是通过复制一组list元素实现的,所以直接在list上绑定click事件,会出现点击不起效果的情况,这里的点击事件用了事件委托,向父组件传递了类名和当前行的数据;
<script>
export default {
  props: {
    option: {}
  },
  data () {
    return {
      listLine: 0,
      classOption: {},
      list: {}
    }
  },
  watch: {
    listLine: {
      immediate: true,
      handler (val) {
        this.classOption = {
          step: this.$attrs.step, // 数值越大速度滚动越快,0时静止
          limitMoveNum: this.listLine, // 开始无缝滚动的数据量 this.dataList.length
          hoverStop: true, // 是否开启鼠标悬停stop
          direction: 1, // 0向下 1向上 2向左 3向右
          openWatch: true, // 开启数据实时监控刷新dom
          singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
          singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
          waitTime: 1000 // 单步运动停止的时间(默认值1000ms)
        }
        const obj = { ...this.option }
        const data = this.option.data
        obj.data = [...data, ...data]
        this.list = this.option.data.length % 2 && this.option.data.length >= this.listLine ?
        	obj : this.option
      }
    }
  },
  mounted () {
    const boxHeight = this.$refs.listScroll?.clientHeight || 0 // 容器高度
    const lineHeight = this.$refs.listTit?.clientHeight || 1 // 行高
    this.listLine = Math.floor(boxHeight / lineHeight) - 1 // 计算滚动数据长度
  },
  methods: {
    handleClick (e) {
      const path = e.path || (e.composedPath && e.composedPath())
      let target = path.filter(r => /row/.test(r.className))
      if (target.length) target = target[0]
      else return
      const obj = JSON.parse(target.getAttribute('item')) // 单项数据详情
      const cls = path.map(item => {
        return item.className
      })
      this.$emit('listClick', { cls, obj })
    }
  }
}
</script>
<style lang="scss" scoped>
.listScroll {
  width: 100%;
  height: 100%;
  flex: 1;
  overflow: hidden;
  box-sizing: border-box;
  position: relative;
  display: flex;
  flex-direction: column;

  ul {
    overflow: auto;
    display: flex;
    flex-direction: column;
    padding: 0 15px;
    margin: 0;
    flex-shrink: 0;

    li {
      display: flex;
      box-sizing: border-box;
      height: 32px;
      align-items: center;
      overflow: hidden;
      flex: unset;

      span {
        color: #fff;
        font-size: 0.14px;
        padding: 0 10px;
        flex-shrink: 0;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        overflow: hidden;
      }

      &:nth-child(even) {
        background: rgba(70, 127, 224, 0.2);
      }

      &:nth-child(odd) {
        background: transparent;
      }
    }

    &.title-ul li {
      background: rgba(70, 127, 224, 0.2);
    }
  }

  .no_data {
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    font-size: 0.14px;
  }
}
</style>

三、引入使用:

可以在main.js中全局注册,方法如上面vueSeamlessScroll注册方式一致,不需要每个页面引入;
这里展示的为单个页面注册引入方法;

<template>
  <div class="content">
    <div class="list-box">
      <list-scroll :option="opt" @listClick="listClick">
        <template #sex="{ item }">
          <div>{{item.sex === 0 ? '女' : '男'}}</div>
        </template>
        <template slot="btn">
          <div class="check">查看</div>
        </template>
      </list-scroll>
    </div>
  </div>
</template>

用setTimeout模拟接口获取数据;

<script>
import listScroll from '@/components/listScroll'
export default {
  components: {
    listScroll
  },
  data () {
    return {
      opt: {
        title: [
          { name: '姓名', key: 'name', width: '40px' },
          { name: '性别', slot: 'sex', width: '40px', align: 'center' },
          { name: '家庭地址', key: 'address' },
          { name: '照片', slot: 'btn', width: '40px', align: 'center' }
        ],
        data: []
      }
    }
  },
  mounted () {
    const that = this
    window.setTimeout(function () {
      that.getList()
    }, 2000)
  },
  methods: {
    getList () {
      for (let i = 0; i < 10; i++) {
        this.opt.data.push({
          name: `姓名${i + 1}`,
          sex: i % 2,
          address: `山东省济南市高新区齐鲁软件园-${i + 1}`
        })
      }
    },
    // 点击事件
    listClick ({ cls, obj }) {
      cls.forEach(item => {
        if (item === 'check') {
          console.log(obj)
        }
      })
    }
  }
}
</script>

注意:必须配置容器宽高:

<style lang="scss" scoped>
  .list-box {
    width: 400px;
    height: 300px;
    background: #000;
    margin: 0 auto;
  }
</style>
GitHub 加速计划 / vu / vue
207.53 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 4 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐