Nuxt/packages/vue-app/template/components/nuxt-link.client.js

108 lines
3.1 KiB
JavaScript
Raw Normal View History

import Vue from 'vue'
const requestIdleCallback = window.requestIdleCallback ||
function (cb) {
const start = Date.now()
return setTimeout(function () {
cb({
didTimeout: false,
2019-09-10 09:51:14 +00:00
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
})
}, 1)
}
const cancelIdleCallback = window.cancelIdleCallback || function (id) {
clearTimeout(id)
}
2019-01-06 07:56:59 +00:00
const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => {
entries.forEach(({ intersectionRatio, target: link }) => {
if (intersectionRatio <= 0) {
return
}
link.__prefetch()
})
})
2019-01-06 07:56:59 +00:00
<%= isTest ? '// @vue/component' : '' %>
export default {
name: 'NuxtLink',
2019-01-06 07:56:59 +00:00
extends: Vue.component('RouterLink'),
props: {
noPrefetch: {
type: Boolean,
default: false
}<% if (router.linkPrefetchedClass) { %>,
prefetchedClass: {
type: String,
default: '<%= router.linkPrefetchedClass %>'
}<% } %>
},
2019-09-10 09:51:14 +00:00
mounted () {
if (!this.noPrefetch) {
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
}
},
2019-09-10 09:51:14 +00:00
beforeDestroy () {
cancelIdleCallback(this.handleId)
if (this.__observed) {
observer.unobserve(this.$el)
delete this.$el.__prefetch
}
},
methods: {
2019-09-10 09:51:14 +00:00
observe () {
// If no IntersectionObserver, avoid prefetching
if (!observer) {
return
}
// Add to observer
if (this.shouldPrefetch()) {
this.$el.__prefetch = this.prefetch.bind(this)
observer.observe(this.$el)
this.__observed = true
}<% if (router.linkPrefetchedClass) { %> else {
this.addPrefetchedClass()
}<% } %>
},
2019-09-10 09:51:14 +00:00
shouldPrefetch () {
return this.getPrefetchComponents().length > 0
},
2019-09-10 09:51:14 +00:00
canPrefetch () {
const conn = navigator.connection
const hasBadConnection = this.<%= globals.nuxt %>.isOffline || (conn && ((conn.effectiveType || '').includes('2g') || conn.saveData))
return !hasBadConnection
},
2019-09-10 09:51:14 +00:00
getPrefetchComponents () {
const ref = this.$router.resolve(this.to, this.$route, this.append)
2019-01-06 07:56:59 +00:00
const Components = ref.resolved.matched.map(r => r.components.default)
2019-01-06 07:56:59 +00:00
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
},
2019-09-10 09:51:14 +00:00
prefetch () {
if (!this.canPrefetch()) {
return
}
// Stop observing this link (in case of internet connection changes)
observer.unobserve(this.$el)
const Components = this.getPrefetchComponents()
for (const Component of Components) {
const componentOrPromise = Component()
if (componentOrPromise instanceof Promise) {
componentOrPromise.catch(() => {})
}
Component.__prefetched = true
}<% if (router.linkPrefetchedClass) { %>
this.addPrefetchedClass()<% } %>
}<% if (router.linkPrefetchedClass) { %>,
2019-09-10 09:51:14 +00:00
addPrefetchedClass () {
if (this.prefetchedClass !== 'false') {
2019-01-30 11:34:33 +00:00
this.$el.className = (this.$el.className + ' ' + this.prefetchedClass).trim()
}
}<% } %>
}
}