首页 > 编程 > JavaScript > 正文

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

2019-11-19 15:59:31
字体:
来源:转载
供稿:网友

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

前言

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

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

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

废话不多说,看效果图…

效果图

实现思路

  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,也就是十来分钟的事情,

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

希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表