import VueRouter from 'vue-router' import { isPage } from 'uni-helpers/index' import { createAppMixin } from './app' import { createPageMixin } from './page' import { lifecycleMixin } from './lifecycle' import { initPolyfill } from './polyfill' import { getTabBarScrollPosition } from './app/router-guard' import { uniIdMixin } from 'uni-shared' function getMinId (routes) { let minId = 0 routes.forEach(route => { if (route.meta.id) { minId++ } }) return minId } function getHash () { const href = window.location.href const index = href.indexOf('#') return index === -1 ? '' : decodeURI(href.slice(index + 1)) } function getLocation (base = '/') { let path = decodeURI(window.location.pathname) const search = window.location.search const hash = window.location.hash // 检查和纠正 path if (base[base.length - 1] === '/' && path === base.substring(0, base.length - 1)) { path = base window.history.replaceState({}, '', base + search + hash) } if (base && path.indexOf(base) === 0) { path = path.slice(base.length) } return (path || '/') + search + hash } /** * Service 层 Vue 插件 * 1.init keepAliveInclude? * 2.init router * 3.init entryRoute * 4.hack vue _init (app) * 5.use router */ export default { install (Vue, { routes } = {}) { if ( __PLATFORM__ === 'h5' && Vue.config.devtools && typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase().indexOf('hbuilderx') !== -1 ) { // HBuilderX 内置浏览器禁用 devtools 提示 Vue.config.devtools = false } initPolyfill(Vue) lifecycleMixin(Vue) uniIdMixin(Vue) /* eslint-disable no-undef */ if (typeof __UNI_ROUTER_BASE__ !== 'undefined') { __uniConfig.router.base = __UNI_ROUTER_BASE__ } const minId = getMinId(routes) const router = new VueRouter({ id: minId, mode: __uniConfig.router.mode, base: __uniConfig.router.base, routes, scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { if ( to && from && to.meta.isTabBar && from.meta.isTabBar ) { // tabbar 跳 tabbar const position = getTabBarScrollPosition(to.params.__id__) if (position) { return position } } return { x: 0, y: 0 } } } }) const keepAliveInclude = [] // 需跨平台,根据用户配置 hash 或 history 来调用 const entryRoute = router.match(__uniConfig.router.mode === 'history' ? getLocation(__uniConfig.router.base) : getHash()) if (entryRoute.meta.name) { if (entryRoute.meta.id) { keepAliveInclude.push(entryRoute.meta.name + '-' + entryRoute.meta.id) } else { keepAliveInclude.push(entryRoute.meta.name + '-' + (minId + 1)) } } /* eslint-disable no-undef */ if (__PLATFORM__ === 'h5') { if (entryRoute.meta && entryRoute.meta.name) { document.body.className = 'uni-body ' + entryRoute.meta.name if (entryRoute.meta.isNVue) { const nvueDirKey = 'nvue-dir-' + __uniConfig.nvue['flex-direction'] document.body.setAttribute('nvue', '') document.body.setAttribute(nvueDirKey, '') } } } Vue.mixin({ beforeCreate () { const options = this.$options if (options.mpType === 'app') { options.data = function () { return { keepAliveInclude } } const appMixin = createAppMixin(Vue, routes, entryRoute) // mixin app hooks Object.keys(appMixin).forEach(hook => { options[hook] = options[hook] ? [].concat(appMixin[hook], options[hook]) : [ appMixin[hook] ] }) // router options.router = router // onError if (!Array.isArray(options.onError) || options.onError.length === 0) { options.onError = [function (err) { console.error(err) }] } } else if (isPage(this)) { const pageMixin = createPageMixin() // mixin page hooks Object.keys(pageMixin).forEach(hook => { if (options.mpOptions) { // 小程序适配出来的 vue 组件(保证先调用小程序适配里的 created,再触发 onLoad) options[hook] = options[hook] ? [].concat(options[hook], pageMixin[hook]) : [ pageMixin[hook] ] } else { options[hook] = options[hook] ? [].concat(pageMixin[hook], options[hook]) : [ pageMixin[hook] ] } }) } else { if (this.$parent && this.$parent.__page__) { this.__page__ = this.$parent.__page__ } } } }) Object.defineProperty(Vue.prototype, '$page', { get () { return this.__page__ } }) Vue.prototype.createSelectorQuery = function createSelectorQuery () { return uni.createSelectorQuery().in(this) } Vue.prototype.createIntersectionObserver = function createIntersectionObserver (args) { return uni.createIntersectionObserver(this, args) } Vue.prototype.createMediaQueryObserver = function createMediaQueryObserver (args) { return uni.createMediaQueryObserver(this, args) } Vue.use(VueRouter) } }