import getRealRoute from '../../get-real-route' function encodeQueryString (url) { if (typeof url !== 'string') { return url } const index = url.indexOf('?') if (index === -1) { return url } const query = url.substr(index + 1).trim().replace(/^(\?|#|&)/, '') if (!query) { return url } url = url.substr(0, index) const params = [] query.split('&').forEach(param => { const parts = param.replace(/\+/g, ' ').split('=') const key = parts.shift() const val = parts.length > 0 ? parts.join('=') : '' params.push(key + '=' + encodeURIComponent(val)) }) return params.length ? url + '?' + params.join('&') : url } function createValidator (type) { return function validator (url, params) { // 格式化为绝对路径路由 url = getRealRoute(url) const pagePath = url.split('?')[0] // 匹配路由是否存在 const routeOptions = __uniRoutes.find(({ path, alias }) => path === pagePath || alias === pagePath) if (!routeOptions) { return 'page `' + url + '` is not found' } // 检测不同类型跳转 if (type === 'navigateTo' || type === 'redirectTo') { if (routeOptions.meta.isTabBar) { return `can not ${type} a tabbar page` } } else if (type === 'switchTab') { if (!routeOptions.meta.isTabBar) { return 'can not switch to no-tabBar page' } } // tabBar不允许传递参数 if (routeOptions.meta.isTabBar) { url = pagePath } // 首页自动格式化为`/` if (routeOptions.meta.isEntry) { url = url.replace(routeOptions.alias, '/') } // 参数格式化 params.url = encodeQueryString(url) } } function createProtocol (type, extras = {}) { return Object.assign({ url: { type: String, required: true, validator: createValidator(type) } }, extras) } function createAnimationProtocol (animationTypes) { return { animationType: { type: String, validator (type) { if (type && animationTypes.indexOf(type) === -1) { return '`' + type + '` is not supported for `animationType` (supported values are: `' + animationTypes.join( '`|`') + '`)' } } }, animationDuration: { type: Number } } } export const redirectTo = createProtocol('redirectTo') export const reLaunch = createProtocol('reLaunch') export const navigateTo = createProtocol('navigateTo', createAnimationProtocol( [ 'slide-in-right', 'slide-in-left', 'slide-in-top', 'slide-in-bottom', 'fade-in', 'zoom-out', 'zoom-fade-out', 'pop-in', 'none' ] )) export const switchTab = createProtocol('switchTab') export const navigateBack = Object.assign({ delta: { type: Number, validator (delta, params) { delta = parseInt(delta) || 1 params.delta = Math.min(getCurrentPages().length - 1, delta) } } }, createAnimationProtocol( [ 'slide-out-right', 'slide-out-left', 'slide-out-top', 'slide-out-bottom', 'fade-out', 'zoom-in', 'zoom-fade-in', 'pop-out', 'none' ] ))