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;
}
}