封装 Anchors 锚点组件

6 篇文章 0 订阅
6 篇文章 0 订阅

背景:
需求是页面要加一个锚点功能用户通过点击快速定位到指定位置,同时页面增加滚到监听功能,动态激活锚点

先上效果图
锚点实例

解题思路
  • 1 实现点击锚点,页面滑动到指定范围
  • 2 页面滚到增加监听事件,判断当前出去那个锚点区域,对应锚点置为激活状态
    Let’s do it!!!
1.实现点击锚点,页面滑动到指定范围

实现步骤:
step1: 在锚点组件点击对应锚点,获取到是第 n 个锚点被点击了,获取对应 dom 元素
step2: 需要滚动得高度 = 获取到第 n 个锚点所在父容器得位置 + 页面卷起来得高度
scrollTop = jump.position().top + dom.scrollTop
step3: 滚起来! dom.scrollTo({ top: scrollTop,behavior: ‘smooth’ })

jump (index, className) {
  const jump = $('.do-jump').eq(index)
  const scrollTop = jump.position().top + this.scrollBox.scrollTop  // 获取需要滚动的距离
  // Chrome
  this.scrollBox.scrollTo({
    top: scrollTop,
    behavior: 'smooth', // 平滑滚动
  })
}
2.页面滚到增加监听事件,判断当前出去那个锚点区域,对应锚点置为激活状态

step1: 页面 dom 渲染完成获取 topArr[ ] 接收各个锚点区域相对于父容器得位置
step2: 增加滚动监听事件,获取当前滚动高度,遍历跟 topArr 做比较,符合条件,把对应锚点 置为激活状态

setTimeout(() => {
  const jump = $('.do-jump')
  const topArr = []
  for (let i = 0; i < jump.length; i++) {
    if (i > 0) {
      topArr.push(topArr[i - 1] + jump[i - 1].offsetHeight)
    } else {
      topArr.push(jump.eq(i).position().top)
    }
  }
  this.topArr = topArr
}, 1000)
const that = this
// 获取滚动dom元素
this.scrollBox = document.getElementById('scrollBox')
// 监听dom元素的scroll事件
this.scrollBox.addEventListener('scroll', () => {
  const current_offset_top = that.scrollBox.scrollTop
  for (let i = 0; i < this.topArr.length; i++) {
    if (current_offset_top <= this.topArr[i]) {
      // 根据滚动距离判断应该滚动到第几个导航的位置
      that.activeMenu = i
      break
    }
  }
}, true)
礼成!完结撒花!

看了好多博客再加上自己的一些见解写出的文章,如果错误请指出,虚心接受错误,轻喷!!!

封装成一个组件方便其他 tab 页使用,贴一个完整代码

// Anchors.vue
<template>
  <div class="anchor-content m-b-10">
    <span class="anchor" v-for="(anchor,index) in anchors" :key="'anchor'+index" :class="[index === activeMenu ? 'active' : '']" v-if="anchor.count>0"  @click="jump(index,className)">{{anchor.count>0?anchor.value+' ('+anchor.count+')':anchor.value}}</span>
  </div>
</template>

<script>
import $ from 'jquery'
export default {
  props: {
    activeMenu: {
      type: Number,
      default: 0
    },
    anchors: {
      type: Array
    },
    className: {
      type: String,
      required: true,
      default: 'do-jump'
    },
    domId: {
      type: String,
      required: true
    }
  },
  watch: {
    activeName () {
      this.listenScroll(this.className, this.domId)
    }
  },
  methods: {
    jump (index, className) {
      this.$emit('setActive', index)// 当前导航
      const jump = $('.' + className).eq(index)
      const scrollTop = jump.position().top + this.scrollBox.scrollTop - 60 // 获取需要滚动的距离
      // Chrome
      this.scrollBox.scrollTo({
        top: scrollTop,
        behavior: 'smooth', // 平滑滚动
      })
    },
    listenScroll (domId, className) {
      setTimeout(() => {
        const jump = $('.' + className)
        const topArr = []
        for (let i = 0; i < jump.length; i++) {
          if (i > 0) {
            topArr.push(topArr[i - 1] + jump[i - 1].offsetHeight + 20)
          } else {
            topArr.push(jump.eq(i).position().top)
          }
        }
        this.topArr = topArr
      }, 1000)
      const that = this
      // 获取滚动dom元素
      this.scrollBox = document.getElementById(domId)
      // 监听dom元素的scroll事件
      this.scrollBox.addEventListener('scroll', () => {
        const current_offset_top = that.scrollBox.scrollTop
        for (let i = 0; i < this.topArr.length; i++) {
          if (current_offset_top <= this.topArr[i]) {
            // 根据滚动距离判断应该滚动到第几个导航的位置
            this.$emit('setActive', i)
            // that.activeMenu = i
            break
          }
        }
      }, true)
    }
  },
  mounted () {
    this.listenScroll(this.domId, this.className);
  },
}
</script>

<style lang="scss" scoped>
.anchor-content {
  border-bottom: 1px solid #e5e5e5;
  line-height: 14px;
  .anchor {
    padding: 5px 15px 5px 15px;
    font-family: PingFangSC-Regular;
    font-size: 14px;
    color: #888;
    cursor: pointer;
    display: inline-block;
  }
  .anchor:hover {
    text-decoration: underline;
  }
  .active {
    color: #f18d00;
  }
}
</style>

父组件调用示例

<template>
  <div class="info-container">
    <Anchor :className="'do-jump'" :domId="'scrollBox'" :anchors="anchors" :activeMenu="activeMenu" @setActive="setActive"></Anchor>
    <div id="scrollBox" class="applications-content">
      <div class="industry_info do-jump m-b-10">
      ...
      </div>
      <div class="key_personnel do-jump m-b-10" v-if="Employees.length > 0">
      ...
      </div>
      ...
    </div>
  </div>
</template>
import Anchor from "@/components/Anchor.vue"
export default {
  components: {
    Anchor
  },
  data () {
    return {
      activeMenu: 0,
      anchors: [{
        id: 0,
        key: 'industry_info',
        value: '工商信息',
        count: 0
      }, {
        id: 1,
        key: 'key_personnel',
        value: '主要人员',
        count: 0
      }, {
        id: 2,
        key: 'partners',
        value: '股东信息',
        count: 0
      }]
    };
  },
  methods: {
    setActive (activeMenu) {
      this.activeMenu = activeMenu
    }
  }
</script>
<style lang="scss" >
.info-container {
  width: 100%;
  .applications-content {
    width: 100%;
    height: 500px;
    overflow: hidden;
    overflow-y: scroll; // 实现滚动得重要代码 不然scrollTop一直为0 jump和监听都会失效
  }
}
</style>
EDG牛逼!!!中国人不骗中国人

EDG

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo___Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值