前几天做项目的时候,需要实现一个动态锚点的效果

如果是传统项目,这个效果就非常简单。但是放到 Vue 中,就有两大难题:

1. 在没有 jQuery 的 animate() 方法的情况下,如何实现平滑滚动?

2. 如何监听页面滚动事件?

在浏览了大量文章、进行多次尝试之后,终于解决了这些问题

期间主要涉及到了 setTimeout 的递归用法,和 Vue 生命周期中的 mounted

一、锚点实现

在实现平滑滚动之前,得先确保基本的锚点功能

如果没有其他要求,直接用 <a href="#id"> 是最简单粗暴的办法

但是为了满足后续的要求,必须另外想办法

首先在父组件(表单)中添加 class="d_jump" 作为钩子

然后在子组件中添加一个 jump 方法

jump (index) {
let jump = document.querySelectorAll('.d_jump')
// 获取需要滚动的距离
let total = jump[index].offsetTop
// Chrome
document.body.scrollTop = total
// Firefox
document.documentElement.scrollTop = total
// Safari
window.pageYOffset = total
},

通过 offsetTop 获取对象到窗体顶部的距离,然后赋值给 scrollTop,就能实现锚点的功能

需要注意的是,各浏览器下获取 scrollTop 有所差异

Chrome: document.body.scrollTop

Firefox: document.documentElement.scrollTop

二、平滑滚动

仅仅是锚点是不够的,这样的跳转十分突兀

为了更好的用户体验 ,需要将滚动的过程展现出来

如果有 jQuery 实现平滑滚动就非常简单:

$('html body').animate({scrollTop: total}, );

可惜没如果~~

在看了好些文章之后,有了一个大概的开发思路:

将总距离分成很多小段,然后每隔一段时间跳一段

只要每段的时间足够短,频次足够多,在视觉上就是正常的平滑滚动了


// 平滑滚动,时长500ms,每10ms一跳,共50跳
// 获取当前滚动条与窗体顶部的距离
let distance = document.documentElement.scrollTop || document.body.scrollTop
// 计算每一小段的距离
let step = total /
(function smoothDown () {
if (distance < total) {
distance += step
  // 移动一小段
document.body.scrollTop = distance
document.documentElement.scrollTop = distance
  // 设定每一次跳动的时间间隔为10ms
setTimeout(smoothDown, )
} else {
  // 限制滚动停止时的距离
document.body.scrollTop = total
document.documentElement.scrollTop = total
}
})()

实际情况下,得考虑向上滚动和向下滚动两种情况,完整的代码为:

    jump (index) {
// 用 class="d_jump" 添加锚点
let jump = document.querySelectorAll('.d_jump')
let total = jump[index].offsetTop
let distance = document.documentElement.scrollTop || document.body.scrollTop
// 平滑滚动,时长500ms,每10ms一跳,共50跳
let step = total / 50
if (total > distance) {
smoothDown()
} else {
let newTotal = distance - total
step = newTotal / 50
smoothUp()
}
function smoothDown () {
if (distance < total) {
distance += step
       document.body.scrollTop = distance
document.documentElement.scrollTop = distance
setTimeout(smoothDown, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
}
}
function smoothUp () {
if (distance > total) {
distance -= step
       document.body.scrollTop = distance
document.documentElement.scrollTop = distance
setTimeout(smoothUp, 10)
} else {
document.body.scrollTop = total
document.documentElement.scrollTop = total
}
}
}

三、修改锚点状态

在上面展示的效果中,当页面滚动的时候,锚点的激活状态会有相应的改变

其实这个效果并不难,只需要监听页面滚动事件,然后根据滚动条的距离修改锚点状态就可以了

但是在 Vue 中,应该在什么地方监听滚动事件呢?

  mounted: function () {
this.$nextTick(function () {
window.addEventListener('scroll', this.onScroll)
})
},
methods: {
onScroll () {
let scrolled = document.documentElement.scrollTop || document.body.scrollTop
    // 586、1063分别为第二个和第三个锚点对应的距离
if (scrolled >= 1063) {
this.steps.active = 2
} else if (scrolled < 1063 && scrolled >= 586) {
this.steps.active = 1
} else {
this.steps.active = 0
}
}
}

上面的代码中,我先写了一个修改锚点状态的方法 onScroll,然后在 mounted 中监听 scroll 事件,并执行 onScroll 方法

mounted 是 Vue 生命周期中的一个状态,在这个状态下,$el (vue 实例的根元素)已经创建完毕,但还没有加载数据

从结果上看,也可以在 created 状态下监听 scroll 事件

如果对 mounted 和 created 还不够了解,可以参考官方文档·生命周期图示

后记

上面只能算是一个应急之法,而且这种操作 DOM 的方法,并不符合 Vue 的设计理念

待我研究出更合理更高效的办法之后,再发出来分享~

Vue 爬坑之路(七)—— 监听滚动事件 实现动态锚点的更多相关文章

  1. Vue 爬坑之路(六)—— 使用 Vuex + axios 发送请求

    Vue 原本有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource 目前主流的 Vue 项目,都选择 axios ...

  2. Vue 爬坑之路(九)—— 用正确的姿势封装组件

    迄今为止做的最大的 Vue 项目终于提交测试,天天加班的日子终于告一段落... 在开发过程中,结合 Vue 组件化的特性,开发通用组件是很基础且重要的工作 通用组件必须具备高性能.低耦合的特性 为了满 ...

  3. Vue 爬坑之路(一)—— 使用 vue-cli 搭建项目

    vue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目,GitHub地址是:https://github.com/vuejs/vue-cli vue ...

  4. Vue 爬坑之路(十二)—— vue-cli 3.x 搭建项目

    Vue Cli 3 官方文档:https://cli.vuejs.org/zh/guide/ 一.安装 @vue/cli 更新到 3.x 之后,vue-cli 的包名从 vue-cli 改成了 @vu ...

  5. vue监听滚动事件,实现滚动监听

    在vue中实现滚动监听和原生js无太大差异,下面是一个简单的demo,可在控制台查看结果 <!DOCTYPE html> <html lang="en"> ...

  6. vue监听滚动事件-元素固定位置显示

    1.监听滚动事件 用VUE写一个在控制台打印当前的scrollTop用来测试是否执行: mounted () { window.addEventListener('scroll', this.hand ...

  7. vue监听滚动事件 实现某元素吸顶或者固定位置显示

    https://blog.csdn.net/wang1006008051/article/details/78003974 1.监听滚动事件 利用VUE写一个在控制台打印当前的scrollTop, 首 ...

  8. vue监听滚动事件

    vue中监听滚动事件,然后对其进行事件处理,一般有:1. 滚动到顶部吸附: 2. 根据滚动的位置激活对应的tab键(锚链接tab键) 这两种方式的处理都是可通过监听scroll来实现 mounted( ...

  9. VUE 实现监听滚动事件,实现数据懒加载

    methods: { // 获取滚动条当前的位置 getScrollTop() { let scrollTop = 0 if (document.documentElement && ...

随机推荐

  1. 用phpmailer发送邮件提示SMTP Error: Could not connect to SMTP host解决办法

    之前做项目的时候做了一个用phpmailer发送邮件的功能<CI框架结合PHPmailer发送邮件>,昨天步署上线(刚开始用新浪云,嫌贵,换成阿里了),测试的时候,发送邮件却意外报错了.. ...

  2. 【OCR技术系列之二】文字定位与切割

    要做文字识别,第一步要考虑的就是怎么将每一个字符从图片中切割下来,然后才可以送入我们设计好的模型进行字符识别.现在就以下面这张图片为例,说一说最一般的字符切割的步骤是哪些. 当然,我们实际上要识别的图 ...

  3. jq,返回上一页,小记history.back(-1)和history.go(-1)区别

    <input type="button" name="back" value="重新填写" onclick="javascr ...

  4. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十六节--SignalR与ABP框架Abp.Web.SignalR及扩展

    SignalR简介 SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...

  5. Cs Round#56 D Find Path Union

    题意:有一棵如下的完全二叉树,求所有给定结点到根节点的路径的并有多少条边. 一开始联想到线段树,发现结点的排布很像线段树的标号.于是模仿线段树敲了一下,交上去发现3个点MLE了... 无心优化,跑去看 ...

  6. day8、 显示Linux路由表、各列信息

    要用到的命令是 route route 命令    显示和设置Linux路由表 -A:设置地址类型: -C:打印将Linux核心的路由缓存: -v:详细信息模式: -n:不执行DNS反向查找,直接显示 ...

  7. 阿里云部署Docker(4)----容器的使用

    通过上一节的学习,我们知道怎样执行docker容器,我们执行了一个普通的,一个后台的,我们还学习了几个指令: docker ps - Lists containers. docker logs - S ...

  8. Android 编程之入门开发目录管理器开发文件事件操作-2

    上一篇博客,我们已经得到了目录列表,我们须要对文件列表子项加入事件,比方我们点击的是文件.就运行 打开操作,点击的是目录运行打开目录操作,遍历文件清单.以此类推直到最后一个是文件位置,关于文件 与目录 ...

  9. android-xBuild apk差分与合成,zip差分与合成,lua打包,apk打包,png/jpg图片压缩

    android-xBuild 是一项集成了apk差分与合成,zip差分与合成,lua打包.apk打包,png/jpg图片压缩五大功能的开源项目 (github地址:https://github.com ...

  10. myeclipse配置SVN插件

    方法一:link安装  安装subclipse, MyEclipse SVN插件  1.从官网下载最新的site-1.x.x.zip文件,网址是:folderID=2240" target= ...