滾動效果
當頁面滑動時,左邊導航欄會自動定位到當前標題,一級標題展開,二級標題的字體變紅色,字體前面有一個小圖標。
上圖。。。。。。。。。。。 html
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>
1、明確各類位置vue
圖片來源於網絡ios
此次項目最經常使用的就是 scrollTop 、offsetTop
其中 srcollTop能夠理解爲 :頁面隨着滾動條下滑而隱藏的高度
offsetTop 能夠理解爲 :當前元素距離它最近的祖先元素頂部的距離,而且這個祖先元素的position不爲static。若是沒有,則是該元素與body頂部的距離web
2、滾動思路axios
滾動到什麼地方,左邊導航欄出現樣式??
當滾動的高度>=右邊第i個div的offsetTop,則左邊的第i個標題出現樣式。api
3、添加滾動監聽事件
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(){ //這裏放的函數下面講到 } }
4、在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);//在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>
前端新手,代碼冗長,有不合理和須要改進的地方麻煩提出