main.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <template>
  2. <transition name="el-fade-in">
  3. <div
  4. v-if="visible"
  5. @click.stop="handleClick"
  6. :style="{
  7. 'right': styleRight,
  8. 'bottom': styleBottom
  9. }"
  10. class="el-backtop">
  11. <slot>
  12. <el-icon name="caret-top"></el-icon>
  13. </slot>
  14. </div>
  15. </transition>
  16. </template>
  17. <script>
  18. import throttle from 'throttle-debounce/throttle';
  19. const cubic = value => Math.pow(value, 3);
  20. const easeInOutCubic = value => value < 0.5
  21. ? cubic(value * 2) / 2
  22. : 1 - cubic((1 - value) * 2) / 2;
  23. export default {
  24. name: 'ElBacktop',
  25. props: {
  26. visibilityHeight: {
  27. type: Number,
  28. default: 200
  29. },
  30. target: [String],
  31. right: {
  32. type: Number,
  33. default: 40
  34. },
  35. bottom: {
  36. type: Number,
  37. default: 40
  38. }
  39. },
  40. data() {
  41. return {
  42. el: null,
  43. container: null,
  44. visible: false
  45. };
  46. },
  47. computed: {
  48. styleBottom() {
  49. return `${this.bottom}px`;
  50. },
  51. styleRight() {
  52. return `${this.right}px`;
  53. }
  54. },
  55. mounted() {
  56. this.init();
  57. this.throttledScrollHandler = throttle(300, this.onScroll);
  58. this.container.addEventListener('scroll', this.throttledScrollHandler);
  59. },
  60. methods: {
  61. init() {
  62. this.container = document;
  63. this.el = document.documentElement;
  64. if (this.target) {
  65. this.el = document.querySelector(this.target);
  66. if (!this.el) {
  67. throw new Error(`target is not existed: ${this.target}`);
  68. }
  69. this.container = this.el;
  70. }
  71. },
  72. onScroll() {
  73. const scrollTop = this.el.scrollTop;
  74. this.visible = scrollTop >= this.visibilityHeight;
  75. },
  76. handleClick(e) {
  77. this.scrollToTop();
  78. this.$emit('click', e);
  79. },
  80. scrollToTop() {
  81. const el = this.el;
  82. const beginTime = Date.now();
  83. const beginValue = el.scrollTop;
  84. const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16));
  85. const frameFunc = () => {
  86. const progress = (Date.now() - beginTime) / 500;
  87. if (progress < 1) {
  88. el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
  89. rAF(frameFunc);
  90. } else {
  91. el.scrollTop = 0;
  92. }
  93. };
  94. rAF(frameFunc);
  95. }
  96. },
  97. beforeDestroy() {
  98. this.container.removeEventListener('scroll', this.throttledScrollHandler);
  99. }
  100. };
  101. </script>