App.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import Vue from 'vue'
  2. import { decode, parsePath, withoutBase, withoutTrailingSlash, normalizeURL } from 'ufo'
  3. import { getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError, urlJoin, sanitizeComponent } from './utils'
  4. import NuxtError from './components/nuxt-error.vue'
  5. import NuxtLoading from './components/nuxt-loading.vue'
  6. import NuxtBuildIndicator from './components/nuxt-build-indicator'
  7. import '..\\assets\\css\\normalize.css'
  8. import '..\\assets\\css\\base.scss'
  9. import _6f6c098b from '..\\layouts\\default.vue'
  10. const layouts = { "_default": sanitizeComponent(_6f6c098b) }
  11. export default {
  12. render (h, props) {
  13. const loadingEl = h('NuxtLoading', { ref: 'loading' })
  14. const layoutEl = h(this.layout || 'nuxt')
  15. const templateEl = h('div', {
  16. domProps: {
  17. id: '__layout'
  18. },
  19. key: this.layoutName
  20. }, [layoutEl])
  21. const transitionEl = h('transition', {
  22. props: {
  23. name: 'layout',
  24. mode: 'out-in'
  25. },
  26. on: {
  27. beforeEnter (el) {
  28. // Ensure to trigger scroll event after calling scrollBehavior
  29. window.$nuxt.$nextTick(() => {
  30. window.$nuxt.$emit('triggerScroll')
  31. })
  32. }
  33. }
  34. }, [templateEl])
  35. return h('div', {
  36. domProps: {
  37. id: '__nuxt'
  38. }
  39. }, [
  40. loadingEl,
  41. h(NuxtBuildIndicator),
  42. transitionEl
  43. ])
  44. },
  45. data: () => ({
  46. isOnline: true,
  47. layout: null,
  48. layoutName: '',
  49. nbFetching: 0
  50. }),
  51. beforeCreate () {
  52. Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
  53. },
  54. created () {
  55. // Add this.$nuxt in child instances
  56. this.$root.$options.$nuxt = this
  57. if (process.client) {
  58. // add to window so we can listen when ready
  59. window.$nuxt = this
  60. this.refreshOnlineStatus()
  61. // Setup the listeners
  62. window.addEventListener('online', this.refreshOnlineStatus)
  63. window.addEventListener('offline', this.refreshOnlineStatus)
  64. }
  65. // Add $nuxt.error()
  66. this.error = this.nuxt.error
  67. // Add $nuxt.context
  68. this.context = this.$options.context
  69. },
  70. async mounted () {
  71. this.$loading = this.$refs.loading
  72. },
  73. watch: {
  74. 'nuxt.err': 'errorChanged'
  75. },
  76. computed: {
  77. isOffline () {
  78. return !this.isOnline
  79. },
  80. isFetching () {
  81. return this.nbFetching > 0
  82. },
  83. isPreview () {
  84. return Boolean(this.$options.previewData)
  85. },
  86. },
  87. methods: {
  88. refreshOnlineStatus () {
  89. if (process.client) {
  90. if (typeof window.navigator.onLine === 'undefined') {
  91. // If the browser doesn't support connection status reports
  92. // assume that we are online because most apps' only react
  93. // when they now that the connection has been interrupted
  94. this.isOnline = true
  95. } else {
  96. this.isOnline = window.navigator.onLine
  97. }
  98. }
  99. },
  100. async refresh () {
  101. const pages = getMatchedComponentsInstances(this.$route)
  102. if (!pages.length) {
  103. return
  104. }
  105. this.$loading.start()
  106. const promises = pages.map((page) => {
  107. const p = []
  108. // Old fetch
  109. if (page.$options.fetch && page.$options.fetch.length) {
  110. p.push(promisify(page.$options.fetch, this.context))
  111. }
  112. if (page.$fetch) {
  113. p.push(page.$fetch())
  114. } else {
  115. // Get all component instance to call $fetch
  116. for (const component of getChildrenComponentInstancesUsingFetch(page.$vnode.componentInstance)) {
  117. p.push(component.$fetch())
  118. }
  119. }
  120. if (page.$options.asyncData) {
  121. p.push(
  122. promisify(page.$options.asyncData, this.context)
  123. .then((newData) => {
  124. for (const key in newData) {
  125. Vue.set(page.$data, key, newData[key])
  126. }
  127. })
  128. )
  129. }
  130. return Promise.all(p)
  131. })
  132. try {
  133. await Promise.all(promises)
  134. } catch (error) {
  135. this.$loading.fail(error)
  136. globalHandleError(error)
  137. this.error(error)
  138. }
  139. this.$loading.finish()
  140. },
  141. errorChanged () {
  142. if (this.nuxt.err) {
  143. if (this.$loading) {
  144. if (this.$loading.fail) {
  145. this.$loading.fail(this.nuxt.err)
  146. }
  147. if (this.$loading.finish) {
  148. this.$loading.finish()
  149. }
  150. }
  151. let errorLayout = (NuxtError.options || NuxtError).layout;
  152. if (typeof errorLayout === 'function') {
  153. errorLayout = errorLayout(this.context)
  154. }
  155. this.setLayout(errorLayout)
  156. }
  157. },
  158. setLayout (layout) {
  159. if(layout && typeof layout !== 'string') {
  160. throw new Error('[nuxt] Avoid using non-string value as layout property.')
  161. }
  162. if (!layout || !layouts['_' + layout]) {
  163. layout = 'default'
  164. }
  165. this.layoutName = layout
  166. this.layout = layouts['_' + layout]
  167. return this.layout
  168. },
  169. loadLayout (layout) {
  170. if (!layout || !layouts['_' + layout]) {
  171. layout = 'default'
  172. }
  173. return Promise.resolve(layouts['_' + layout])
  174. },
  175. },
  176. components: {
  177. NuxtLoading
  178. }
  179. }