您的位置:首页 > Web前端 > Vue.js

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

2017-07-25 14:45 1111 查看

最近在学习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); 返回到视图的point,也就是滚动到哪里
  5. 过渡时间(ms级别)
  6. 一堆过渡效果,字符串格式,其实就是滚动的计算函数..
  7. 当然少不了默认参数了,除了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>

    总结

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

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

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

    希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    您可能感兴趣的文章:

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签:  Vue 返回顶部