1.效果图

 2.样式代码

注:部分组件使用的naive-Ui

<template>
  <div id="gridBox">
    <div class='left' ref="scrollRef">
      <div class="left_box" ref="scrollRef" id="scrollRef">
        <div class="table_box" v-for="(item,index) in list" :key="index" :id="item.anchor">  

//每个节点需要有一个对应的不同的id
          <n-card :title="item.title">
            <xx-table :xxData="item.data"></xx-table>
          </n-card>
        </div>
      </div>
    </div>
    <div class="right">
      <div class="nav_box">
        <div class="nav_item" :class="scrollIndex===index ? 'nav_select' : ''" v-for="(item,index) in list" :key="index"
             @click="toAnchor(item,index)">{{ item.title }}
        </div>
      </div>
      <div class="button_box">
        <div v-for="(item,index) in btnList" :key="index">
          <n-button class="btn" :type="item.type" @click="item.onClick">{{ item.text }}</n-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import {nextTick, onMounted, ref, onBeforeUnmount} from "vue";
import {NButton, NCard} from 'naive-ui'

export default {
  name: "grid",
  components: {
    NButton, NCard
  },
  props: {
    listData: {
      type: Array
    },
    operation: {
      type: Array
    }
  },
//listData是父组件传递过来的数据。格式大概:
 //let list = ref([
      //{
      //  title: "表格11111", //表格名字
      //  anchor: 'span1',   //每个唯一的id锚点标识
      //  data: xxTableData  //表格数据
     // }]
  setup(props) {
    console.log(props)
    let scrollRef = ref(null);
    let scrollList = ref([])   //每个盒子的滚动距离列表
    let scrollIndex = ref(0)  //导航选中样式绑定索引
    let btnList = ref([])     //操作按钮列表

    function handleScroll(e) {     //滚动事件
      scrollList.value.forEach((item, index) => {
        if (e.target.scrollTop >= item.scrollTopNum) {
          scrollIndex.value = index
        }
      })
    }

    function toAnchor(item, index) {    //单击单个导航执行事件
      nextTick(() => {
        scrollIndex.value = index;
        scrollRef.value.scrollTop = document.getElementById(item.anchor).offsetTop + 2;
      })
      scrollIndex.value = index
    }

    onMounted(() => {
      btnList.value = props.operation;
      props.listData.forEach((item) => {
        scrollList.value.push({scrollTopNum: document.getElementById(item.anchor).offsetTop})
      })
      window.addEventListener('scroll', handleScroll, true)
    })
    onBeforeUnmount(() => {
      window.removeEventListener('scroll');
    })
    return {scrollRef, toAnchor, list: ref(props.listData), scrollIndex,btnList}
  }
}
</script>

<style scoped lang=scss>
#gridBox {
  position: relative;
  height: 100%;
}

.right {
  /* 绝对定位才能脱离文档,相对定位不行 */
  position: absolute;
  right: 0;
  top: 0;
  width: 17vw;
  //background-color: pink;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.left {
  padding-right: 17vw;
  box-sizing: border-box;
  /* 这里不设置宽度也可以 */
  /* width: auto; */
  width: 100%;
  min-height: 88vh;
  max-height: 88vh;
  //background-color: skyblue;
  overflow-y: scroll;
}

.left::-webkit-scrollbar {
  width: 0;
}

.table_box {
  padding: 20px;
  box-sizing: border-box;

  .title {
    font-size: 30px;
    font-weight: bold;
  }
}

.left_box {
  height: 100%;
  overflow-y: auto;
}

.nav_item {
  padding-left: 20px;
  box-sizing: border-box;
  height: 150px;
  border: 1px solid #fff;
  background-color: #ececec;
  //color: #fff;
  line-height: 150px;
  cursor: pointer;
}

.nav_select {
  padding-left: 20px;
  box-sizing: border-box;
  height: 150px;
  border: 1px solid #cdcdcd;
  background-color: #fff;
  font-weight: bold;
  //color: #9a6e3a;
  line-height: 150px;
  cursor: pointer;
}

.button_box {
  display: flex;
  flex-direction: column;

  .btn {
    min-width: 100%;
    margin-top: 10px;
  }

  button {
    //border: 0;
    //background-color: #2b85e4;
    //color: #fff;
    padding: 20px 0;
    box-sizing: border-box;
  }
}

Logo

前往低代码交流专区

更多推荐