vue3+ts+element-plus,实现el-table表格内数据上下滑动的时候,右侧的类别也上下变更

先看效果: 

lp20240428

我在开发过程中,遇到这样一个需求,表格的数据根据类别来定位。当用户在列表上上下滑动的时候,右侧的类别也跟着上下变更;当用户点击右侧的类别的时候,左侧的列表也要迅速定位到该类别的数据上。

实现步骤:

1.处理数据

我这里用for循环模拟了一部分数据,具体数据如下图所示,其中最重要的是groupId,判断这条数据的类别。

接下来就是groupArray右侧显示的类别,通过groupArray循环来设置列表数据里每个group第一个科目的group名称。

2.实现表格滚动导航,右侧的类别跟着上下变更

这里我们就需要用到IntersectionObserver(交叉观察器),observe:开始监听特定元素(需要接收一个target参数,值是Element类型,用来指定被监听的目标元素)。具体如下图所示:

3.实现点击右侧的类别,左侧的列表也要迅速定位到该类别的数据上

添加右侧的类别点击事件

通过HTMLCollectionOf<HTMLElement>获取offsetTop,在表格里使用setScrollTop直接定位到该类别的数据。

 完整代码如下:

<template>
  <div class="voucher">
    <div class="content-box">
      <el-table
        id="accountListTable"
        class="account-list-table"
        ref="dataListTableRef"
        :data="dataList"
        row-key="id"
        border
        style="width: 100%"
        header-cell-class-name="custome-table-header"
        :row-class-name="
          ({ row }) => (row._groupAnchorsId ? row._groupAnchorsId : '')
        "
      >
        <el-table-column prop="name" label="姓名" />
        <el-table-column
          prop="age"
          align="center"
          label="年龄"
          min-width="100"
        />
        <el-table-column
          prop="sex"
          align="center"
          label="性别"
          min-width="100"
        />
        <el-table-column
          prop="work"
          align="center"
          label="工作经历"
          min-width="100"
        />
        <el-table-column
          prop="address"
          align="center"
          label="住址"
          min-width="100"
        />
      </el-table>
    </div>
    <div class="side-bar-index">
      <div class="anchor-box">
        <div class="anchor-content">
          <template v-for="(item, index) of groupArray" :key="item.id">
            <div
              class="anchor-link"
              @click="scrollTableTo(`groupAnchors_${item.value}`)"
            >
              <span>{{
                currentTableScrollId === `groupAnchors_${item.value}`
                  ? item.value
                  : ''
              }}</span>
            </div>
            <div v-if="index + 1 < groupArray.length" class="line"></div>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { ElTable } from 'element-plus'

const currentTableScrollId = ref('groupAnchors_类一')
// 大类别id
let groupArray = ref<any>([
  {
    key: 1,
    value: '类一',
  },
  {
    key: 2,
    value: '类二',
  },
  {
    key: 3,
    value: '类三',
  },
  {
    key: 4,
    value: '类四',
  },
  {
    key: 5,
    value: '类五',
  },
])

const dataListTableRef = ref<InstanceType<typeof ElTable>>()
//
const dataList = ref<any>([])

// 数据
function getList() {
  for (let i = 0; i < 100; i++) {
    dataList.value.push({
      id: `${i + 1}`,
      name: `姓名${i + 1}`,
      age: `${i + 1}`,
      sex: `${i % 2 == 0 ? '女' : '男'}`,
      work: `工作${i + 1}`,
      address: `住址${i + 1}`,
      groupId: `${
        i < 20
          ? '1'
          : i >= 20 && i < 40
          ? '2'
          : i >= 40 && i < 60
          ? '3'
          : i >= 60 && i < 80
          ? '4'
          : '5'
      }`,
    })
  }

  groupArray.value.forEach((item: { key: number; value: string }) => {
    const findIndex = dataList.value.findIndex(
      (_: any) => +_.groupId === item.key
    )
    if (findIndex !== -1) {
      // 设置每个group第一个科目的group名称
      dataList.value[findIndex]._groupAnchorsId = `groupAnchors_${item.value}`
    }
  })

  // 新建交叉监视器用于滚动导航
  const io = new IntersectionObserver(
    (entries) => {
      // 如果达到显示比例

      if (entries[0].isIntersecting) {
        // 获取节点 class
        const targetClass = entries[0].target.getAttribute('class')

        // 获取 name
        const targetId = targetClass
          ? targetClass
              .split(' ')
              .find((item) => item.includes('groupAnchors_'))
          : ''

        // 赋值设置右侧导航
        currentTableScrollId.value = targetId || currentTableScrollId.value
      }
    },
    // 显示比例为 0.5 时 isIntersecting 为 true
    { threshold: 0.5 }
  )

  nextTick(() => {
    groupArray.value.forEach((item: { value: any }) => {
      const target = document.getElementsByClassName(
        `groupAnchors_${item.value}`
      )[0]

      if (target) {
        io.observe(target)
      }
    })
  })
}

// 表格锚点定位
const scrollTableTo = (id: string) => {
  const element = document.getElementsByClassName(
    id
  ) as HTMLCollectionOf<HTMLElement>

  if (dataList.value && dataList.value.length > 0 && element) {
    dataListTableRef.value!.setScrollTop(element[0].offsetTop)

    nextTick(() => {
      currentTableScrollId.value = id
    })
  }
}

onMounted(() => {
  getList()
})
</script>

<style lang="scss" scoped>
.voucher {
  display: flex;
  align-items: flex-start;
  width: 100%;
  height: 100%;
  padding: 16px;
  overflow: auto;

  .content-box {
    display: flex;
    flex-direction: column;
    width: calc(100% - 38px - 16px);
    height: 100%;
    padding: 16px;
    background: #fff;
    border-radius: 4px;
  }

  .account-list-table {
    width: 100%;
    height: calc(100vh - 200px);
  }

  .side-bar-index {
    display: flex;
    flex-direction: column;
    margin-left: 16px;

    .anchor-box {
      padding: 16px 0;
      margin-bottom: 16px;
      background-color: #fff;
      border-radius: 4px;
    }

    .anchor-content {
      display: flex;
      flex-direction: column;
      align-items: center;

      .anchor-link {
        display: flex;
        align-items: center;
        justify-content: center;
        min-width: 10px;
        min-height: 10px;
        cursor: pointer;
        border: 1px solid red;
        border-radius: 50%;
      }

      span {
        padding: 2px;
        font-family: PingFangSC, 'PingFang SC';
        font-size: 12px;
        font-weight: 400;
        line-height: 24px;
        color: red;
      }

      .line {
        width: 1px;
        height: 16px;
        background-color: red;
      }
    }
  }
}
</style>

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先你需要在项目中安装 `element-plus`,可以通过以下命令进行安装: ``` npm install element-plus --save ``` 然后在你的 Vue 项目中引入 `element-plus` 的 `Table` 组件,以及需要使用的相关样式: ```js import { defineComponent } from 'vue'; import { ElTable, ElTableColumn } from 'element-plus'; import 'element-plus/lib/theme-chalk/index.css'; export default defineComponent({ components: { ElTable, ElTableColumn }, data() { return { tableData: [], // 后台获取的数据 }; }, mounted() { // 在这里调用后台接口获取数据,并将返回的数据赋值给 tableData }, render() { return ( <div> <el-table data={this.tableData}> <el-table-column prop="name" label="名称"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> ); }, }); ``` 在上面的代码中,我们使用了 `ElTable` 和 `ElTableColumn` 组件来渲染表格,其中 `data` 属性绑定了从后台获取的数据 `tableData`,每个 `el-table-column` 标签的 `prop` 属性绑定了对应数据对象的属性名,`label` 属性则是表格列的标题。 当然,你还需要在项目中引入 `element-plus` 的样式,这里我们直接引入了整个 `index.css` 文件来覆盖默认样式。如果你只需要使用部分组件,可以按需引入对应的样式文件。 以上就是使用 `element-plus` 的 `Table` 组件渲染后台数据的基本方法,你可以根据具体需求进行进一步的定制和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值