Vue实现一个返回顶部backToTop组件
程序员文章站
2022-03-20 23:08:27
最近在学习vue。自己就在研究怎么用vue实现一个组件的封装,今日就算留个笔记
前言
返回顶部这个功能用jq实现,好容易实现,一个animate配合scrollto...
最近在学习vue。自己就在研究怎么用vue实现一个组件的封装,今日就算留个笔记
前言
返回顶部这个功能用jq实现,好容易实现,一个animate配合scrollto就搞定了
今天我们来试试vue封装一个原生js实现的返回顶部;
写起来够呛,借助github,看了别人的gist,稍微封装了下;
当然不是用scrollto直接调位那种,没有过渡效果怎么说得过去!!还是捣鼓出来了.
废话不多说,看效果图…
效果图
实现思路
- 过渡用的是requestanimationframe,这货只支持ie10+,所以必须做兼容
- 滚动视图是window.pageyoffset,这货支持ie9+;
- 为了让可控性更强,图标采用iconfont,具体瞅代码
你能学到什么?
- 学到一些页面计算相关的东东
- 动画api的一些知识
- vue封装组件相关知识和生命周期和事件监听销毁相关知识的运用
实现功能
- 视图默认在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>
总结
从心血来潮到折腾出来,为了兼顾兼容性和拓展性,好像几个小时了.
不过实现了.你再搬到其他语言,类似ng4,也就是十来分钟的事情,
思路会了,实现更多的是写法而已,至于性能优化,可以一边写一边考虑,也可以实现后有空再优化.
希望对大家的学习有所帮助,也希望大家多多支持。