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 相关文章推荐
Firefox window.close()的使用注意事项
Apr 11 Javascript
Webkit的跨域安全问题说明
Sep 13 Javascript
修复IE9&amp;safari 的sort方法
Oct 21 Javascript
FF火狐下获取一个元素同类型的相邻元素实现代码
Dec 15 Javascript
js 立即调用的函数表达式如何写
Jan 12 Javascript
JS实现不规则TAB选项卡效果代码
Sep 16 Javascript
BootStrap智能表单实战系列(十一)级联下拉的支持
Jun 13 Javascript
jQuery EasyUI datagrid在翻页以后仍能记录被选中行的实现代码
Aug 15 Javascript
jQuery中show与hide方法用法示例
Sep 16 Javascript
详解Weex基于Vue2.0开发模板搭建
Mar 20 Javascript
微信小程序使用picker实现时间和日期选择框功能【附源码下载】
Dec 11 Javascript
解决vue单页面应用进入页面加载所有 js 的问题
Aug 12 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更新购物车数量(表单部分/PHP处理部分)
2013/05/03 PHP
Linux Apache PHP Oracle 安装配置(具体操作步骤)
2013/06/17 PHP
PHP微信H5支付开发实例
2018/07/25 PHP
php对象工厂类完整示例
2018/08/09 PHP
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
2010/12/03 Javascript
字符串的replace方法应用浅析
2011/12/06 Javascript
关于img的href和src取变量及赋值的方法
2014/04/28 Javascript
JS实现超精简的链接列表在固定区域内滚动效果代码
2015/11/04 Javascript
详解Angular2表单-模板驱动的表单(Template-Driven Forms)
2017/08/04 Javascript
利用three.js画一个3D立体的正方体示例代码
2017/11/19 Javascript
vue单页应用的内存泄露定位和修复问题小结
2019/08/02 Javascript
[01:09]2014DOTA2国际邀请赛 TI4西雅图DOTA2 中国美女coser加油助威
2014/07/20 DOTA
python查询mysql中文乱码问题
2014/11/09 Python
Python基于scrapy采集数据时使用代理服务器的方法
2015/04/16 Python
Python中pow()和math.pow()函数用法示例
2018/02/11 Python
django中模板的html自动转意方法
2018/05/27 Python
详解python中递归函数
2019/04/16 Python
Django如何开发简单的查询接口详解
2019/05/17 Python
python实现植物大战僵尸游戏实例代码
2019/06/10 Python
python利用dlib获取人脸的68个landmark
2019/11/27 Python
python str字符串转uuid实例
2020/03/03 Python
基于Python爬取fofa网页端数据过程解析
2020/07/13 Python
anaconda3安装及jupyter环境配置全教程
2020/08/24 Python
用Python匹配HTML tag的时候,<.*>和<.*?>有什么区别
2012/11/04 面试题
什么时候需要进行强制类型转换
2016/09/03 面试题
生物化工专业个人自荐信
2013/09/26 职场文书
小学新学期教师寄语
2014/01/18 职场文书
财务主管岗位职责
2014/02/28 职场文书
公司财务流程之主管工作流程
2014/03/03 职场文书
技术负责人任命书
2014/06/05 职场文书
2014年度工作总结报告
2014/12/15 职场文书
台风停课通知
2015/04/24 职场文书
基石观后感
2015/06/12 职场文书
MongoDB安装使用并实现Python操作数据库
2021/06/28 MongoDB
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
2022/03/16 Redis
微软发布Windows 11今年最大更新22H2(附 ISO 镜像官方下载)
2022/09/23 数码科技