场景需求:
- 左侧为菜单列表,右侧是对应菜单的内容,
- 所有内容可进行无缝滚动
- 当内容滚动到对应的菜单时,菜单进行定位并显示到可视区域
- 点击菜单时,对应内容显示到可视区域
涉及知识点:
- intersectionObserver 监听元素是否在可视区域
- scrollIntoView 滚动到可视区域
思路
切换菜单时,内容滚动到对应菜单
- 定义变量
active
存储当前菜单名称,获取当前内容ref
进行scrollTop
滚动
效果图
滚动内容时,菜单切换对应菜单并可见
- 页面加载时使用
intersectionObserver.observe()
建立观察,观察每一个内容是否在可视区域 - 当内容出现在可视区域时,当
entrie.intersectionRatio
返回值不是0的时候,使用entrie.target.innerHTML.trim()
拿到当前激活的菜单名称赋值给active
- 此时
active
的值进行变化,有了新的ref
名称activeMenu
,于是使用scrollIntoView
将新的激活菜单滚动到可视区域即可
效果图
HTML
<div class="content-box">
<div class="menu-tabs">
<div
class="tab"
:class="{'tab-active':active === item.name}"
v-for="(item,index) in menuList"
:key="index"
:ref="active === item.name ? 'activeMenu':''"
@click="menuClick(item.name,index)">
<span>{{ item.name }}</span>
</div>
</div>
<div class="content-wrap" id="contentWrap">
<div
class="content"
v-for="(content,index) in this.contentList"
:key="index">
<div class="active-title" ref="title"> {{ content.name }}</div>
<div class="content-html" v-html="content.content"/>
</div>
</div>
</div>
CSS
.content-box{
display: flex;
height: 80%;
background-color: #fff;
.menu-tabs{
width: 210px;
font-size: 24px;
overflow-x: hidden;
.tab{
@include fw500;
width: 206px;
height: 80px;
display: flex;
align-items: center;
margin-bottom: 10px;
padding-left: 20px;
background-repeat: no-repeat;
background-image: url('~@/assets/images/disease/tab-bg.png');
background-size: cover;
line-height: 3.5;
&.tab-active{
background-image: url('~@/assets/images/disease/tab-bg-active.png');
}
}
}
.content-wrap{
flex: 1;
font-size: 40px;
padding: 0 16px;
overflow-y: scroll;
.content-html{
font-size: 30px;
text-indent: 2em;
line-height:54px;
font-weight: 400
}
}
}
JS
data(){
return {
active: '第1集',
menuList:[{ name:'第1集' },{ name:'第2集' },{ name:'第3集' },{ name:'第4集' },{ name:'第5集' },{ name:'第6集' },{ name:'第7集' },{ name:'第8集' }],
contentList:[
{ name:'第1集',content:'江湖上传言,二十年前,大魔头容炫在青崖山被五湖盟及天下英雄伏诛,他临终前留下了能让人一夜之间无敌于天下的武库,如果想打开.' },
{ name:'第2集',content:'温客行一眼就看出周子舒使用的是四季山庄的流云九宫步,狠狠教训了顾湘一顿,就带她离开了。张成岭看出周子舒有一身好武功,只是深藏不露,就主动过来和周子舒寒暄,还给他一块名帖,让他有事去镜湖山庄,张成岭着急给母亲买点心,就先行离开了。周子舒听到孩子们在唱那首五湖盟争夺武林盟主以及琉璃甲的歌谣,不禁感慨江湖的风云多变。周子舒叫醒岸边的摆渡船夫,他要乘船去镜湖山庄,摆渡船夫趁机狮子大开口,周子舒也不还价,摆渡船夫看他一副病恹恹的模样,不忍心敲诈他,温客行带顾湘及时赶来,主动提出送周子舒去镜湖山庄,摆渡船夫不依不饶,拉起周子舒就上船离开了。周子舒远远就发现镜湖山庄犹如人间仙境,他迫不及待赶过去,下船就忘了付钱,遭到摆渡船夫劈头盖脸一顿臭骂,周子舒索性就坐一次霸王船。周子舒施展轻功,很快就进入镜湖山庄的桃林,他沉醉于花香之中,温客行突然从背后偷袭,周子舒只能迎战,两个人交手几个回合,温客行对周子舒心生佩服.' },
{ name:'第3集',content:'温客行认定周子舒易了容,几次三番想揭穿他的真面目,周子舒巧妙应付过去,温客行好奇镜湖山庄为何会招惹青崖山鬼谷的人,张成岭也毫不知情,周子舒更不感兴趣,温客行搬出孩童们的歌谣来说事,口口声声称江湖上盛传大魔头容炫留下能让人无敌于天下的武库,打开武库需要琉璃甲,各大门派为了得到琉璃甲互相残杀,周子舒觉得这些人就是想不劳而获,不值得浪费时间讨论,温客行也只好闭嘴。大孤山派掌门沈慎架着一叶小舟来到镜湖山庄,发现这里横尸遍野,岳阳派首徒邓宽等人在帮忙清理尸体,沈慎得知结拜兄弟张玉森,张成峦和张成峰被人虐凌而死,他伤心地痛不欲生,邓宽跪倒在地向沈慎认错,他们来给张玉森送请柬,没想到码头的船都被人赶走了,他们眼看着镜湖山庄着火,最后赶到的时候为时已晚,沈慎忍不住仰天长叹,发誓要为张玉森父子三人报仇。桃红婆和绿柳翁随后赶来,对沈慎恶语相向,大骂他是五湖盟盟主高崇的走狗,让他也追随张玉森一起去死,沈慎气得咬牙切齿,丐帮长老黄鹤及时赶来劝解,劝他们以大局为重,暂时放下个人恩怨。' },
{ name:'第4集',content:'周子舒带着张成岭离开客栈,温客行在路口已经等候多时,张成岭感谢他的救命之恩,就在这时,丐帮大智分舵副舵主跛脚乞丐喊住张成岭,他自称受了黄鹤的委托寻找张玉森的儿子张成岭,丐帮弟子闻讯都围拢过来,张成岭不认识他们,吓得躲到周子舒身后,跛脚乞丐口口声声称沈慎委托丐帮帮忙,坚持要把张成岭带走,张成岭坚决不跟他们走,跛脚乞丐一口咬定周子舒给张成岭下了药,温客行当场和跛脚乞丐发生争执。跛脚乞丐一声令下,丐帮弟子摆出密不透风的大阵,要围攻周子舒,周子舒拜托温客行照顾张成岭,他上下翻飞,不费吹灰之力就把丐帮的大阵攻破,张成岭不禁替周子舒捏了一把汗,让温客行去帮忙,温客行坚信周子舒一个人就能应付。周子舒随后拎起地上的一袋子黄豆洒在地上,丐帮弟子们被摔得东倒西歪,跛脚乞丐趁机去抓张成岭,周子舒被团团包围,温客行催周子舒亮出兵器,周子舒对他置之不理,想突出重围去救张成岭,突然口吐鲜血,温客行把张成岭救下来,周子舒拉起张成岭飞走了,温客行掐死跛脚乞丐,把丐帮弟子们也一一打死。周子舒带张成岭来到小胡同里,他体力渐渐不支,只好原地打坐修复元气。' },
{ name:'第5集',content:'沈慎把桃红婆和绿柳翁打跑,让傲崃子把陆太冲的两个弟子交出来,傲崃子坚决不干,弟子们也想跟着傲崃子,沈慎恼羞成怒,打着保护丹阳派的旗号相威胁,傲崃子毫不畏惧,两个人一言不合就剑拔弩张。青华带着赵敬等人及时赶来制止,沈慎和赵敬称兄道弟,详细讲述了他打跑桃红绿柳的经过,赵敬请傲崃子带着丹阳派的两位弟子去三白山庄,傲崃子断然拒绝,赵敬想把丹阳派的两位弟子留下,他们要谨遵师命跟着傲崃子,赵敬也不再勉强,就此和傲崃子一行人告别。赵敬向沈慎隆重介绍了周子舒和温客行,沈慎看到张成岭还活着,对他们俩表示感谢。赵敬设宴请周子舒和温客行,请来五湖盟的各门派作陪,还让歌姬伴舞助兴,温客行和他们推杯换盏。傲崃子带着众弟子一口气跑到断剑山庄的地盘,眼看天色已晚,突然看到断剑山庄的少庄主穆云歌一路狂奔,嘴里喊着救命。穆云歌向傲崃子求救,口口声声称有女鬼追他,空中传来女鬼幽怨的骂声,大骂穆云歌是薄情郎,没等傲崃子醒过味来,穆云歌就被女鬼抓走了。沈慎借着酒劲不停地劝张成岭喝酒,张成岭不会喝,赵敬赶忙过来解围,让岳阳派弟子宋怀仁把沈慎搀回去休息,派人把张成岭送回房间。' },
{ name:'第6集',content:'温客行突然发现其中一个棺材板剧烈晃动,没等周子舒反应过来,从棺材里跳出来十大恶鬼之一的吊死鬼,他自称给周子舒和温客行下了迷香,摇铃铛把其他棺材里的人都喊出来,每个棺材里都跳出来一个铜皮铁臂的药人,他们团团围住周子舒,对他痛下杀手,周子舒深知药人浑身都是毒药,他无力反抗,可又不甘心就这样死去,多亏温客行及时出手,把那些药人全部打死,周子舒从吊死鬼手里抢了一个缠魂丝匣。周子舒手臂被药人划伤,他先给温客行一颗解药,又用匕首把伤口划开,把里面的毒液吸出来,温客行发现他肩膀上也有伤口,而且身上其他地方还有内伤,赶忙用嘴帮周子舒把肩膀的毒吸出来,周子舒极力掩饰身体有内伤,温客行当面揭穿他用了易容术,好奇他想躲着什么仇家,答应全力以赴帮他对付仇家,劝周子舒和他坦诚相待,周子舒断然拒绝,他不想让任何人看到自己真实的样子。温客行出手试探周子舒的武功,两个人你来我往,互不相让,周子舒因内伤输了一招,他失足跌落水中,温客行见他迟迟不出来,赶忙跳进水池去救他,周子舒撕开面具露出真容,两个人一起上岸烤火,温客行目不转睛盯着周子舒俊秀的面庞,证实了自己的判断,两个人不打不相识.' },
{ name:'第7集',content:'鬼谷的喜丧鬼号称薄情簿主,扬言要杀尽天下所有的负心汉,喜丧鬼听说穆云歌对峨眉弟子莫燕婉始乱终弃,导致莫艳婉含恨吊死在断剑山庄.。' },
{ name:'第8集',content:'高崇对张成岭嘘寒问暖,迫不及待向他讨要琉璃甲,张成岭一问三不知,赵敬赶忙为张成岭解围,谎称他暂时失忆,劝高崇给他一点时间,高崇坚决不干,对张成岭苦苦相逼,沈慎也在一旁帮腔,张成岭大为恼火,他反复讲明不知道琉璃甲的下落,高崇根本不信,还对他威胁恐吓一番。赵敬赶忙从中劝解,高崇更是气不打一处来,把他对张玉森的恨全撒在张成岭身上,赵敬好说歹说才把他劝走,沈慎也对赵敬大为不满,埋怨他太迁就张成岭。曹蔚宁荷包被偷无法结账,赶忙过来向周子舒和温客行赔罪,周子舒邀请他坐下来一起喝酒,他们俩一见如故,把酒言欢,温客行看曹蔚宁不顺眼,示意顾湘把他撵走,顾湘想利用曹蔚宁的关系混进岳阳派,温客行不依不饶,逼顾湘去把偷荷包的贼方不知抓来,曹蔚宁深知方不知的厉害,主动提出帮顾湘去找。曹蔚宁对美食很有研究,他想请顾湘品尝当地美食,顾湘自然求之不得。周子舒早就听说清风剑派的掌门是一只老狐狸,没想到他竟然曹蔚宁这样单纯的儿子,温客行看到周子舒对曹蔚宁热情态度就生气,忍不住对周子舒冷嘲热讽,周子舒只是想通过他打听一下张成岭的下落,没想到温客行已经派顾湘跟着曹蔚宁去岳阳派,设法打听张成岭的消息。周子舒却不买账。' },
],
intersectionObserver:null, // 是否元素在可是区域
}
},
created() {
this.$nextTick(()=>{
this.initIntersectionObserver()
})
},
methods: {
// 切换菜单
menuClick(item,index){
this.intersectionObserver.disconnect()
this.active = item
let contentWrapEl = document.getElementById('contentWrap')
let activeEl = this.$refs['title'][index]
contentWrapEl.scrollTop = activeEl.offsetTop - activeEl.offsetHeight - 70
},
// 当文档进入可视区域时进行跳转tab操作
initIntersectionObserver(){
this.intersectionObserver = new IntersectionObserver((entries) => {
let entrie = entries[0];
if(!entrie.intersectionRatio)return false;
this.active = entrie.target.innerHTML.trim();
setTimeout(()=>{
this.$refs['activeMenu'][0].scrollIntoView();
})
})
this.$refs['title'].forEach(ele=>{
this.intersectionObserver.observe(ele)
})
},
},
附加知识点:
Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
总结:实现这个功能时,最开始我用的是swipe
+getBoundingClientRec
的方式实现,后面是另一个前端小伙伴提醒说可以使用intersectionObserver
,于是才换成现有的方式。无论和哪种人共事,只要他身上有可取之处,就是值得你学习的,加油。