【vue】【intersectionObserver】滚动正文时菜单滚动到对应菜单

Myth丶恋晨 2022-10-20 13:45 309阅读 0赞

场景需求:

  • 左侧为菜单列表,右侧是对应菜单的内容,
  • 所有内容可进行无缝滚动
  • 当内容滚动到对应的菜单时,菜单进行定位并显示到可视区域
  • 点击菜单时,对应内容显示到可视区域

涉及知识点:

  • intersectionObserver 监听元素是否在可视区域
  • scrollIntoView 滚动到可视区域

思路

切换菜单时,内容滚动到对应菜单

  • 定义变量active存储当前菜单名称,获取当前内容ref进行scrollTop滚动

效果图

在这里插入图片描述

滚动内容时,菜单切换对应菜单并可见

  • 页面加载时使用intersectionObserver.observe()建立观察,观察每一个内容是否在可视区域
  • 当内容出现在可视区域时,当entrie.intersectionRatio返回值不是0的时候,使用entrie.target.innerHTML.trim()拿到当前激活的菜单名称赋值给active
  • 此时active的值进行变化,有了新的ref名称activeMenu,于是使用scrollIntoView将新的激活菜单滚动到可视区域即可

效果图

在这里插入图片描述

HTML

  1. <div class="content-box">
  2. <div class="menu-tabs">
  3. <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)">
  4. <span>{
  5. { item.name }}</span>
  6. </div>
  7. </div>
  8. <div class="content-wrap" id="contentWrap">
  9. <div class="content" v-for="(content,index) in this.contentList" :key="index">
  10. <div class="active-title" ref="title"> {
  11. { content.name }}</div>
  12. <div class="content-html" v-html="content.content"/>
  13. </div>
  14. </div>
  15. </div>

CSS

  1. .content-box{
  2. display: flex;
  3. height: 80%;
  4. background-color: #fff; .menu-tabs{
  5. width: 210px;
  6. font-size: 24px;
  7. overflow-x: hidden; .tab{
  8. @include fw500;
  9. width: 206px;
  10. height: 80px;
  11. display: flex;
  12. align-items: center;
  13. margin-bottom: 10px;
  14. padding-left: 20px;
  15. background-repeat: no-repeat;
  16. background-image: url('~@/assets/images/disease/tab-bg.png');
  17. background-size: cover;
  18. line-height: 3.5; &.tab-active{
  19. background-image: url('~@/assets/images/disease/tab-bg-active.png');
  20. }
  21. }
  22. }
  23. .content-wrap{
  24. flex: 1;
  25. font-size: 40px;
  26. padding: 0 16px;
  27. overflow-y: scroll; .content-html{
  28. font-size: 30px;
  29. text-indent: 2em;
  30. line-height:54px;
  31. font-weight: 400
  32. }
  33. }
  34. }

JS

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

附加知识点:

  • getBoundingClientRect

Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。

在这里插入图片描述

  • Object.entries

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

在这里插入图片描述
总结:实现这个功能时,最开始我用的是swipe+getBoundingClientRec的方式实现,后面是另一个前端小伙伴提醒说可以使用intersectionObserver,于是才换成现有的方式。无论和哪种人共事,只要他身上有可取之处,就是值得你学习的,加油。

发表评论

表情:
评论列表 (有 0 条评论,309人围观)

还没有评论,来说两句吧...

相关阅读