Vue实现一个返回顶部backToTop组件


Posted in Javascript onJuly 25, 2017

最近在学习VUE。自己就在研究怎么用VUE实现一个组件的封装,今日就算留个笔记

前言

返回顶部这个功能用jq实现,好容易实现,一个animate配合scrollTo就搞定了

今天我们来试试vue封装一个原生js实现的返回顶部;
写起来够呛,借助github,看了别人的gist,稍微封装了下;

当然不是用scrollTo直接调位那种,没有过渡效果怎么说得过去!!还是捣鼓出来了.

废话不多说,看效果图…

效果图

Vue实现一个返回顶部backToTop组件

实现思路

  1. 过渡用的是requestAnimationFrame,这货只支持IE10+,所以必须做兼容
  2. 滚动视图是window.pageYOffset,这货支持IE9+;
  3. 为了让可控性更强,图标采用iconfont,具体瞅代码

你能学到什么?

  1. 学到一些页面计算相关的东东
  2. 动画API的一些知识
  3. Vue封装组件相关知识和生命周期和事件监听销毁相关知识的运用

实现功能

  1. 视图默认在350处显示返回顶部的按钮和图标
  2. 提示文字和颜色,在图标上下左右的自定义,字段都限制了格式和默认值
  3. 图标颜色和形状,大小的自定义,字段都限制了格式和默认值
  4. 过渡动效的自定义,用法:scrollIt(0, 1500, 'easeInOutCubic', callback);
    1. 返回到视图的point,也就是滚动到哪里
    2. 过渡时间(ms级别)
    3. 一堆过渡效果,字符串格式,其实就是滚动的计算函数..
    4. 当然少不了默认参数了,除了callback
  5. 兼容性是IE9+,特意开了虚拟机去尝试

代码

scrollIt.js ?过渡滚动实现

export function scrollIt(
 destination = 0,
 duration = 200,
 easing = "linear",
 callback
) {
 // define timing functions -- 过渡动效
 let easings = {
  // no easing, no acceleration
  linear(t) {
   return t;
  },
  // accelerating from zero velocity
  easeInQuad(t) {
   return t * t;
  },
  // decelerating to zero velocity
  easeOutQuad(t) {
   return t * (2 - t);
  },
  // acceleration until halfway, then deceleration
  easeInOutQuad(t) {
   return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
  },
  // accelerating from zero velocity
  easeInCubic(t) {
   return t * t * t;
  },
  // decelerating to zero velocity
  easeOutCubic(t) {
   return --t * t * t + 1;
  },
  // acceleration until halfway, then deceleration
  easeInOutCubic(t) {
   return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
  },
  // accelerating from zero velocity
  easeInQuart(t) {
   return t * t * t * t;
  },
  // decelerating to zero velocity
  easeOutQuart(t) {
   return 1 - --t * t * t * t;
  },
  // acceleration until halfway, then deceleration
  easeInOutQuart(t) {
   return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
  },
  // accelerating from zero velocity
  easeInQuint(t) {
   return t * t * t * t * t;
  },
  // decelerating to zero velocity
  easeOutQuint(t) {
   return 1 + --t * t * t * t * t;
  },
  // acceleration until halfway, then deceleration
  easeInOutQuint(t) {
   return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
  }
 };
 // requestAnimationFrame()的兼容性封装:先判断是否原生支持各种带前缀的
 //不行的话就采用延时的方案
 (function() {
  var lastTime = 0;
  var vendors = ["ms", "moz", "webkit", "o"];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
   window.requestAnimationFrame =
    window[vendors[x] + "RequestAnimationFrame"];
   window.cancelAnimationFrame =
    window[vendors[x] + "CancelAnimationFrame"] ||
    window[vendors[x] + "CancelRequestAnimationFrame"];
  }

  if (!window.requestAnimationFrame)
   window.requestAnimationFrame = function(callback, element) {
    var currTime = new Date().getTime();
    var timeToCall = Math.max(0, 16 - (currTime - lastTime));
    var id = window.setTimeout(function() {
     callback(currTime + timeToCall);
    }, timeToCall);
    lastTime = currTime + timeToCall;
    return id;
   };

  if (!window.cancelAnimationFrame)
   window.cancelAnimationFrame = function(id) {
    clearTimeout(id);
   };
 })();

 function checkElement() {
  // chrome,safari及一些浏览器对于documentElemnt的计算标准化,reset的作用
  document.documentElement.scrollTop += 1;
  let elm =
   document.documentElement.scrollTop !== 0
    ? document.documentElement
    : document.body;
  document.documentElement.scrollTop -= 1;
  return elm;
 }

 let element = checkElement(); 
 let start = element.scrollTop; // 当前滚动距离
 let startTime = Date.now(); // 当前时间

 function scroll() { // 滚动的实现
  let now = Date.now();
  let time = Math.min(1, (now - startTime) / duration);
  let timeFunction = easings[easing](time);
  element.scrollTop = timeFunction * (destination - start) + start;

  if (element.scrollTop === destination) {
   callback; // 此次执行回调函数
   return;
  }
  window.requestAnimationFrame(scroll);
 }
 scroll();
}

backToTop.vue

<template>
 <div class="back-to-top" @click="backToTop" v-show="showReturnToTop" @mouseenter="show" @mouseleave="hide">
  <i :class="[bttOption.iClass]" :style="{color:bttOption.iColor,'font-size':bttOption.iFontsize}"></i>
  <span class="tips" :class="[bttOption.iPos]" :style="{color:bttOption.textColor}" v-show="showTooltips">{{bttOption.text}}</span>
 </div>
</template>

<script>
 import { scrollIt } from './scrollIt'; // 引入动画过渡的实现
 export default {
  name: 'back-to-top',
  props: {
   text: { // 文本提示
    type: String,
    default: '返回顶部'
   },
   textColor: { // 文本颜色
    type: String,
    default: '#f00'
   },
   iPos: { // 文本位置
    type: String,
    default: 'right'
   },
   iClass: { // 图标形状
    type: String,
    default: 'fzicon fz-ad-fanhuidingbu1'
   },
   iColor: { // 图标颜色
    type: String,
    default: '#f00'
   },
   iFontsize: { // 图标大小
    type: String,
    default: '32px'
   },
   pageY: { // 默认在哪个视图显示返回按钮
    type: Number,
    default: 400
   },
   transitionName: { // 过渡动画名称
    type: String,
    default: 'linear'
   }
  },
  data: function () {
   return {
    showTooltips: false,
    showReturnToTop: false
   }
  },
  computed: {
   bttOption () {
    return {
     text: this.text,
     textColor: this.textColor,
     iPos: this.iPos,
     iClass: this.iClass,
     iColor: this.iColor,
     iFontsize: this.iFontsize
    }
   }
  },
  methods: {
   show () { // 显示隐藏提示文字
    return this.showTooltips = true;
   },
   hide () {
    return this.showTooltips = false;
   },
   currentPageYOffset () {
    // 判断滚动区域大于多少的时候显示返回顶部的按钮
    window.pageYOffset > this.pageY ? this.showReturnToTop = true : this.showReturnToTop = false;

   },
   backToTop () {
    scrollIt(0, 1500, this.transitionName, this.currentPageYOffset);
   }
  },
  created () {
   window.addEventListener('scroll', this.currentPageYOffset);
  },
  beforeDestroy () {
   window.removeEventListener('scroll', this.currentPageYOffset)
  }
 }
</script>

<style scoped lang="scss">
 .back-to-top {
  position: fixed;
  bottom: 5%;
  right: 100px;
  z-index: 9999;
  cursor: pointer;
  width: auto;
  i {
   font-size: 32px;
   display: inline-block;
   position: relative;
   text-align: center;
   padding: 5px;
   background-color: rgba(234, 231, 231, 0.52);
   border-radius: 5px;
   transition: all 0.3s linear;
   &:hover {
    border-radius: 50%;
    background: #222;
    color: #fff !important;
   }
  }
  .tips {
   display: inline-block;
   position: absolute;
   word-break: normal;
   white-space: nowrap;
   width: auto;
   font-size: 12px;
   color: #fff;
   z-index: -1;
  }
  .left {
   right: 0;
   top: 50%;
   margin-right: 50px;
   transform: translateY(-50%);
  }
  .right {
   left: 0;
   top: 50%;
   margin-left: 50px;
   transform: translateY(-50%);
  }
  .bottom {
   bottom: 0;
   margin-top: 50px;
  }
  .top {
   top: 0;
   margin-bottom: 50px;
  }
 }
</style>

总结

从心血来潮到折腾出来,为了兼顾兼容性和拓展性,好像几个小时了.

不过实现了.你再搬到其他语言,类似ng4,也就是十来分钟的事情,

思路会了,实现更多的是写法而已,至于性能优化,可以一边写一边考虑,也可以实现后有空再优化.

希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
彻底搞懂JS无缝滚动代码
Jan 03 Javascript
使用js对select动态添加和删除OPTION示例代码
Aug 12 Javascript
只需一行代码,轻松实现一个在线编辑器
Nov 12 Javascript
详解JavaScript的AngularJS框架中的表达式与指令
Mar 05 Javascript
微信小程序 数组中的push与concat的区别
Jan 05 Javascript
浅谈js停止事件冒泡 阻止浏览器的默认行为(阻止超连接 #)
Feb 08 Javascript
微信小程序实战之轮播图(3)
Apr 17 Javascript
vue 请求后台数据的实例代码
Jun 22 Javascript
JS实现问卷星自动填问卷脚本并在两秒自动提交功能
Jun 17 Javascript
React Native自定义控件底部抽屉菜单的示例
Feb 08 Javascript
JavaScript引用类型之基本包装类型实例分析【Boolean、Number和String】
Aug 09 Javascript
使用原生JS实现滚轮翻页效果的示例代码
May 31 Javascript
基于jquery实现多级菜单效果
Jul 25 #jQuery
关于TypeScript中import JSON的正确姿势详解
Jul 25 #Javascript
微信JSSDK调用微信扫一扫功能的方法
Jul 25 #Javascript
利用node.js爬取指定排名网站的JS引用库详解
Jul 25 #Javascript
详解angularjs获取元素以及angular.element()用法
Jul 25 #Javascript
以BootStrap Tab为例写一个前端组件
Jul 25 #Javascript
基于Bootstrap的标签页组件及bootstrap-tab使用说明
Jul 25 #Javascript
You might like
很好用的PHP数据库类
2009/05/27 PHP
CodeIgniter控制器之业务逻辑实例分析
2016/01/20 PHP
PHP中include/require/include_once/require_once使用心得
2016/08/28 PHP
基于PHP-FPM进程池探秘
2017/10/17 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
JavaScript 动态添加表格行 使用模板、标记
2009/10/24 Javascript
jquery验证表单中的单选与多选实例
2013/08/18 Javascript
js+jquery常用知识点汇总
2015/03/03 Javascript
jquery带动画效果幻灯片特效代码
2015/08/27 Javascript
Bootstrap table使用方法总结
2017/05/10 Javascript
基于VUE.JS的移动端框架Mint UI的使用
2017/10/11 Javascript
vue+element UI实现树形表格带复选框的示例代码
2019/04/16 Javascript
layui数据表格跨行自动合并的例子
2019/09/02 Javascript
从零使用TypeScript开发项目打包发布到npm
2020/02/14 Javascript
加速vue组件渲染之性能优化
2020/04/09 Javascript
微信小程序实现点赞业务
2021/02/10 Javascript
python递归删除指定目录及其所有内容的方法
2017/01/13 Python
Python模拟脉冲星伪信号频率实例代码
2018/01/03 Python
Python中的heapq模块源码详析
2019/01/08 Python
python 图像处理画一个正弦函数代码实例
2019/09/10 Python
8段用于数据清洗Python代码(小结)
2019/10/31 Python
Python实现新型冠状病毒传播模型及预测代码实例
2020/02/05 Python
基于python实现上传文件到OSS代码实例
2020/05/09 Python
Python 使用生成器代替线程的方法
2020/08/04 Python
HTML5实现多张图片上传功能
2016/03/11 HTML / CSS
马来西亚太阳镜、眼镜和隐形眼镜网上商店:Focus Point
2018/12/13 全球购物
英国汽车零件购物网站:GSF Car Parts
2019/05/23 全球购物
几个数据库方面的面试题
2016/07/01 面试题
西部世纪.net笔试题面试题
2014/04/03 面试题
竞选班长的演讲稿
2014/04/24 职场文书
超市店庆活动方案
2014/08/31 职场文书
课堂打架检讨书200字
2014/11/21 职场文书
六一儿童节致辞
2015/07/31 职场文书
检讨书范文
2019/04/16 职场文书
Golang map映射的用法
2022/04/22 Golang