Nuxt/packages/app/template/components/nuxt-loading.vue

178 lines
3.9 KiB
Vue

<script>
export default {
name: 'nuxt-loading',
data() {
return {
percent: 0,
show: false,
canSucceed: true,
reversed: false,
skipTimerCount: 0,
rtl: <%= loading.rtl || false %>,
throttle: <%= loading.throttle || 200 %>,
duration: <%= loading.duration || 3000 %>,
continuous: <%= loading.continuous || false %>
}
},
computed: {
left() {
if (!this.continuous && !this.rtl) {
return false
}
return this.rtl
? (this.reversed ? '0px' : 'auto')
: (!this.reversed ? '0px' : 'auto')
}
},
beforeDestroy() {
this.clear()
},
methods: {
clear() {
clearInterval(this._timer)
clearTimeout(this._throttle)
this._timer = null
},
start() {
this.clear()
this.percent = 0
this.reversed = false
this.skipTimerCount = 0
this.canSucceed = true
if (this.throttle) {
this._throttle = setTimeout(() => this.startTimer(), this.throttle)
} else {
this.startTimer()
}
return this
},
set(num) {
this.show = true
this.canSucceed = true
this.percent = Math.min(100, Math.max(0, Math.floor(num)))
return this
},
get() {
return this.percent
},
increase(num) {
this.percent = Math.min(100, Math.floor(this.percent + num))
return this
},
decrease(num) {
this.percent = Math.max(0, Math.floor(this.percent - num))
return this
},
pause() {
clearInterval(this._timer)
return this
},
resume() {
this.startTimer()
return this
},
finish() {
this.percent = this.reversed ? 0 : 100
this.hide()
return this
},
hide() {
this.clear()
setTimeout(() => {
this.show = false
this.$nextTick(() => {
this.percent = 0
this.reversed = false
})
}, 500)
return this
},
fail() {
this.canSucceed = false
return this
},
startTimer() {
if (!this.show) {
this.show = true
}
if (typeof this._cut === 'undefined') {
this._cut = 10000 / Math.floor(this.duration)
}
this._timer = setInterval(() => {
/**
* When reversing direction skip one timers
* so 0, 100 are displayed for two iterations
* also disable css width transitioning
* which otherwise interferes and shows
* a jojo effect
*/
if (this.skipTimerCount > 0) {
this.skipTimerCount--
return
}
if (this.reversed) {
this.decrease(this._cut)
} else {
this.increase(this._cut)
}
if (this.continuous) {
if (this.percent >= 100) {
this.skipTimerCount = 1
this.reversed = !this.reversed
} else if (this.percent <= 0) {
this.skipTimerCount = 1
this.reversed = !this.reversed
}
}
}, 100)
}
},
render(h) {
let el = h(false)
if (this.show) {
el = h('div', {
staticClass: 'nuxt-progress',
class: {
'nuxt-progress-notransition': this.skipTimerCount > 0,
'nuxt-progress-failed': !this.canSucceed
},
style: {
'width': this.percent + '%',
'left': this.left
}
})
}
return el
}
}
</script>
<% if (loading && loading.css) { %>
<style>
.nuxt-progress {
position: fixed;
top: 0px;
left: <%= loading.rtl === true ? 'auto' : '0px' %>;
right: 0px;
height: <%= loading.height %>;
width: 0%;
opacity: 1;
transition: width 0.1s, opacity 0.4s;
background-color: <%= loading.color %>;
z-index: 999999;
}
.nuxt-progress.nuxt-progress-notransition {
transition: none;
}
.nuxt-progress-failed {
background-color: <%= loading.failedColor %>;
}
</style><% } %>