backtop.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <template>
  2. <div :class="['nut-backtop', { show: backTop }]" :style="styles" @click="goto">
  3. <slot>
  4. <div class="nut-backtop-main"></div>
  5. </slot>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. name: 'nut-backtop',
  11. props: {
  12. distance: {
  13. type: Number,
  14. default: 200,
  15. },
  16. bottom: {
  17. type: Number,
  18. default: 20,
  19. },
  20. right: {
  21. type: Number,
  22. default: 10,
  23. },
  24. duration: {
  25. type: Number,
  26. default: 1000,
  27. },
  28. zIndex: {
  29. type: Number,
  30. default: 1111,
  31. },
  32. },
  33. data() {
  34. return {
  35. backTop: false,
  36. };
  37. },
  38. mounted() {
  39. window.addEventListener('scroll', this.handleScroll, false);
  40. window.addEventListener('resize', this.handleScroll, false);
  41. },
  42. beforeDestroy() {
  43. window.removeEventListener('scroll', this.handleScroll, false);
  44. window.removeEventListener('resize', this.handleScroll, false);
  45. },
  46. computed: {
  47. styles() {
  48. return {
  49. bottom: `${this.bottom}px`,
  50. right: `${this.right}px`,
  51. 'z-index': this.zIndex,
  52. };
  53. },
  54. },
  55. methods: {
  56. handleScroll() {
  57. this.backTop = window.pageYOffset >= this.distance;
  58. },
  59. goto() {
  60. const sTop = document.documentElement.scrollTop || document.body.scrollTop;
  61. this.scrollTop(window, sTop, 0, this.duration);
  62. this.$emit('click');
  63. },
  64. scrollTop(el, from = 0, to, duration = 500, endCallback) {
  65. this.el = el;
  66. let lastTime = 0;
  67. let vendors = ['webkit', 'moz'];
  68. for (let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  69. window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
  70. window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
  71. }
  72. if (!window.requestAnimationFrame) {
  73. window.requestAnimationFrame = function (callback, element) {
  74. let currTime = new Date().getTime();
  75. let timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
  76. let id = window.setTimeout(function () {
  77. callback(currTime + timeToCall);
  78. }, timeToCall);
  79. lastTime = currTime + timeToCall;
  80. return id;
  81. };
  82. }
  83. if (!window.cancelAnimationFrame) {
  84. window.cancelAnimationFrame = function (id) {
  85. clearTimeout(id);
  86. };
  87. }
  88. const difference = Math.abs(from - to);
  89. const step = Math.ceil((difference / duration) * 50);
  90. this.scroll(from, to, step, endCallback);
  91. },
  92. scroll(start, end, step, endCallback) {
  93. if (start === end) {
  94. endCallback && endCallback();
  95. return;
  96. }
  97. let d = start + step > end ? end : start + step;
  98. if (start > end) {
  99. d = start - step < end ? end : start - step;
  100. }
  101. if (this.el === window) {
  102. window.scrollTo(d, d);
  103. } else {
  104. this.el.scrollTop = d;
  105. }
  106. window.requestAnimationFrame(() => this.scroll(d, end, step));
  107. },
  108. },
  109. };
  110. </script>