nuxt-loading.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <script>
  2. export default {
  3. name: 'NuxtLoading',
  4. data () {
  5. return {
  6. percent: 0,
  7. show: false,
  8. canSucceed: true,
  9. reversed: false,
  10. skipTimerCount: 0,
  11. rtl: false,
  12. throttle: 200,
  13. duration: 5000,
  14. continuous: false
  15. }
  16. },
  17. computed: {
  18. left () {
  19. if (!this.continuous && !this.rtl) {
  20. return false
  21. }
  22. return this.rtl
  23. ? (this.reversed ? '0px' : 'auto')
  24. : (!this.reversed ? '0px' : 'auto')
  25. }
  26. },
  27. beforeDestroy () {
  28. this.clear()
  29. },
  30. methods: {
  31. clear () {
  32. clearInterval(this._timer)
  33. clearTimeout(this._throttle)
  34. this._timer = null
  35. },
  36. start () {
  37. this.clear()
  38. this.percent = 0
  39. this.reversed = false
  40. this.skipTimerCount = 0
  41. this.canSucceed = true
  42. if (this.throttle) {
  43. this._throttle = setTimeout(() => this.startTimer(), this.throttle)
  44. } else {
  45. this.startTimer()
  46. }
  47. return this
  48. },
  49. set (num) {
  50. this.show = true
  51. this.canSucceed = true
  52. this.percent = Math.min(100, Math.max(0, Math.floor(num)))
  53. return this
  54. },
  55. get () {
  56. return this.percent
  57. },
  58. increase (num) {
  59. this.percent = Math.min(100, Math.floor(this.percent + num))
  60. return this
  61. },
  62. decrease (num) {
  63. this.percent = Math.max(0, Math.floor(this.percent - num))
  64. return this
  65. },
  66. pause () {
  67. clearInterval(this._timer)
  68. return this
  69. },
  70. resume () {
  71. this.startTimer()
  72. return this
  73. },
  74. finish () {
  75. this.percent = this.reversed ? 0 : 100
  76. this.hide()
  77. return this
  78. },
  79. hide () {
  80. this.clear()
  81. setTimeout(() => {
  82. this.show = false
  83. this.$nextTick(() => {
  84. this.percent = 0
  85. this.reversed = false
  86. })
  87. }, 500)
  88. return this
  89. },
  90. fail (error) {
  91. this.canSucceed = false
  92. return this
  93. },
  94. startTimer () {
  95. if (!this.show) {
  96. this.show = true
  97. }
  98. if (typeof this._cut === 'undefined') {
  99. this._cut = 10000 / Math.floor(this.duration)
  100. }
  101. this._timer = setInterval(() => {
  102. /**
  103. * When reversing direction skip one timers
  104. * so 0, 100 are displayed for two iterations
  105. * also disable css width transitioning
  106. * which otherwise interferes and shows
  107. * a jojo effect
  108. */
  109. if (this.skipTimerCount > 0) {
  110. this.skipTimerCount--
  111. return
  112. }
  113. if (this.reversed) {
  114. this.decrease(this._cut)
  115. } else {
  116. this.increase(this._cut)
  117. }
  118. if (this.continuous) {
  119. if (this.percent >= 100) {
  120. this.skipTimerCount = 1
  121. this.reversed = !this.reversed
  122. } else if (this.percent <= 0) {
  123. this.skipTimerCount = 1
  124. this.reversed = !this.reversed
  125. }
  126. }
  127. }, 100)
  128. }
  129. },
  130. render (h) {
  131. let el = h(false)
  132. if (this.show) {
  133. el = h('div', {
  134. staticClass: 'nuxt-progress',
  135. class: {
  136. 'nuxt-progress-notransition': this.skipTimerCount > 0,
  137. 'nuxt-progress-failed': !this.canSucceed
  138. },
  139. style: {
  140. width: this.percent + '%',
  141. left: this.left
  142. }
  143. })
  144. }
  145. return el
  146. }
  147. }
  148. </script>
  149. <style>
  150. .nuxt-progress {
  151. position: fixed;
  152. top: 0px;
  153. left: 0px;
  154. right: 0px;
  155. height: 2px;
  156. width: 0%;
  157. opacity: 1;
  158. transition: width 0.1s, opacity 0.4s;
  159. background-color: black;
  160. z-index: 999999;
  161. }
  162. .nuxt-progress.nuxt-progress-notransition {
  163. transition: none;
  164. }
  165. .nuxt-progress-failed {
  166. background-color: red;
  167. }
  168. </style>