UNPKG

@ray-js/router-mp

Version:

Ray Core

210 lines (199 loc) 5.85 kB
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import { navigateBack, navigateTo, reLaunch, redirectTo, switchTab } from '@ray-js/api'; import { url } from '@ray-js/library'; import { RouterScheduler, currentPage } from './RouterScheduler'; function pathRelative(fromPath, toPath) { const from = fromPath.split('/'); const to = toPath.split('/'); let i = 0; // 找到两个路径第一个不同的目录 while (from[i] === to[i]) { i++; } let result = ''; // 在 from 中添加 '..' 直到达到相同的目录 for (let j = i; j < from.length - 1; j++) { result += '../'; } // 在 result 中添加 to 中剩余的目录 for (let j = i; j < to.length; j++) { result += to[j]; if (j < to.length - 1) { result += '/'; } } return result; } export class Router { // 只有作为其他小程序的子包时,才设置urlPrefix urlPrefix = ''; /** * 功能页模式为 functional,使用相对路径模式 * 如果是绝对路径,表示跳转到宿主小程序 * * @private */ mode = 'miniprogram'; // functional /** * setUrlPrefix */ setUrlPrefix(prefix) { this.urlPrefix = prefix; } setMode(mode) { this.mode = mode; } scheduler = (() => new RouterScheduler())(); /** * 标准化路由路径,将 web 标准的地址栏转化到 小程序地址 */ normalizeRoute(params) { let { pathname, query, hash } = url.parse(params.to); const subPackage = params.subpackage; const currentRoute = this.scheduler.getCurrentRoute(); const isRelativePath = pathname.startsWith('.'); if (isRelativePath) { const currentPathname = currentRoute.route; // 如果是相对路径,修正为绝对路径 const absolutePathSegments = (currentPathname + '/' + pathname).split('/'); const normalizedPathSegments = []; for (let i = 0; i < absolutePathSegments.length; i++) { const segment = absolutePathSegments[i]; if (segment === '..') { normalizedPathSegments.pop(); } else if (segment !== '.') { normalizedPathSegments.push(segment); } } pathname = normalizedPathSegments.join('/'); } // 如果是相对路径,修正为绝对路径 const matchedPage = subPackage ? this.scheduler.getMatchedSubPackagePage(pathname, subPackage) : this.scheduler.getMatchedPage(pathname); if (!matchedPage) { console.warn('try match page', { pathname, query, hash }); return Promise.reject('can not find page by path: ' + params.to); } // 作为其他小程序时不能作为tabBar if (this.urlPrefix) { matchedPage.isTabBar = false; } let finalPath = matchedPage.path; // FIXME: tabBar.list里的页面不能有query,也不能有hash if (!matchedPage.isTabBar) { finalPath = url.format({ pathname: matchedPage.path, query: _objectSpread(_objectSpread(_objectSpread({}, query), matchedPage.params), {}, { // 模式匹配得到的参数,如/xxx/:id 可以匹配路径 /xxx/123 得参数id: 123 ____h_a_s_h____: hash.slice(1) // 小程序中不能传递hash参数,用query辅助传递 }) }); } /** * 坑点之一 * 微信小程序: app.json 里的页面配置不能以`/`开头,wx.navigatorTo 却需要 */ if (this.urlPrefix) { finalPath = ('/' + this.urlPrefix + '/' + finalPath).replace(/\/+/g, '/'); } matchedPage.path = finalPath; // 因为可能是功能页模式,必须使用相对路径进行跳转 if (isRelativePath) { // 将路径基于 currentRoute 进行绝对路径转成相对路径 matchedPage.path = pathRelative(currentRoute.path, matchedPage.path); } return Promise.resolve(matchedPage); } /** * 跳转到指定路由 * @param to - routes.config.ts 中配置的路由地址 * @param options * @param options.subpackage - 分包名 * * @example * router.push('/cat', { subpackage: 'packageA' }); */ push(to, options) { const subpackage = options === null || options === void 0 ? void 0 : options.subpackage; this.normalizeRoute({ to, subpackage }).then(route => { const path = route.path; if (route.isTabBar) { switchTab({ url: path }); } else { navigateTo({ url: path }); } }); } /** * 替换当前页到指定路由 * @param to - routes.config.ts 中配置的路由地址 * @param options * @param options.subpackage - 分包名 * * @example * router.replace('/cat', { subpackage: 'packageA' }); */ replace(to, options) { const subpackage = options === null || options === void 0 ? void 0 : options.subpackage; this.normalizeRoute({ to, subpackage }).then(route => { if (route.isTabBar) { switchTab({ url: route.path }); } else { redirectTo({ url: route.path }); } }); } reload() { const page = currentPage(); reLaunch({ url: url.params(page.route, page.options) }); } go() { throw new Error('Method not implemented.'); } back() { navigateBack({ delta: 1 }); } // 获取宿主环境上的 href ,小程序端需要通过 path 进行转换 get href() { const page = currentPage(); const reg = RegExp('^' + this.urlPrefix + '/'); const r = page.route.replace(reg, ''); const path = url.params(`/${r}`, page.options); const { pathname, query, hash } = url.parse(path); return this.scheduler.getHrefByPath({ path: pathname, query, hash }); } } export const router = new Router();