Vue 2.x折腾记 - (6) 写一个不大靠谱的backToTop组件

前言

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

今天咱们来试试vue封装一个原生js实现的返回顶部;css

写起来够呛,借助github,看了别人的gist,稍微封装了下;html

固然不是用scrollTo直接调位那种,没有过渡效果怎么说得过去,仍是捣鼓出来了。vue

效果图

实现思路java

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

你能学到什么?git

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

实现功能github

  • 视图默认在350处显示返回顶部的按钮和图标
  • 提示文字和颜色,在图标上下左右的自定义,字段都限制了格式和默认值
  • 图标颜色和形状,大小的自定义,字段都限制了格式和默认值
  • 过渡动效的自定义,用法:scrollIt(0, 1500, 'easeInOutCubic', callback);
    • 返回到视图的point,也就是滚动到哪里
    • 过渡时间(ms级别)
    • 一堆过渡效果,字符串格式,其实就是滚动的计算函数..
    • 固然少不了默认参数了,除了callback
  • 兼容性是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>


复制代码

总结

有更好的实现方案和思路能够往下面留言,谢谢web

相关文章
相关标签/搜索