锚点功能的实现

1.页面:

  1. //需要被定为的点
  2. <div class="choice-result-box" id="questionReport">
  3. <template v-for="(item, index) in list">
  4. <div :id="'anchor-'+(index+1)">
  5. </div>
  6. </tempate>
  7. </div>
  8. //触发锚点事件
  9. <div @click="nextQuestion" data-classname="choice-result-box" :data-index="quesIndex"
  10. v-anchor="'anchor-'+quesIndex">
  11. <span>下一题</span>
  12. </div>

2.vue自定义指令

  1. // 当被绑定的元素插入到 DOM 中时
  2. inserted: function (el, binding) {
  3. el.onclick = function () {
  4. //要定位的元素className
  5. let className = el.dataset.classname;
  6. //第一个元素相对于文档偏移量
  7. let topOffsetPx = document.getElementsByClassName(className)[0].offsetTop;
  8. //当前选中的元素文档偏移量
  9. let domOffsetPx = document.getElementById('anchor-' + el.dataset.index).offsetTop;
  10. // 目标元素相对于文档偏移量 - 第一个元素相对于文档偏移量 就是滚动条要滚动的距离
  11. let scrollTopPx = domOffsetPx - topOffsetPx;
  12. document.getElementById('questionReport').scrollTo({
  13. top:scrollTopPx,
  14. behavior:'smooth'
  15. });
  16. }
  17. }

3.js实现动画滚动效果

方法一:

  1. el.onclick = function () {
  2. //要定位的元素className
  3. let className = el.dataset.classname;
  4. //第一个元素相对于文档偏移量
  5. let topOffsetPx = document.getElementsByClassName(className)[0].offsetTop;
  6. //当前选中的元素文档偏移量
  7. let domOffsetPx = document.getElementById('anchor-' + el.dataset.index).offsetTop;
  8. // 目标元素相对于文档偏移量 - 第一个元素相对于文档偏移量 就是滚动条要滚动的距离
  9. let scrollTopPx = domOffsetPx - topOffsetPx;
  10. //需要滚动的距离不应该每次从头开始
  11. topOffsetPx += document.getElementById('questionReport').scrollTop;
  12. let speed = scrollTopPx / 50;
  13. (
  14. //方法一
  15. function smoothDown() {
  16. //大于的话是向下滚动,小于是向上滚动
  17. if (scrollTopPx > topOffsetPx) {
  18. topOffsetPx += speed;
  19. //因为scrollTop取小数会造成不准确的问题,所以大于的话直接取需要滚动的距离
  20. if (topOffsetPx > scrollTopPx) {
  21. topOffsetPx = scrollTopPx
  22. }
  23. document.getElementById('questionReport').scrollTop = topOffsetPx;
  24. setTimeout(smoothDown, 40);
  25. }
  26. }
  27. )();
  28. }
  29. }

方法二:

  1. inserted: function (el, binding) {
  2. el.onclick = function () {
  3. //要定位的元素className
  4. let className = el.dataset.classname;
  5. //第一个元素相对于文档偏移量
  6. let topOffsetPx = document.getElementsByClassName(className)[0].offsetTop;
  7. //当前选中的元素文档偏移量
  8. let domOffsetPx = document.getElementById('anchor-' + el.dataset.index).offsetTop;
  9. // 目标元素相对于文档偏移量 - 第一个元素相对于文档偏移量 就是滚动条要滚动的距离
  10. let scrollTopPx = domOffsetPx - topOffsetPx;
  11. (function startRollToEnd(end = 0, time = 1000) {
  12. let timer;
  13. //获取当前毫秒数
  14. let startTime = +new Date();
  15. let start = document.getElementById('questionReport').scrollTop; //初始位置
  16. //获取从开始到结束需要滚动的长度
  17. let lengthY =scrollTopPx-start ;
  18. timer = requestAnimationFrame(function func() {
  19. //获取下一帧的时间距离开始的时间,以此计算此时的位置,如果超过了预计的时间,则就等于参数所规定的时间
  20. let timeX = time - Math.max(0, startTime - (+new Date()) + time);
  21. document.getElementById('questionReport').scrollTop = timeX * (lengthY) / time + start;
  22. timer = requestAnimationFrame(func);
  23. // 如果距离开始时间已经到了规定的时间则不用在执行了
  24. if (timeX == time) {
  25. cancelAnimationFrame(timer);
  26. }
  27. });
  28. }
  29. )();
  30. }
  31. }

其他实现方法

  1. let button = document.getElementById('button')
  2. button.addEventListener('click',function(){
  3. let cb = ()=>{
  4. if(document.documentElement.scrollTop===0){
  5. //满足条件,不再递归调用
  6. return;
  7. } else {
  8. let speed = 40 //每个帧内滚动条移动的距离
  9. document.documentElement.scrollTop -= speed
  10. //不满足条件,再次调用cb
  11. requestAnimationFrame(cb)
  12. }
  13. }
  14. requestAnimationFrame(cb)
  15. }

参考链接:https://juejin.cn/post/6844903925473083405

image.png

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

  1. function animateScroll(element,speed) {
  2. let rect=element.getBoundingClientRect();
  3. //获取元素相对窗口的top值,此处应加上窗口本身的偏移
  4. let top=window.pageYOffset+rect.top;
  5. let currentTop=0;
  6. let requestId;
  7. //采用requestAnimationFrame,平滑动画
  8. function step(timestamp) {
  9. currentTop+=speed;
  10. if(currentTop<=top){
  11. window.scrollTo(0,currentTop);
  12. requestId=window.requestAnimationFrame(step);
  13. }else{
  14. window.cancelAnimationFrame(requestId);
  15. }
  16. }
  17. window.requestAnimationFrame(step);
  18. }

参考文档:https://www.jianshu.com/p/b11b058ff5d8