使用element-ul实现描点导航
左侧为导航栏,点击内容滚动到指定位置,监听滚动条,左侧锚点导航高亮
效果图如下:
组件封装PointTags:使用el-tabs实现左侧导航
<template> <div class="point-wrap"> <el-tabs tab-position="left" v-model="activeTag" size="middle" @tab-click="tabHandle"> <el-tab-pane :key="item.id" v-for="item in tagsList" :label="item.label" :name="item.id"></el-tab-pane> </el-tabs> </div> </template> <script setup lang="ts"> import { ref, watch } from 'vue'; import type { TabsPaneContext } from 'element-plus'; let activeTag = ref(); const props = defineProps({ tagsList: { type: Array<{ id: String; label: String }>, default: () => [] } }); defineExpose({ setActiveTag: (id:string) => { activeTag.value = id; } }) watch( () => props.tagsList, value => { if (value.length) { activeTag.value = value[0].id; } }, { immediate: true, deep: true } ); const emit = defineEmits(['active-tag']); const tabHandle = (tab: TabsPaneContext) => { console.log(tab); emit('active-tag', tab.paneName as string); }; </script> <style lang="less" scoped> :deep(.el-tabs--left .el-tabs__header.is-left) { width: 100%; } :deep(.el-tabs--left .el-tabs__item.is-left) { justify-content: flex-start; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; } :deep(.el-tabs--left .el-tabs__active-bar.is-left) { left: 0; } :deep(.el-tabs--left .el-tabs__nav-wrap.is-left::after) { left: 0; } :deep(.el-tabs__nav) { width: 100%; } :deep(.el-tabs__item) { padding: 0 16px; } </style>
父级调用
<!-- 左侧导航 --> <div class="left" v-show="!isCollapse"> <PointTags :tagsList="tagsList" @active-tag="activeTagHandle" ref="pointTags" /> </div> <!-- 右侧主体内容 --> <div class="doc-list" ref="docListRef"> <DocCard v-for="item in docList" :id="item.id" :key="item.id" :title="item.title" :content="item.content" :isActive="activeId === item.id" /> </div> <script lang="ts"> import { onMounted, ref } from 'vue'; import PointTags from './components/PointTags.vue'; import DocCard from './components/DocCard.vue'; // 导航栏模块 type Tags = { id: string; label: string; }; let tagsList = ref<Tags[]>([]); const pointTags = ref(); const docListRef = ref(); let timeout: null | number = null; const scrollHandle = (e: any) => { timeout && clearTimeout(timeout); window.setTimeout(() => { let scrollItems: NodeListOf<HTMLDivElement> = document.querySelectorAll('.doc-card'); for (let i = scrollItems.length - 1; i >= 0; i--) { // 判断滚动条滚动距离是否大于当前滚动项可滚动距离 if (e.target) { let judge = e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop - 30; if (judge) { const id = docList.value[i].id; pointTags.value.setActiveTag(id); // console.log('id', id); break; } } } }, 200); }; const activeTagHandle = (id: string) => { let height: number = docListRef.value.scrollTop; let dom = document.getElementById(id); let domHeight: number = dom!.offsetTop - 20; //滚动距离计算 let H = Number(height) - Number(domHeight); console.log('滚动距离计算', H); if (H < 0) { //下滚 H = Math.abs(H); docListRef.value.scrollBy({ top: H, behavior: 'smooth' }); } else if (H == 0) { //不滚 docListRef.value.scrollBy({ top: 0, behavior: 'smooth' }); } else { //上滚 H = -H; docListRef.value.scrollBy({ top: H, behavior: 'smooth' }); } }; onMounted(() => { docListRef.value.addEventListener('scroll', scrollHandle, true); }); <script>
分类:
JavaScript
, vue
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现