1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- import Vue from 'vue'
- const requestIdleCallback = window.requestIdleCallback ||
- function (cb) {
- const start = Date.now()
- return setTimeout(function () {
- cb({
- didTimeout: false,
- timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
- })
- }, 1)
- }
- const cancelIdleCallback = window.cancelIdleCallback || function (id) {
- clearTimeout(id)
- }
- const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => {
- entries.forEach(({ intersectionRatio, target: link }) => {
- if (intersectionRatio <= 0 || !link.__prefetch) {
- return
- }
- link.__prefetch()
- })
- })
- export default {
- name: 'NuxtLink',
- extends: Vue.component('RouterLink'),
- props: {
- prefetch: {
- type: Boolean,
- default: true
- },
- noPrefetch: {
- type: Boolean,
- default: false
- }
- },
- mounted () {
- if (this.prefetch && !this.noPrefetch) {
- this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
- }
- },
- beforeDestroy () {
- cancelIdleCallback(this.handleId)
- if (this.__observed) {
- observer.unobserve(this.$el)
- delete this.$el.__prefetch
- }
- },
- methods: {
- observe () {
- // If no IntersectionObserver, avoid prefetching
- if (!observer) {
- return
- }
- // Add to observer
- if (this.shouldPrefetch()) {
- this.$el.__prefetch = this.prefetchLink.bind(this)
- observer.observe(this.$el)
- this.__observed = true
- }
- },
- shouldPrefetch () {
- return this.getPrefetchComponents().length > 0
- },
- canPrefetch () {
- const conn = navigator.connection
- const hasBadConnection = this.$nuxt.isOffline || (conn && ((conn.effectiveType || '').includes('2g') || conn.saveData))
- return !hasBadConnection
- },
- getPrefetchComponents () {
- const ref = this.$router.resolve(this.to, this.$route, this.append)
- const Components = ref.resolved.matched.map(r => r.components.default)
- return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
- },
- prefetchLink () {
- 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
- }
- }
- }
- }
|