vue实现滚动监听,点击瞄点平滑滚动,控制内嵌滚动条滚动
滚动效果当页面滑动时,左边导航栏会自动定位到当前标题,一级标题展开,二级标题的字体变红色,字体前面有一个小图标。上图。。。。。。。。。。。Html代码<template><div id="notes"><nav-top></nav-top><!-- 中间
滚动效果
当页面滑动时,左边导航栏会自动定位到当前标题,一级标题展开,二级标题的字体变红色,字体前面有一个小图标。
上图。。。。。。。。。。。
Html代码
<template>
<div id="notes">
<nav-top></nav-top>
<!-- 中间部分 -->
<div class="notes_detail_page">
<div class="left" id="left_y_scroll" ref="lys">
<div >
<div class="side_nav" id="chap_nav">
<ul v-for="NItem1 in chapList" class="side_nav_level1">
<li id="lis" @click="UpClick(NItem1.ordered)" class="first_li" >{{NItem1.ordered}} {{NItem1.title}}
<ul class="side_nav_level2" v-show="UnderTitle.id==NItem1.ordered&&UnderTitle.isshow" >
<li v-for="(NItem2,index) in NItem1.episodeList" @click.stop :id="'lNav'+(NItem2.id-1)">
<!--@click.stop
阻止事件冒泡
-->
<span>
<img v-show="isshow==NItem2.id-1" src="@/assets/images/landmark.png"/>
</span>
<a id="nav_a" @click="jump(NItem2.id-1)" :class="{'a_red':isshow==NItem2.id-1}">{{NItem1.ordered}}.{{NItem2.ordered}} {{NItem2.title}}</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="right">
<div id="hide">
<h1 id="v_title">{{VideoList.title}}</h1>
<div class="avatar_items">
<img class="avatar" :src="AuthorList.head_img"/>
<div class="items">
<p id="author">{{AuthorList.name}}</p>
<span id="c_time">{{VideoList.create_time}}</span>
<img class="view" src="@/assets/images/view.png"/>
<span id="viewNum">{{VideoList.view_num}}</span>
<img class="fabulous" src="@/assets/images/fabulous.png"/>
<span id="praise_num">6666</span>
</div>
</div>
<div class="note_list" v-for="NItem1 in chapList">
<div v-for="NItem2 in NItem1.episodeList" class="notes_text" :data-id="NItem1.ordered">
<h2 v-html="NItem1.ordered+'.'+NItem2.ordered+' '+NItem2.title"></h2>
<p v-html="NItem2.note"></p>
</div>
</div>
</div>
</div>
</div>
<footer-container></footer-container>
</div>
</template>
一、明确各种位置
图片来源于网络
这次项目最常用的就是 scrollTop 、offsetTop
其中 srcollTop可以理解为 :页面随着滚动条下滑而隐藏的高度
offsetTop 可以理解为 :当前元素距离它最近的祖先元素顶部的距离,并且这个祖先元素的position不为static。如果没有,则是该元素与body顶部的距离
二、滚动思路
滚动到什么地方,左边导航栏出现样式??
当滚动的高度>=右边第i个div的offsetTop,则左边的第i个标题出现样式。
三、添加滚动监听事件
1.添加滚动监听事件
知识点:addEventListener() 方法,事件监听
用法:element.addEventListener(event, function, useCapture);
第一个参数是:事件的类型。这个项目是滚动监听,所以event是写“scroll”。(其他项目可根据需求,如果是点击就写“click”,以此类推);
第二个参数是:监听事件时调用的函数。这里调用的是 this.menu 这个函数。
第三个参数是:布尔值。即true/false,这个参数是与事件捕获和事件冒泡有关,与这两个有关一般是点击事件,这个项目是滚动事件,所以第三个参数可以不写。
mounted(){
window.addEventListener("scroll",this.menu)
}
2.在data里面定义一个字符串scroll存放滚动的高度也就是scrollTop,并且在watch中监听data里面scroll的数据变化。
data(){
return{
scroll:""
}
},
watch(){
srcoll:function(){
//这里放的函数下面讲到
}
}
四、在methods定义方法,主要有三个步骤
1.触发滚动监听事件时,调用的函数,此函数的作用是获取滚动条的高度
menu:function(){
this.srcoll=window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
}
//兼容不同的三个浏览器版本
//也就是上文调用的函数window.addEventListener("scroll",this.menu)
2.定义一个平滑滚动的方法,参考网络上的大神写的。
定义变量total=div[index].offsetTop,则滚动条就需要滚动这个total的距离。
为了达到平滑滚动的效果,把总距离total分成50个小段,每10ms执行一次。
并且还要区分是向上滑动还是向下滑动,完整代码如下:
jump:function(index){ //把左边导航栏li的下标传进来。
this.isshow=index;//使左边导航出现相应的样式
let divArr=document.querySelectorAll(".notes_text");//获取右边的div数组
let total=divArr[index].offsetTop;//获取第index个div到窗口顶部的距离
let distance = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset//获取滚动条的高度(兼容三种浏览器版本)
//平滑滚动的效果,把总距离分成50个小段,每10ms执行一次
let step = total / 50
if (total > distance) { //当divArr.[index]offsetTop的距离>滚动条的距离,向下滑动,此时滑动的距离是total
smoothDown() //向下滑动
} else {
let newTotal = distance - total //当div到窗口的距离<滚动条的距离,向上滑动,此时滑动的距离是distance - total
step = newTotal / 50;
smoothUp()
}
//向下滑动
function smoothDown () {
if (distance < total) {
distance = distance + step
document.body.scrollTop = distance
document.documentElement.scrollTop = distance
window.pageYOffset = total;
setTimeout(smoothDown, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
window.pageYOffset = total;
}
}
//向上滑动
function smoothUp () {
if (distance > total) {
distance -= step
document.body.scrollTop = distance
document.documentElement.scrollTop = distance
window.pageYOffset = total;
setTimeout(smoothUp, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
window.pageYOffset = total;
}
}
}
3.定义方法实现当滚动条的高度>divArr[index].offsetTop时,左边样式改变的函数
loadSroll: function () {
let divArr=document.querySelectorAll(".notes_text");//获取右边div的数组
for (var i = 0; i < divArr.length; i++) {
if (this.scroll >= divArr[i].offsetTop) { //滚动条的高度>divArr[index].offsetTop,左边导航栏样式改变
var OrderId = divArr[i].getAttribute("data-id");//获取div中data-id的属性值。为了实现左边一级标题打开的效果
this.UnderTitle={id:OrderId,isshow:true};//实现一级标题打开
this.isshow = i;//实现字体变红,小图标出现
//控制左边内嵌滚动条滚动
var lOffsetTop = document.getElementById("lNav"+i).offsetTop;//获取左边导航栏li距离li最近的祖先元素id为left_y_scroll的元素的顶部的距离。(left_y_scroll的position为fixed),详情见下图
if(lOffsetTop > 300){ //当li的offsetTop大于300时,滚动条需要下滑,因为整个div的高度为350px,所以我这里设置了300
this.$refs.lys.scrollTop = lOffsetTop; //使子滚动条的滚动高度,等于lOffsetTop
}else{
this.$refs.lys.scrollTop = 0;//在不大于300的情况下,子滚动条的高度为0.
}
}
}
}
这里的这个函数,需要放在watch里面,因为这里的this.srcoll 是data里面的srcoll,而srcoll是靠watch监听。
所以我们需要在watch()里面写:
watch(){
srcoll:function(){
this.loadSroll()
}
}
lOffsetTop的距离如下图
滚动监听的效果,就可以实现了
完成代码如下!!!!!
<script>
import NavTop from "@/components/NavTop.vue"
import FooterContainer from "@/components/FooterContainer.vue"
export default{
components:{
NavTop,
FooterContainer
},
created(){
this.init();
},
data(){
return{
chapList:[],//一级标题和二级标题的数组
VideoList:[],
AuthorList:[],
epiList:[],
UnderTitle:"",//左边导航栏的状态判断,其中isshow为true且id相符时,显示
scroll:"",//存储滚动条的高度
isshow:-1,//默认导航栏小图标不显示,点击之后显示
left_up:false,
}
},
watch: {
scroll: function () { //用来监听data中的scroll字符串的变化
this.loadSroll()
}
},
mounted() {
window.addEventListener('scroll', this.menu,false);//在mounted钩子中给window添加一个滚动监听事件
},
methods:{
init:function(){
this.getVideoDetail();
},
getVideoDetail:function(){
this.$axios.get(this.GLOBAL.host+"/pub/api/v1/web/video_detail",{
params:{
video_id:this.$route. query.video_id
}
}).then(res =>{
//console.log(res.data.data);
this.VideoList=res.data.data.video;
this.AuthorList=res.data.data.author;
this.chapList=res.data.data.chapter_list;
//console.log(this.chapList);
for(var i=0;i<this.chapList.length;i++){
for(var j=0;j<this.chapList[i].episodeList.length;j++){
this.epiList.push(this.chapList[i].episodeList[j])
for(var k=0;k<this.epiList.length;k++){
this.epiList[k].id=k+1;
//console.log(k)
}
}
}
//console.log(this.epiList);
});
},
UpClick:function(id){
if(typeof this.UnderTitle.isshow=="underfine"||this.UnderTitle.id!=id){
this.UnderTitle={id:id,isshow:true}
}else{
//当点击两次以上,ul隐藏的情况
this.UnderTitle.isshow=!this.UnderTitle.isshow;
}
},
menu:function(){
//获取滚动条的高度
this.scroll=window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
},
jump:function(index){
this.isshow=index;//使左边导航出现相应的样式
//console.log(index)
let divArr=document.querySelectorAll(".notes_text");//获取右边的div数组
let total=divArr[index].offsetTop;//获取第index个div的offsetTop距离
let distance = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset//获取滚动条的高度(兼容三种浏览器版本)
//平滑滚动的效果,把总距离分成50个小段,每10ms执行一次
let step = total / 50
if (total > distance) { //当div到窗口的距离>滚动条的距离,向下滑动,此时滑动的距离是total
smoothDown() //向下滑动
} else {
let newTotal = distance - total //当div到窗口的距离<滚动条的距离,向上滑动,此时滑动的距离是distance - total
step = newTotal / 50;
smoothUp()
}
//向下滑动
function smoothDown () {
if (distance < total) {
distance = distance + step
document.body.scrollTop = distance
document.documentElement.scrollTop = distance
window.pageYOffset = total;
setTimeout(smoothDown, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
window.pageYOffset = total;
}
}
//向上滑动
function smoothUp () {
if (distance > total) {
distance -= step
document.body.scrollTop = distance
document.documentElement.scrollTop = distance
window.pageYOffset = total;
setTimeout(smoothUp, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
window.pageYOffset = total;
}
}
},
loadSroll: function () {
let divArr=document.querySelectorAll(".notes_text");
//console.log(divArr)
for (var i = 0; i < divArr.length; i++) {
if (this.scroll >= divArr[i].offsetTop - 88 ) { //这里其实可以减去一个数值,使其左边的导航栏的样式提前出现,我这里是减去了top栏的高度。
//console.log(i)
var OrderId = divArr[i].getAttribute("data-id");
//console.log(OrderId);
this.UnderTitle={id:OrderId,isshow:true};
this.isshow = i;
var lOffsetTop = document.getElementById("lNav"+i).offsetTop;//获取li到窗口的距离
console.log(lOffsetTop);
if(lOffsetTop > 300){ //当li的offsetTop大于300时,滚动条需要下滑,因为整个div的高度为350px,所以我这里设置了300
this.$refs.lys.scrollTop = lOffsetTop; //使子滚动条的滚动高度,等于lOffsetTop
}else{
this.$refs.lys.scrollTop = 0;//在不大于300的情况下,子滚动条的高度为0.
}
}
}
}
},
}
</script>
前端新手,代码冗长,有不合理和需要改进的地方麻烦提出
更多推荐
所有评论(0)