1.首先写一个导航条组件,
1>组件要求父级传的参数包含一个导航列表:sideMenulist,另包含一个锚点id:selectId
2>添加点击menu的方法selectMenu,触发父级菜单对应的锚点id:toParentid
<template>
<div class="sibarmenu">
<div class="sidebar_title">Dashboard Outline</div>
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:default-active="activeIndex"
@select="selectMenu">
<div v-for="(item,index) in sideMenulist" :key="item.id">
<el-menu-item :index="item.id">
<span slot="title">{{item.firsettitle}}</span>
</el-menu-item>
<el-menu-item-group v-if="item.secondtitle.length>0" v-for="(temp,index) in item.secondtitle" :key="temp.id">
<el-menu-item :index="temp.id">
<span>{{temp.title}}</span>
</el-menu-item>
</el-menu-item-group>
</div>
</el-menu>
</div>
</template>
<script>
export default{
props:{
sideMenulist:{
type:Array,
required:true,
},
selectId:{
type:String,
}
},
data() {
return {
activeIndex:''
};
},
watch:{
selectId(){
this.activeIndex = this.selectId;
}
},
methods: {
selectMenu(key) {
this.$emit("toParentid",key);
},
},
mounted(){
console.log('selectId',this.selectId)
}
}
</script>
2.父级页面注入导航条组件
<side-bar @toParentid="showDetails" :sideMenulist="voicesideMenudata" :selectId="selectId"></side-bar>
定义父组件向子组件传递的初始值内容,渲染对应的子组件到父组件中
selectId:null,
voicesideMenudata:[
{
firsettitle:'Overall Status',
id:'Overall Status',
secondtitle:[]
},
{
firsettitle:'Test Set',
id:'Test Set',
secondtitle:[
{title:'● Short Speech',id:'Test Set Short Speech'},
{title:'● Long Speech',id:'Test Set Long Speech'},
]
},
{
firsettitle:'ASR Engine Test Results',
id:'ASR Engine Test Results',
secondtitle:[
{title:'● Short Speech',id:'ASR Engine Test Results Short Speech'},
{title:'● Long Speech',id:'ASR Engine Test Results Long Speech'}
]
},
{
firsettitle:'Server Test Results',
id:'Server Test Results',
secondtitle:[
{title:'● X86',id:'X86'},
{title:'● ARM',id:'ARM'}
]
},
{
firsettitle:'Others',
id:'Others',
secondtitle:[
{title:'● LeVoice for SIoT–Lecoo插座',id:'LeVoice for SIoT–Lecoo插座'},
{title:'● LeVoice for SIoT–联想智能空净',id:'LeVoice for SIoT–联想智能空净'},
{title:'● Smart Headset 语音交互调研',id:'Smart Headset 语音交互调研'},
]
},
],
3.在父组件中添加锚点id和锚点跳转的方法
1>添加锚点id
2>添加锚点跳转方法
//锚点跳转
showDetails(id){
var el=document.getElementById(id);
this.$nextTick(function () {
window.scrollTo({"behavior":"smooth","top":el&&el.offsetTop});
})
}
添加完这些以后,便可以实现简单的点击导航跳转到对应锚点的功能了
接下来,我们添加滚动页面的时候导航跟随锚点添加对应class类的方法
4.在父级页面中给所有锚点添加一个公用的类
5.在父级页面中监听滚动方法,将可视区内的id传递给子组件的selectId
onScroll(){
let that = this;
const navContents = document.querySelectorAll('.acontent')
// 所有锚点元素的 offsetTop
const offsetTopArr = []
navContents.forEach(item => {
let temp={
offsetTop:item.offsetTop,
id:item.id,
}
offsetTopArr.push(temp)
})
// 获取当前文档流的 scrollTop
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
// 定义当前点亮的导航下标
let navIndex = ''
for (let n = 0; n < offsetTopArr.length; n++) {
// 如果 scrollTop 大于等于第 n 个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
// 那么此时导航索引就应该是 n 了
if (scrollTop >= offsetTopArr[n].offsetTop) {
navIndex = offsetTopArr[n].id;
}else{
}
}
// 把下标赋值给 vue 的 data
this.selectId = navIndex;
},
6.在页面初始化的时候监听滚动条滚动,调用scrollTo方法,在离开页面是销毁监听
mounted(){
window.addEventListener('scroll', this.onScroll)
},
destroy() {
// 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
window.removeEventListener('scroll', this.onScroll)
}
7,赋一个父级页面代码的完整例子,子组件完整代码在文章第一条内容里就有
<template>
<div class="levoice">
<div class="content">
<div>
<div class="levoice_content" :class="openflag?'levoice_content':'levoice_content_reback'">
<!-- Overall -->
<div>
<p class="titlebar acontent" id="Overall Status">Overall Status</p>
<Overall></Overall>
</div>
<!-- Testset -->
<div>
<p class="titlebar acontent" id="Test Set">Test Set</p>
<Testset></Testset>
</div>
<!-- ASR Engine Test Result -->
<div>
<!-- <p class="titlebar">ASR Engine Test Result</p> -->
<p class="titlebar acontent" id="ASR Engine Test Results">ASR Engine Test Results – WER based on Pinyin</p>
<Asrengine></Asrengine>
</div>
<!-- Sever Performance Test Result -->
<div>
<p class="titlebar acontent" id="Server Test Results">Server Performance Test Results</p>
<Serverperformance v-on:listenToChildEvent="enlargeImg"></Serverperformance>
</div>
<!-- Others -->
<div>
<p class="titlebar acontent" id="Others">Others</p>
<Others v-on:listenToChildEvent="enlargeImg"></Others>
</div>
</div>
<!-- 左侧菜单栏样式 -->
<div style="border:1px solid #ccc;width:20px;height:100%">
<div @click="openflag=!openflag" class="sibar_switch" :style="openflag?'left:200px':'left:0'">
<i :class="openflag?'el-icon-d-arrow-left':'el-icon-d-arrow-right'"></i>
</div>
</div>
<div class="navigation " :class="openflag?'navigation':'navigation_icon'">
<side-bar @toParentid="showDetails" :sideMenulist="voicesideMenudata" :selectId="selectId"></side-bar>
</div>
</div>
</div>
</div>
</template>
<script>
import Overall from '@/components/AI/lenovovoice/overall/mainpage'
import Testset from '@/components/AI/lenovovoice/testset/mainpage'
import Asrengine from '@/components/AI/lenovovoice/asrengine/mainpage'
import Serverperformance from '@/components/AI/lenovovoice/serverperformance/mainpage'
import Others from '@/components/AI/lenovovoice/others/mainpage'
import SideBar from '@/components/Common/Sidebar'
export default {
data(){
return{
openflag:true,
navTree: [],
selectId:null,
voicesideMenudata:[
{
firsettitle:'Overall Status',
id:'Overall Status',
secondtitle:[]
},
{
firsettitle:'Test Set',
id:'Test Set',
secondtitle:[
{title:'● Short Speech',id:'Test Set Short Speech'},
{title:'● Long Speech',id:'Test Set Long Speech'},
]
},
{
firsettitle:'ASR Engine Test Results',
id:'ASR Engine Test Results',
secondtitle:[
{title:'● Short Speech',id:'ASR Engine Test Results Short Speech'},
{title:'● Long Speech',id:'ASR Engine Test Results Long Speech'}
]
},
{
firsettitle:'Server Test Results',
id:'Server Test Results',
secondtitle:[
{title:'● X86',id:'X86'},
{title:'● ARM',id:'ARM'}
]
},
{
firsettitle:'Others',
id:'Others',
secondtitle:[
{title:'● LeVoice for SIoT–Lecoo插座',id:'LeVoice for SIoT–Lecoo插座'},
{title:'● LeVoice for SIoT–联想智能空净',id:'LeVoice for SIoT–联想智能空净'},
{title:'● Smart Headset 语音交互调研',id:'Smart Headset 语音交互调研'},
]
},
],
}
},
components:{
Overall,
Testset,
Asrengine,
Serverperformance,
Others,
SideBar
},
methods:{
//点击方法图片
enlargeImg(msg,title){
var imgbox = new Image()
imgbox.src=msg;
imgbox.alt="nopicure";
this.$alert("<div class='enlargeImgbox'><img src='"+msg+"'/></div>", title, {
dangerouslyUseHTMLString: true,
confirmButtonText: 'Confirm',
// showConfirmButton:false
}).catch(()=>{
});
},
//锚点跳转
showDetails(id){
var el=document.getElementById(id);
this.$nextTick(function () {
window.scrollTo({"behavior":"smooth","top":el&&el.offsetTop});
})
},
onScroll(){
let that = this;
const navContents = document.querySelectorAll('.acontent')
// 所有锚点元素的 offsetTop
const offsetTopArr = []
navContents.forEach(item => {
let temp={
offsetTop:item.offsetTop,
id:item.id,
}
offsetTopArr.push(temp)
})
// 获取当前文档流的 scrollTop
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
// 定义当前点亮的导航下标
let navIndex = ''
for (let n = 0; n < offsetTopArr.length; n++) {
// 如果 scrollTop 大于等于第 n 个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
// 那么此时导航索引就应该是 n 了
if (scrollTop >= offsetTopArr[n].offsetTop) {
navIndex = offsetTopArr[n].id;
}else{
}
}
// 把下标赋值给 vue 的 data
this.selectId = navIndex;
},
},
mounted(){
window.addEventListener('scroll', this.onScroll)
},
destroy() {
// 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
window.removeEventListener('scroll', this.onScroll)
},
}
</script>