视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue实现一个返回顶部backToTop组件
2020-11-27 22:34:16 责编:小采
文档


最近在学习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,也就是十来分钟的事情,

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

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

下载本文
显示全文
专题