UNPKG

@tarojs/router

Version:
1,756 lines • 77.7 kB
import { defineCustomElementTaroTabbar } from '@tarojs/components/dist/components';
import { initTabBarApis } from '@tarojs/taro';
import { __awaiter } from 'tslib';
import { addLeadingSlash, eventCenter, Current, stripBasename, incrementId, createPageConfig, hooks, stringify, getHomePage, getCurrentPage, stripTrailing, requestAnimationFrame as requestAnimationFrame$1, safeExecute } from '@tarojs/runtime';
import { EventChannel } from '@tarojs/shared';
import { createBrowserHistory, createHashHistory, Action, parsePath } from 'history';
export { createBrowserHistory, createHashHistory } from 'history';
import queryString from 'query-string';
import UniversalRouter from 'universal-router';

/**
 * 插入页面动画需要的样式
 */
function loadAnimateStyle(ms = 300) {
    const css = `
body {
  /* 防止 iOS 页面滚动 */
  overflow: hidden;
}
.taro_router > .taro_page {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: #fff;
  transform: translate(100%, 0);
  transition: transform ${ms}ms;
  z-index: 0;
}

.taro_router > .taro_page.taro_tabbar_page,
.taro_router > .taro_page.taro_page_show.taro_page_stationed {
  transform: none;
  transition: none;
}

.taro_router > .taro_page.taro_page_show {
  transform: translate(0, 0);
}
`;
    addStyle(css);
}
/**
 * 插入路由相关样式
 */
function loadRouterStyle(enableTabBar, enableWindowScroll, enhanceAnimation) {
    const css = `
  .taro_router {
    position: relative;
    width: 100%;
    height: 100%;
  }

  .taro_page {
    width: 100%;
    height: 100%;
${enableWindowScroll ? '' : `
    overflow-x: hidden;
    overflow-y: scroll;
    max-height: 100vh;
`}
  }
${enableTabBar ? `
  .taro-tabbar__container {
      height:100%;
  }
  .taro-tabbar__panel {
      height: 100%;
  }
  .taro-tabbar__container > .taro-tabbar__panel {
    overflow: hidden;
  }

  .taro-tabbar__container > .taro-tabbar__panel > .taro_page.taro_tabbar_page {
    max-height: calc(100vh - var(--taro-tabbar-height) - constant(safe-area-inset-bottom));
    max-height: calc(100vh - var(--taro-tabbar-height) - env(safe-area-inset-bottom));
  }

` : ''}
${enhanceAnimation
        ? `.taro_page_shade:has(+.taro_page_stationed),
  .taro_page_shade.taro_tabbar_page,
  .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child):has(+.taro_page_stationed) {
    display: none;
  }` : ` .taro_page_shade,
  .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child) {
    display: none;
  }`}
`;
    addStyle(css);
}
/**
 * 插入导航栏相关的样式
*/
function loadNavigationBarStyle() {
    const css = `
  .taro-navigation-bar-show {
    display: flex;
    background: white;
    position: sticky;
    z-index: 500;
    top: 0;
    padding-bottom: 8px;
    padding-top: calc(env(safe-area-inset-top) + 8px);
    justify-content: center;
    align-items: center;
  }

  .taro-navigation-bar-hide {
    display: none;
  }

  .taro-navigation-bar-title-wrap {
    display: flex;
    height: 24px;
  }

  .taro-navigation-bar-title-wrap > .taro-navigation-bar-loading {
    display: none;
    animation: loading 2s linear infinite;
  }

  .taro-navigation-bar-title-wrap .taro-navigation-bar-loading.taro-navigation-bar-loading-show {
    display: flex;
  }

  .taro-navigation-bar-title-wrap > .taro-navigation-bar-title {
    font-size: 24px;
    height: 24px;
    line-height: 24px;
    max-width: 100px;
    white-space: nowrap;
    overflow: hidden;
    line-height: 24px;
    text-overflow: ellipsis;
  }

  @keyframes loading {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  @keyframes loading {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
    display: none;
  }

  .taro-navigation-bar-no-icon > .taro-navigation-bar-back {
    display: none;
  }

  .taro-navigation-bar-home-icon > .taro-navigation-bar-home {
    display: flex;
    left: 8px;
    position: absolute;
    width: 24px;
    height: 24px;
  }

  .taro-navigation-bar-back-icon > .taro-navigation-bar-back {
    display: flex;
    left: 8px;
    position: absolute;
    width: 24px;
    height: 24px;
  }
`;
    addStyle(css);
}
function addStyle(css) {
    if (!css)
        return;
    const style = document.createElement('style');
    style.innerHTML = css;
    document.getElementsByTagName('head')[0].appendChild(style);
}

const home_svg_str = `
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M23.8899 12.2737C23.8232 12.3584 23.7237 12.3997 23.6198 12.3974H20.7994V23.5996C20.7994 23.8194 20.6213 24 20.4001 24H14.7994C14.5791 24 14.4002 23.8194 14.4002 23.5996V15.6H9.59963V23.5996C9.59963 23.8194 9.42075 24 9.20033 24H3.59968C3.48981 24 3.38964 23.954 3.31764 23.8811C3.24495 23.8091 3.2004 23.7087 3.2004 23.5996V12.3975H0.398546V12.3967C0.296893 12.396 0.194446 12.3544 0.11579 12.2738C-0.0371146 12.114 -0.0400714 11.864 0.11579 11.7076L11.7201 0.117284C11.8767 -0.0390948 12.1298 -0.0390948 12.2863 0.117284L23.8899 11.7076C24.0465 11.864 24.0265 12.0995 23.8899 12.2737ZM12.0029 0.964625L1.37086 11.5854L3.59968 11.5839V11.5999C3.65537 11.5999 3.70804 11.611 3.75557 11.6307C3.89952 11.692 4.00046 11.8339 4.00046 11.9996V23.1991H8.79955V15.2003C8.79955 14.9789 8.97917 14.8002 9.20033 14.8002H14.7995C15.0207 14.8002 15.2003 14.9789 15.2003 15.2003V23.1991H20.0001V11.9996C20.0001 11.8339 20.1003 11.692 20.2443 11.6307C20.2918 11.611 20.3453 11.5999 20.4001 11.5999V11.5713L22.6193 11.5691L12.0029 0.964625Z" fill="currentColor"/>
</svg>
`;
const back_svg_str = `
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M17.8206 22.9016L7.45515 11.8756L17.8206 1.09845C18.0598 0.849741 18.0598 0.435233 17.8206 0.186528C17.5814 -0.0621762 17.1827 -0.0621762 16.9435 0.186528L6.1794 11.4611C5.9402 11.7098 5.9402 12.1244 6.1794 12.3731L16.9435 23.8135C17.1827 24.0622 17.5814 24.0622 17.8206 23.8135C18.0598 23.5648 18.0598 23.1503 17.8206 22.9016Z" fill="currentColor"/>
</svg>
`;
const loading_svg_str = `
<svg t="1709608074670" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4741" width="24" height="24"><path d="M256 529.066667H85.333333a17.066667 17.066667 0 1 1 0-34.133334h170.666667a17.066667 17.066667 0 0 1 0 34.133334z" opacity=".278" p-id="4742"></path><path d="M99.84 640a17.066667 17.066667 0 0 1-4.437333-33.553067l164.693333-44.373333a17.066667 17.066667 0 1 1 8.891733 32.9728l-164.693333 44.373333a17.544533 17.544533 0 0 1-4.4544 0.580267z" opacity=".322" p-id="4743"></path><path d="M264.533333 462.523733a16.896 16.896 0 0 1-4.369066-0.580266l-164.693334-43.52a17.0496 17.0496 0 1 1 8.721067-32.989867l164.693333 43.52a17.066667 17.066667 0 1 1-4.352 33.570133z" opacity=".239" p-id="4744"></path><path d="M384.017067 307.2a17.032533 17.032533 0 0 1-14.7968-8.533333l-85.333334-147.626667a17.066667 17.066667 0 0 1 29.559467-17.083733l85.333333 147.626666A17.066667 17.066667 0 0 1 384.017067 307.2z" opacity=".122" p-id="4745"></path><path d="M639.982933 307.2a17.0496 17.0496 0 0 1-14.762666-25.6l85.333333-147.626667a17.066667 17.066667 0 1 1 29.559467 17.066667l-85.333334 147.626667a17.032533 17.032533 0 0 1-14.7968 8.533333z" opacity=".922" p-id="4746"></path><path d="M692.906667 347.306667a17.066667 17.066667 0 0 1-12.117334-29.098667l120.337067-121.173333a17.066667 17.066667 0 1 1 24.234667 24.046933l-120.337067 121.173333a17.1008 17.1008 0 0 1-12.117333 5.051734z" opacity=".878" p-id="4747"></path><path d="M733.883733 401.066667a17.066667 17.066667 0 0 1-8.5504-31.8464l147.626667-85.333334a17.0496 17.0496 0 1 1 17.066667 29.5424l-147.626667 85.333334a16.776533 16.776533 0 0 1-8.516267 2.304z" opacity=".839" p-id="4748"></path><path d="M512 273.066667a17.066667 17.066667 0 0 1-17.066667-17.066667V85.333333a17.066667 17.066667 0 0 1 34.133334 0v170.666667a17.066667 17.066667 0 0 1-17.066667 17.066667z" p-id="4749"></path><path d="M578.577067 281.6a17.066667 17.066667 0 0 1-16.520534-21.418667l43.52-164.693333a17.066667 17.066667 0 0 1 33.006934 8.721067l-43.52 164.693333a17.066667 17.066667 0 0 1-16.4864 12.6976z" opacity=".961" p-id="4750"></path><path d="M445.44 282.453333a17.066667 17.066667 0 0 1-16.469333-12.629333l-44.373334-164.693333a17.066667 17.066667 0 0 1 32.955734-8.891734l44.373333 164.693334a17.066667 17.066667 0 0 1-16.4864 21.521066z" opacity=".078" p-id="4751"></path><path d="M924.177067 640c-1.4848 0-2.9696-0.187733-4.4544-0.580267l-164.693334-44.373333a17.066667 17.066667 0 0 1 8.874667-32.9728l164.693333 44.373333a17.066667 17.066667 0 0 1-4.420266 33.553067z" opacity=".722" p-id="4752"></path><path d="M881.476267 742.4a17.015467 17.015467 0 0 1-8.482134-2.269867l-148.48-85.333333a17.0496 17.0496 0 1 1 16.9984-29.5936l148.48 85.333333a17.0496 17.0496 0 0 1-8.516266 31.863467z" opacity=".678" p-id="4753"></path><path d="M813.226667 830.293333a17.015467 17.015467 0 0 1-12.066134-5.000533l-120.337066-120.337067a17.0496 17.0496 0 1 1 24.132266-24.132266l120.337067 120.337066a17.0496 17.0496 0 0 1-12.066133 29.1328z" opacity=".639" p-id="4754"></path><path d="M938.666667 529.066667H768a17.066667 17.066667 0 1 1 0-34.133334h170.666667a17.066667 17.066667 0 1 1 0 34.133334z" opacity=".761" p-id="4755"></path><path d="M401.066667 941.226667a17.066667 17.066667 0 0 1-16.4864-21.504l44.373333-164.693334a17.066667 17.066667 0 1 1 32.955733 8.874667l-44.373333 164.693333a17.066667 17.066667 0 0 1-16.469333 12.629334z" opacity=".478" p-id="4756"></path><path d="M298.6496 898.56a17.066667 17.066667 0 0 1-14.779733-25.565867l85.333333-148.48a17.083733 17.083733 0 0 1 29.5936 16.9984l-85.333333 148.48a17.032533 17.032533 0 0 1-14.813867 8.567467z" opacity=".439" p-id="4757"></path><path d="M512 955.733333a17.066667 17.066667 0 0 1-17.066667-17.066666V768a17.066667 17.066667 0 1 1 34.133334 0v170.666667a17.066667 17.066667 0 0 1-17.066667 17.066666z" opacity=".522" p-id="4758"></path><path d="M725.3504 898.56a17.032533 17.032533 0 0 1-14.7968-8.533333l-85.333333-147.626667a17.066667 17.066667 0 0 1 29.559466-17.066667l85.333334 147.626667a17.066667 17.066667 0 0 1-14.762667 25.6z" opacity=".6" p-id="4759"></path><path d="M622.062933 942.08c-7.509333 0-14.421333-5.0176-16.469333-12.629333l-44.3904-164.693334a17.066667 17.066667 0 1 1 32.9728-8.874666l44.3904 164.693333a17.066667 17.066667 0 0 1-16.503467 21.504z" opacity=".561" p-id="4760"></path><path d="M759.4496 463.36a17.083733 17.083733 0 0 1-4.420267-33.553067l164.693334-44.373333a17.066667 17.066667 0 0 1 8.874666 32.955733l-164.693333 44.373334a16.657067 16.657067 0 0 1-4.4544 0.597333z" opacity=".702" p-id="4761"></path><path d="M330.24 347.306667a17.015467 17.015467 0 0 1-12.066133-5.000534l-120.32-120.32a17.0496 17.0496 0 1 1 24.132266-24.132266l120.32 120.32a17.0496 17.0496 0 0 1-12.066133 29.1328z" opacity=".161" p-id="4762"></path><path d="M290.116267 401.066667a17.032533 17.032533 0 0 1-8.533334-2.286934l-147.626666-85.333333a17.066667 17.066667 0 1 1 17.083733-29.5424l147.626667 85.333333a17.066667 17.066667 0 0 1-8.5504 31.829334z" opacity=".2" p-id="4763"></path><path d="M142.523733 742.4a17.066667 17.066667 0 0 1-8.567466-31.8464l147.626666-85.333333a17.066667 17.066667 0 1 1 17.083734 29.559466l-147.626667 85.333334a16.930133 16.930133 0 0 1-8.516267 2.286933z" opacity=".361" p-id="4764"></path><path d="M209.92 830.293333a17.066667 17.066667 0 0 1-12.117333-29.098666l120.32-121.173334a17.066667 17.066667 0 0 1 24.2176 24.029867l-120.32 121.1904a16.896 16.896 0 0 1-12.100267 5.051733z" opacity=".4" p-id="4765"></path></svg>
`;
function initNavigationBar(config, container) {
    if (config.router.mode === 'multi')
        return;
    const navigationBar = document.createElement('div');
    navigationBar.classList.add('taro-navigation-bar-no-icon');
    const navigationBarBackBtn = document.createElement('div');
    navigationBarBackBtn.classList.add('taro-navigation-bar-back');
    const navigationBarHomeBtn = document.createElement('div');
    navigationBarHomeBtn.classList.add('taro-navigation-bar-home');
    navigationBarBackBtn.innerHTML = back_svg_str;
    navigationBarHomeBtn.innerHTML = home_svg_str;
    const navigationBarTitleWrap = document.createElement('div');
    navigationBarTitleWrap.classList.add('taro-navigation-bar-title-wrap');
    const navigationBarLoading = document.createElement('div');
    navigationBarLoading.classList.add('taro-navigation-bar-loading');
    navigationBarLoading.innerHTML = loading_svg_str;
    const navigationBarTitle = document.createElement('div');
    navigationBarTitle.classList.add('taro-navigation-bar-title');
    navigationBarTitleWrap.appendChild(navigationBarLoading);
    navigationBarTitleWrap.appendChild(navigationBarTitle);
    navigationBar.appendChild(navigationBarHomeBtn);
    navigationBar.appendChild(navigationBarBackBtn);
    navigationBar.appendChild(navigationBarTitleWrap);
    navigationBar.id = 'taro-navigation-bar';
    // prepend 不兼容 android6
    container.insertBefore(navigationBar, container.firstChild);
    loadNavigationBarStyle();
}

function initTabbar(config, history) {
    if (config.tabBar == null || config.tabBar.custom) {
        return;
    }
    // TODO: custom-tab-bar
    defineCustomElementTaroTabbar();
    const tabbar = document.createElement('taro-tabbar');
    const homePage = config.entryPagePath || (config.pages ? config.pages[0] : '');
    tabbar.conf = config.tabBar;
    tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
    const routerConfig = config.router;
    tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
    if (routerConfig.customRoutes) {
        tabbar.conf.custom = true;
        tabbar.conf.customRoutes = routerConfig.customRoutes;
    }
    else {
        tabbar.conf.custom = false;
        tabbar.conf.customRoutes = {};
    }
    if (typeof routerConfig.basename !== 'undefined') {
        tabbar.conf.basename = routerConfig.basename;
    }
    const container = document.getElementById('container');
    container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
    initTabBarApis(config);
}

class RouterConfig {
    static set config(e) {
        this.__config = e;
    }
    static get config() {
        return this.__config;
    }
    static get pages() {
        return this.config.pages || [];
    }
    static get router() {
        return this.config.router || {};
    }
    static get mode() {
        return this.router.mode || 'hash';
    }
    static get customRoutes() { return this.router.customRoutes || {}; }
    // 这个方法不考虑 basename 和 customRoutes,只判断原始的 url 是否在 pages 中
    static isPage(url = '') {
        return this.pages.findIndex(e => addLeadingSlash(e) === url) !== -1;
    }
}

let history;
let basename = '/';
class MpaHistory {
    constructor() {
        this.back = window.history.back;
        this.forward = window.history.forward;
        this.pushState = this.eventState('pushState');
        this.replaceState = this.eventState('replaceState');
    }
    get location() {
        return {
            pathname: window.location.pathname,
            search: window.location.search,
            hash: window.location.hash,
            key: `${window.history.length}`,
            state: window.history.state
        };
    }
    createHref(_to) {
        throw new Error('Method not implemented.');
    }
    parseUrl(to) {
        let url = to.pathname || '';
        if (RouterConfig.isPage(addLeadingSlash(url))) {
            url += '.html';
        }
        if (to.search) {
            url += `?${to.search}`;
        }
        if (to.hash) {
            url += to.hash.startsWith('#') ? to.hash : `#${to.hash}`;
        }
        return url;
    }
    push(to, _state = {}) {
        window.location.assign(this.parseUrl(to));
        // this.pushState(_state, '', this.parseUrl(to))
    }
    replace(to, _state = {}) {
        window.location.replace(this.parseUrl(to));
        // this.replaceState(_state, '', this.parseUrl(to))
    }
    go(delta) {
        window.history.go(delta);
    }
    listen(listener) {
        function callback(e) {
            if (e.action === 'pushState') {
                listener({ action: Action.Push, location: this.location });
            }
            else if (e.action === 'replaceState') {
                listener({ action: Action.Replace, location: this.location });
            }
            else {
                // NOTE: 这里包括 back、forward、go 三种可能,并非是 POP 事件
                listener({ action: Action.Pop, location: this.location });
            }
        }
        window.addEventListener('popstate', callback);
        return () => {
            window.removeEventListener('popstate', callback);
        };
    }
    block(_blocker) {
        throw new Error('Method not implemented.');
    }
    eventState(action) {
        return (data, unused, url) => {
            const wrapper = window.history[action](data, unused, url);
            const evt = new Event(action);
            evt.action = action;
            evt.state = data;
            evt.unused = unused;
            evt.url = url;
            window.dispatchEvent(evt);
            return wrapper;
        };
    }
}
function setHistory(h, base = '/') {
    history = h;
    basename = base;
}
function createMpaHistory(_) {
    return new MpaHistory();
}
function setHistoryMode(mode, base = '/') {
    const options = {
        window
    };
    basename = base;
    if (mode === 'browser') {
        history = createBrowserHistory(options);
    }
    else if (mode === 'multi') {
        history = createMpaHistory();
    }
    else {
        // default is hash
        history = createHashHistory(options);
    }
}
function prependBasename(url = '') {
    return basename.replace(/\/$/, '') + '/' + url.replace(/^\//, '');
}

class Stacks {
    constructor() {
        this.stacks = [];
        this.backDelta = 0;
        this.tabs = {};
        this.methodName = '';
    }
    set delta(delta) {
        if (delta > 0) {
            this.backDelta = delta;
        }
        else if (this.backDelta > 0) {
            --this.backDelta;
        }
        else {
            this.backDelta = 0;
        }
    }
    get delta() {
        return this.backDelta;
    }
    set method(methodName) {
        this.methodName = methodName;
    }
    get method() {
        return this.methodName;
    }
    get length() {
        return this.stacks.length;
    }
    get last() {
        return this.stacks[this.length - 1];
    }
    get() {
        return this.stacks;
    }
    getItem(index) {
        return this.stacks[index];
    }
    getLastIndex(pathname, stateWith = 1) {
        const list = [...this.stacks].reverse();
        return list.findIndex((page, i) => { var _a; return i >= stateWith && ((_a = page.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname; });
    }
    getDelta(pathname) {
        if (this.backDelta >= 1) {
            return this.backDelta;
        }
        const index = this.getLastIndex(pathname);
        // NOTE: 此处为了修复浏览器后退多级页面,在大量重复路由状况下可能出现判断错误的情况 (增强判断能力只能考虑在 query 中新增参数来判断,暂时搁置)
        return index > 0 ? index : 1;
    }
    getPrevIndex(pathname, stateWith = 1) {
        const lastIndex = this.getLastIndex(pathname, stateWith);
        if (lastIndex < 0) {
            return -1;
        }
        return this.length - 1 - lastIndex;
    }
    pop() {
        return this.stacks.pop();
    }
    push(page) {
        return this.stacks.push(page);
    }
    getTabs() {
        return this.tabs;
    }
    pushTab(path) {
        this.tabs[path] = this.last;
        this.pop();
    }
    popTab(path) {
        this.push(this.tabs[path]);
        delete this.tabs[path];
    }
    removeTab(path) {
        delete this.tabs[path];
    }
}
const stacks = new Stacks();

const isWeixin = () => !!navigator.userAgent.match(/\bMicroMessenger\b/ig);
const isDingTalk = () => !!navigator.userAgent.match(/\bDingTalk\b/ig);
let preTitle = document.title;
let isLoadDdEntry = false;
function setMpaTitle(title) {
    if (preTitle === title)
        return;
    document.title = title;
    preTitle = title;
    if (process.env.SUPPORT_DINGTALK_NAVIGATE !== 'disabled' && isDingTalk()) {
        if (!isLoadDdEntry) {
            isLoadDdEntry = true;
            require('dingtalk-jsapi/platform');
        }
        const setDingTitle = require('dingtalk-jsapi/api/biz/navigation/setTitle').default;
        setDingTitle({ title });
    }
}
function setTitle(title) {
    eventCenter.trigger('__taroH5SetNavigationBarTitle', title);
}
function setNavigationBarStyle(option) {
    eventCenter.trigger('__taroH5setNavigationBarColor', option);
}
function setNavigationBarLoading(loading) {
    eventCenter.trigger('__taroH5setNavigationBarLoading', loading);
}

class RoutesAlias {
    constructor() {
        this.conf = [];
        this.getConfig = (url = '') => {
            const customRoute = this.conf.filter((arr) => {
                return arr.includes(url);
            });
            return customRoute[0];
        };
        this.getOrigin = (url = '') => {
            var _a;
            return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[0]) || url;
        };
        this.getAlias = (url = '') => {
            var _a;
            return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[1]) || url;
        };
        this.getAll = (url = '') => {
            return this.conf
                .filter((arr) => arr.includes(url))
                .reduceRight((p, a) => {
                p.unshift(a[1]);
                return p;
            }, []);
        };
    }
    set(customRoutes = {}) {
        for (let key in customRoutes) {
            const path = customRoutes[key];
            key = addLeadingSlash(key);
            if (typeof path === 'string') {
                this.conf.push([key, addLeadingSlash(path)]);
            }
            else if ((path === null || path === void 0 ? void 0 : path.length) > 0) {
                this.conf.push(...path.map(p => [key, addLeadingSlash(p)]));
            }
        }
    }
}
const routesAlias = new RoutesAlias();

const routeEvtChannel = EventChannel.routeChannel;
function processNavigateUrl(option) {
    var _a;
    const pathPieces = parsePath(option.url);
    // 处理相对路径
    if ((_a = pathPieces.pathname) === null || _a === void 0 ? void 0 : _a.includes('./')) {
        const parts = routesAlias.getOrigin(history.location.pathname).split('/');
        parts.pop();
        pathPieces.pathname.split('/').forEach((item) => {
            if (item === '.')
                return;
            item === '..' ? parts.pop() : parts.push(item);
        });
        pathPieces.pathname = parts.join('/');
    }
    // 确保是 / 开头的路径
    pathPieces.pathname = addLeadingSlash(pathPieces.pathname);
    // 处理自定义路由
    pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
    // 处理 basename
    pathPieces.pathname = prependBasename(pathPieces.pathname);
    // hack fix history v5 bug: https://github.com/remix-run/history/issues/814
    if (!pathPieces.search)
        pathPieces.search = '';
    return pathPieces;
}
function navigate(option, method) {
    return __awaiter(this, void 0, void 0, function* () {
        return new Promise((resolve, reject) => {
            stacks.method = method;
            const { success, complete, fail } = option;
            const unListen = history.listen(() => {
                const res = { errMsg: `${method}:ok` };
                if (method === 'navigateTo') {
                    res.eventChannel = routeEvtChannel;
                    routeEvtChannel.addEvents(option.events);
                }
                success === null || success === void 0 ? void 0 : success(res);
                complete === null || complete === void 0 ? void 0 : complete(res);
                resolve(res);
                unListen();
            });
            try {
                if ('url' in option) {
                    const pathPieces = processNavigateUrl(option);
                    const state = { timestamp: Date.now() };
                    if (method === 'navigateTo') {
                        // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
                        history.push(pathPieces, state);
                    }
                    else if (method === 'redirectTo' || method === 'switchTab') {
                        history.replace(pathPieces, state);
                    }
                    else if (method === 'reLaunch') {
                        stacks.delta = stacks.length;
                        history.replace(pathPieces, state);
                    }
                }
                else if (method === 'navigateBack') {
                    stacks.delta = option.delta;
                    if (stacks.length > option.delta) {
                        history.go(-option.delta);
                    }
                    else {
                        history.go(1 - stacks.length);
                    }
                }
            }
            catch (error) {
                const res = { errMsg: `${method}:fail ${error.message || error}` };
                fail === null || fail === void 0 ? void 0 : fail(res);
                complete === null || complete === void 0 ? void 0 : complete(res);
                if (fail || complete) {
                    return resolve(res);
                }
                else {
                    return reject(res);
                }
            }
        });
    });
}
function navigateTo(option) {
    return navigate(option, 'navigateTo');
}
function redirectTo(option) {
    return navigate(option, 'redirectTo');
}
function navigateBack(option = { delta: 1 }) {
    if (!option.delta || option.delta < 1) {
        option.delta = 1;
    }
    return navigate(option, 'navigateBack');
}
function switchTab(option) {
    return navigate(option, 'switchTab');
}
function reLaunch(option) {
    return navigate(option, 'reLaunch');
}
function getCurrentPages() {
    if (process.env.NODE_ENV !== 'production' && RouterConfig.mode === 'multi') {
        console.warn('多页面路由模式不支持使用 getCurrentPages 方法!');
    }
    const pages = stacks.get();
    return pages.map(e => { var _a; return (Object.assign(Object.assign({}, e), { route: ((_a = e.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) || '' })); });
}

let pageResizeFn;
function bindPageResize(page) {
    pageResizeFn && window.removeEventListener('resize', pageResizeFn);
    pageResizeFn = function () {
        if (page.onResize) {
            const mediaQuery = window.matchMedia('(orientation: portrait)');
            page.onResize({
                deviceOrientation: mediaQuery.matches ? 'portrait' : 'landscape',
                size: {
                    windowHeight: window.innerHeight,
                    windowWidth: window.innerWidth,
                    screenHeight: window.screen.height,
                    screenWidth: window.screen.width,
                }
            });
        }
    };
    window.addEventListener('resize', pageResizeFn, false);
}

const pageScrollBindings = new Map();
function bindPageScroll(page, scrollEl, distance = 50) {
    var _a;
    const pagePath = (page ? page === null || page === void 0 ? void 0 : page.path : (_a = Current.router) === null || _a === void 0 ? void 0 : _a.path);
    const previous = pageScrollBindings.get(pagePath);
    previous === null || previous === void 0 ? void 0 : previous.target.removeEventListener('scroll', previous.listener);
    let isReachBottom = false;
    const listener = function () {
        var _a;
        (_a = page.onPageScroll) === null || _a === void 0 ? void 0 : _a.call(page, {
            scrollTop: scrollEl instanceof Window ? scrollEl.scrollY : scrollEl.scrollTop
        });
        if (isReachBottom && getOffset(scrollEl) > distance) {
            isReachBottom = false;
        }
        if (page.onReachBottom &&
            !isReachBottom &&
            getOffset(scrollEl) < distance) {
            isReachBottom = true;
            page.onReachBottom();
        }
    };
    pageScrollBindings.set(pagePath, { target: scrollEl, listener });
    scrollEl.addEventListener('scroll', listener, false);
}
function getOffset(scrollEl) {
    if (scrollEl instanceof Window) {
        return scrollEl.document.documentElement.scrollHeight - scrollEl.scrollY - scrollEl.innerHeight;
    }
    else {
        return scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight;
    }
}

/* eslint-disable dot-notation */
class MultiPageHandler {
    constructor(config, history) {
        this.history = history;
        this.config = config;
        this.mount();
    }
    get appId() { return this.config.appId || 'app'; }
    get router() { return this.config.router || {}; }
    get routerMode() { return this.router.mode || 'hash'; }
    get customRoutes() { return this.router.customRoutes || {}; }
    get tabBarList() { var _a; return ((_a = this.config.tabBar) === null || _a === void 0 ? void 0 : _a.list) || []; }
    get PullDownRefresh() { return this.config.PullDownRefresh; }
    set pathname(p) { this.router.pathname = p; }
    get pathname() { return this.router.pathname; }
    get basename() { return this.router.basename || ''; }
    get pageConfig() { return this.config.route; }
    get isTabBar() {
        var _a;
        const routePath = addLeadingSlash(stripBasename(this.pathname, this.basename));
        const pagePath = ((_a = Object.entries(this.customRoutes).find(([, target]) => {
            if (typeof target === 'string') {
                return target === routePath;
            }
            else if ((target === null || target === void 0 ? void 0 : target.length) > 0) {
                return target.includes(routePath);
            }
            return false;
        })) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
        return !!pagePath && this.tabBarList.some(t => t.pagePath === pagePath);
    }
    get search() { return location.search.substr(1); }
    get usingWindowScroll() {
        var _a;
        let usingWindowScroll = true;
        if (typeof ((_a = this.pageConfig) === null || _a === void 0 ? void 0 : _a.usingWindowScroll) === 'boolean') {
            usingWindowScroll = this.pageConfig.usingWindowScroll;
        }
        const win = window;
        win.__taroAppConfig || (win.__taroAppConfig = {});
        win.__taroAppConfig.usingWindowScroll = usingWindowScroll;
        return usingWindowScroll;
    }
    getQuery(search = '', options = {}) {
        search = search ? `${search}&${this.search}` : this.search;
        const query = search
            ? queryString.parse(search)
            : {};
        return Object.assign(Object.assign({}, query), options);
    }
    isDefaultNavigationStyle() {
        var _a, _b;
        let style = (_a = this.config.window) === null || _a === void 0 ? void 0 : _a.navigationStyle;
        if (typeof ((_b = this.pageConfig) === null || _b === void 0 ? void 0 : _b.navigationStyle) === 'string') {
            style = this.pageConfig.navigationStyle;
        }
        return style !== 'custom';
    }
    mount() {
        setHistory(this.history, this.basename);
        // Note: 注入页面样式
        loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll);
    }
    onReady(page, onLoad = true) {
        var _a;
        const pageEl = this.getPageContainer(page);
        if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
            const el = pageEl.firstElementChild;
            const componentOnReady = el === null || el === void 0 ? void 0 : el['componentOnReady'];
            if (componentOnReady) {
                componentOnReady === null || componentOnReady === void 0 ? void 0 : componentOnReady().then(() => {
                    requestAnimationFrame(() => {
                        var _a;
                        (_a = page.onReady) === null || _a === void 0 ? void 0 : _a.call(page);
                        pageEl['__isReady'] = true;
                    });
                });
            }
            else {
                (_a = page.onReady) === null || _a === void 0 ? void 0 : _a.call(page);
                pageEl['__isReady'] = true;
            }
            onLoad && (pageEl['__page'] = page);
        }
    }
    load(page, pageConfig = {}) {
        var _a;
        if (!page)
            return;
        (_a = page.onLoad) === null || _a === void 0 ? void 0 : _a.call(page, this.getQuery('', page.options), () => {
            var _a;
            const pageEl = this.getPageContainer(page);
            if (this.isTabBar) {
                pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.add('taro_tabbar_page');
            }
            if (this.isDefaultNavigationStyle()) {
                pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.add('taro_navigation_page');
            }
            this.onReady(page, true);
            (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
            this.bindPageEvents(page, pageConfig);
            this.triggerRouterChange();
        });
    }
    getPageContainer(page) {
        var _a;
        const path = page ? page === null || page === void 0 ? void 0 : page.path : (_a = Current.page) === null || _a === void 0 ? void 0 : _a.path;
        const id = path === null || path === void 0 ? void 0 : path.replace(/([^a-z0-9\u00a0-\uffff_-])/ig, '\\$1');
        if (page) {
            return document.querySelector(`.taro_page#${id}`);
        }
        const el = (id
            ? document.querySelector(`.taro_page#${id}`)
            : document.querySelector('.taro_page') ||
                document.querySelector('.taro_router'));
        return el;
    }
    getScrollingElement(page) {
        if (this.usingWindowScroll)
            return window;
        return this.getPageContainer(page) || window;
    }
    bindPageEvents(page, config = {}) {
        var _a;
        const scrollEl = this.getScrollingElement(page);
        const distance = config.onReachBottomDistance || ((_a = this.config.window) === null || _a === void 0 ? void 0 : _a.onReachBottomDistance) || 50;
        bindPageScroll(page, scrollEl, distance);
        bindPageResize(page);
    }
    triggerRouterChange() {
        /**
         * @tarojs/runtime 中生命周期跑在 promise 中,所以这里需要 setTimeout 延迟事件调用
         * TODO 考虑将生命周期返回 Promise,用于处理相关事件调用顺序
         */
        setTimeout(() => {
            eventCenter.trigger('__afterTaroRouterChange', {
                toLocation: {
                    path: this.pathname
                }
            });
        }, 0);
    }
}

const createStampId$1 = incrementId();
const launchStampId$1 = createStampId$1();
// TODO 支持多路由 (APP 生命周期仅触发一次)
/** Note: 关于多页面应用
 * - 需要配置路由映射(根目录跳转、404 页面……)
 * - app.onPageNotFound 事件不支持
 * - 应用生命周期可能多次触发
 * - TabBar 会多次加载
 * - 不支持路由动画
 */
function createMultiRouter(history, app, config, framework) {
    return __awaiter(this, void 0, void 0, function* () {
        var _a, _b, _c, _d, _e, _f;
        if (typeof app.onUnhandledRejection === 'function') {
            window.addEventListener('unhandledrejection', app.onUnhandledRejection);
        }
        eventCenter.on('__taroH5SetNavigationBarTitle', setMpaTitle);
        RouterConfig.config = config;
        const handler = new MultiPageHandler(config, history);
        const launchParam = {
            path: config.pageName, // 多页面模式没新开一个页面相当于重启,所以直接使用当前页面路径
            query: handler.getQuery(launchStampId$1),
            scene: 0,
            shareTicket: '',
            referrerInfo: {}
        };
        eventCenter.trigger('__taroRouterLaunch', launchParam);
        (_a = app.onLaunch) === null || _a === void 0 ? void 0 : _a.call(app, launchParam);
        app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
        const pathName = config.pageName;
        const pageConfig = handler.pageConfig;
        eventCenter.trigger('__taroRouterChange', {
            toLocation: {
                path: pathName
            }
        });
        let element;
        try {
            element = yield ((_b = pageConfig.load) === null || _b === void 0 ? void 0 : _b.call(pageConfig));
            if (element instanceof Array) {
                element = element[0];
            }
        }
        catch (error) {
            throw new Error(error);
        }
        if (!element)
            return;
        let enablePullDownRefresh = ((_c = config === null || config === void 0 ? void 0 : config.window) === null || _c === void 0 ? void 0 : _c.enablePullDownRefresh) || false;
        if (pageConfig) {
            setMpaTitle((_d = pageConfig.navigationBarTitleText) !== null && _d !== void 0 ? _d : document.title);
            if (typeof pageConfig.enablePullDownRefresh === 'boolean') {
                enablePullDownRefresh = pageConfig.enablePullDownRefresh;
            }
        }
        const el = (_e = element.default) !== null && _e !== void 0 ? _e : element;
        const loadConfig = Object.assign({}, pageConfig);
        delete loadConfig['path'];
        delete loadConfig['load'];
        const page = createPageConfig(enablePullDownRefresh ? hooks.call('createPullDownComponent', el, pathName, framework, handler.PullDownRefresh) : el, pathName + stringify(launchParam), {}, loadConfig);
        handler.load(page, pageConfig);
        (_f = app.onShow) === null || _f === void 0 ? void 0 : _f.call(app, launchParam);
        window.addEventListener('visibilitychange', () => {
            var _a, _b, _c;
            const currentPath = ((_a = Current.page) === null || _a === void 0 ? void 0 : _a.path) || '';
            const path = currentPath.substring(0, currentPath.indexOf('?'));
            const param = {};
            // app的 onShow/onHide 生命周期的路径信息为当前页面的路径
            Object.assign(param, launchParam, { path });
            if (document.visibilityState === 'visible') {
                (_b = app.onShow) === null || _b === void 0 ? void 0 : _b.call(app, param);
            }
            else {
                (_c = app.onHide) === null || _c === void 0 ? void 0 : _c.call(app, param);
            }
        });
    });
}

class NavigationBarHandler {
    constructor(pageContext) {
        this.isLoadDdEntry = false;
        this.cache = {};
        this.pageContext = pageContext;
        this.init();
        eventCenter.on('__taroH5SetNavigationBarTitle', (title) => {
            this.setTitle(title);
        });
        eventCenter.on('__taroH5setNavigationBarLoading', (loading) => {
            this.setNavigationLoading(loading);
        });
        eventCenter.on('__taroH5setNavigationBarColor', ({ backgroundColor, frontColor }) => {
            if (typeof backgroundColor === 'string')
                this.setNavigationBarBackground(backgroundColor);
            if (typeof frontColor === 'string')
                this.setNavigationBarTextStyle(frontColor);
        });
    }
    toHomeFn() {
        reLaunch({ url: this.pageContext.originHomePage });
    }
    backFn() {
        navigateBack();
    }
    get homeBtnElement() {
        var _a;
        if (!this.navigationBarElement)
            return null;
        return (_a = this.navigationBarElement.getElementsByClassName('taro-navigation-bar-home')) === null || _a === void 0 ? void 0 : _a[0];
    }
    get backBtnElement() {
        var _a;
        if (!this.navigationBarElement)
            return null;
        return (_a = this.navigationBarElement.getElementsByClassName('taro-navigation-bar-back')) === null || _a === void 0 ? void 0 : _a[0];
    }
    get titleElement() {
        var _a;
        if (!this.navigationBarElement)
            return null;
        return (_a = this.navigationBarElement.getElementsByClassName('taro-navigation-bar-title')) === null || _a === void 0 ? void 0 : _a[0];
    }
    get loadingElement() {
        if (!this.navigationBarElement)
            return null;
        return this.navigationBarElement.getElementsByClassName('taro-navigation-bar-loading')[0];
    }
    init() {
        var _a, _b;
        this.setNavigationBarElement();
        if (!this.navigationBarElement)
            return;
        (_a = this.homeBtnElement) === null || _a === void 0 ? void 0 : _a.addEventListener('click', this.toHomeFn.bind(this));
        (_b = this.backBtnElement) === null || _b === void 0 ? void 0 : _b.addEventListener('click', this.backFn.bind(this));
    }
    setNavigationBarElement() {
        this.navigationBarElement = document.getElementById('taro-navigation-bar');
    }
    load() {
        this.setCacheValue();
        this.setTitle();
        this.setNavigationBarVisible();
        this.setFnBtnState();
        this.setNavigationBarBackground();
        this.setNavigationBarTextStyle();
        this.setNavigationLoading();
    }
    setCacheValue() {
        const currentPage = this.pageContext.originPathname;
        if (typeof this.cache[currentPage] !== 'object') {
            this.cache[currentPage] = {};
        }
    }
    setFnBtnState() {
        const currentRouter = this.pageContext.currentPage;
        if (this.pageContext.isTabBar(currentRouter) || this.pageContext.homePage === currentRouter) {
            this.fnBtnToggleToNone();
        }
        else if (stacks.length > 1) {
            this.fnBtnToggleToBack();
        }
        else {
            this.fnBtnToggleToHome();
        }
    }
    shiftLoadingState(show) {
        if (!this.loadingElement)
            return;
        if (show) {
            this.loadingElement.classList.add('taro-navigation-bar-loading-show');
        }
        else {
            this.loadingElement.classList.remove('taro-navigation-bar-loading-show');
        }
    }
    setNavigationLoading(show) {
        var _a;
        if (!this.navigationBarElement)
            return;
        const currentPage = this.pageContext.originPathname;
        let isShow;
        if (typeof show === 'boolean') {
            isShow = show;
            this.cache[currentPage] &&
                (this.cache[currentPage].loading = isShow);
        }
        else {
            const cacheValue = (_a = this.cache[currentPage]) === null || _a === void 0 ? void 0 : _a.loading;
            if (typeof cacheValue === 'boolean') {
                isShow = cacheValue;
            }
            else {
                // 默认值为 false
                isShow = false;
                this.cache[currentPage] &&
                    (this.cache[currentPage].loading = isShow);
            }
        }
        this.shiftLoadingState(isShow);
    }
    setNavigationBarBackground(backgroundColor) {
        var _a, _b, _c;
        if (!this.navigationBarElement)
            return;
        const currentPage = this.pageContext.originPathname;
        let color;
        if (typeof backgroundColor === 'string') {
            color = backgroundColor;
            this.cache[currentPage] &&
                (this.cache[currentPage].backgroundColor = color);
        }
        else {
            const cacheValue = (_a = this.cache[currentPage]) === null || _a === void 0 ? void 0 : _a.backgroundColor;
            if (typeof cacheValue === 'string') {
                color = cacheValue;
            }
            else {
                color = ((_c = (_b = this.pageContext.config) === null || _b === void 0 ? void 0 : _b.window) === null || _c === void 0 ? void 0 : _c.navigationBarBackgroundColor) || '#000000';
                this.cache[currentPage] &&
                    (this.cache[currentPage].backgroundColor = color);
            }
        }
        this.navigationBarElement.style.background = color;
    }
    setNavigationBarTextStyle(fontColor) {
        var _a, _b, _c;
        if (!this.navigationBarElement)
            return;
        const currentPage = this.pageContext.originPathname;
        let color;
        if (typeof fontColor === 'string') {
            color = fontColor;
            this.cache[currentPage] &&
                (this.cache[currentPage].fontColor = color);
        }
        else {
            const cacheValue = (_a = this.cache[currentPage]) === null || _a === void 0 ? void 0 : _a.fontColor;
            if (typeof cacheValue === 'string') {
                color = cacheValue;
            }
            else {
                color = ((_c = (_b = this.pageContext.config) === null || _b === void 0 ? void 0 : _b.window) === null || _c === void 0 ? void 0 : _c.navigationBarTextStyle) || 'white';
                this.cache[currentPage] &&
                    (this.cache[currentPage].fontColor = color);
            }
        }
        this.navigationBarElement.style.color = color;
    }
    setTitle(title) {
        var _a, _b, _c;
        const currentPage = this.pageContext.originPathname;
        let proceedTitle;
        if (typeof title === 'string') {
            proceedTitle = title;
            this.cache[currentPage] &&
                (this.cache[currentPage].title = proceedTitle);
        }
        else {
            const cacheValue = (_a = this.cache[currentPage]) === null || _a === void 0 ? void 0 : _a.title;
            if (typeof cacheValue === 'string') {
                proceedTitle = cacheValue;
            }
            else {
                proceedTitle = (_c = (_b = this.pageContext.pageConfig) === null || _b === void 0 ? void 0 : _b.navigationBarTitleText) !== null && _c !== void 0 ? _c : document.title;
                this.cache[currentPage] &&
                    (this.cache[currentPage].title = proceedTitle);
            }
        }
        if (process.env.SUPPORT_DINGTALK_NAVIGATE !== 'disabled' && isDingTalk()) {
            if (!this.isLoadDdEntry) {
                this.isLoadDdEntry = true;
                require('dingtalk-jsapi/platform');
            }
            const setDingTitle = require('dingtalk-jsapi/api/biz/navigation/setTitle').default;
            setDingTitle({ proceedTitle });
        }
        document.title = proceedTitle;
        if (!this.titleElement)
            return;
        this.titleElement.innerHTML = proceedTitle;
    }
    fnBtnToggleToHome() {
        if (!this.navigationBarElement)
            return;
        this.navigationBarElement.classList.add('taro-navigation-bar-home-icon');
        this.navigationBarElement.classList.remove('taro-navigation-bar-back-icon');
    }
    fnBtnToggleToBack() {
        if (!this.navigationBarElement)
            return;
        this.navigationBarElement.classList.remove('taro-navigation-bar-home-icon');
        this.navigationBarElement.classList.add('taro-navigation-bar-back-icon');
    }
    fnBtnToggleToNone() {
        if (!this.navigationBarElement)
            return;
        this.navigationBarElement.classList.remove('taro-navigation-bar-home-icon');
        this.navigationBarElement.classList.remove('taro-navigation-bar-back-icon');
    }
    setNavigationBarVisible(show) {
        var _a, _b;
        if (!this.navigationBarElement)
            return;
        let shouldShow;
        if (typeof show === 'boolean') {
            shouldShow = show;
        }
        else {
            shouldShow = (_a = this.pageContext.config.window) === null || _a === void 0 ? void 0 : _a.navigationStyle;
            if (typeof ((_b = this.pageContext.pageConfig) === null || _b === void 0 ? void 0 : _b.navigationStyle) === 'string') {
                shouldShow = this.pageContext.pageConfig.navigationStyle;
            }
        }
        if (shouldShow === 'default') {
            this.navigationBarElement.classList.add('taro-navigation-bar-show');
            this.navigationBarElement.classList.remove('taro-navigation-bar-hide');
        }
        else {
            this.navigationBarElement.classList.add('taro-navigation-bar-hide');
            this.navigationBarElement.classList.remove('taro-navigation-bar-show');
        }
    }
}

/* eslint-disable dot-notation */
class PageHandler {
    constructor(config, history) {
        this.history = history;
        this.defaultAnimation = { duration: 300, delay: 50 };
        this.config = config;
        this.homePage = getHomePage(this.routes[0].path, this.basename, this.customRoutes, this.config.entryPagePath);
        this.originHomePage = this.config.entryPagePath || this.routes[0].path || this.basename;
        this.mount();
        this.navigationBarHandler = new NavigationBarHandler(this);
    }
    get currentPage() {
        const routePath = getCurrentPage(this.routerMode, this.basename);
        return routePath === '/' ? this.homePage : routePath;
    }
    get appId() { return this.config.appId || 'app'; }
    get router() { return this.config.router || {}; }
    get routerMode() { return this.router.mode || 'hash'; }
    get customRoutes() { return this.router.customRoutes || {}; }
    get routes() { return this.config.routes || []; }
    get tabBarList() { var _a; return ((_a = this.config.tabBar) === null || _a === void 0 ? void 0 : _a.list) || []; }
    get PullDownRefresh() { return this.config.PullDownRefresh; }
    get animation() { var _a, _b; return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.animation) !== null && _b !== void 0 ? _b : this.defaultAnimation; }
    get animationDelay() {
        var _a;
        return (typeof this.animation === 'object'
            ? this.animation.delay
            : this.animation
                ? (_a = this.defaultAnimation) === null || _a === void 0 ? void 0 : _a.delay
                : 0) || 0;
    }
    get animationDuration() {
        var _a;
        return (typeof this.animation === 'object'
            ? this.animation.duration
            : this.animation
                ? (_a = this.defaultAnimation) === null || _a === void 0 ? void 0 : _a.duration
                : 0) || 0;
    }
    set pathname(p) { this.router.pathname = p; }
    get pathname() { return this.router.pathname; }
    // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
    get originPathname() { return routesAlias.getOrigin(addLeadingSlash(stripBasename(this.pathname, this.basename))); }
    get basename() { return this.router.basename || ''; }
    get pageConfig() {
        const homePage = addLeadingSlash(this.homePage);
        return this.routes.find(r => {
            const pagePath = addLeadingSlash(r.path);
            return [pagePath, homePage].includes(this.originPathname);
        });
    }
    isTabBar(pathname) {
        var _a;
        const routePath = addLeadingSlash(stripBasename(pathname, this.basename)).split('?')[0];
        const pagePath = ((_a = Object.entries(this.customRoutes).find(([, target]) => {
            if (typeof target === 'string') {
                return target === routePath;
            }
            else if ((target === null || target === void 0 ? void 0 : target.length) > 0) {
                return target.includes(routePath);
            }
            return false;
        })) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
        // Fix: 这里仍然需要使用 addLeadingSlash 来处理 pagePath,因为 pagePath 可能在未被增加统一前缀 / 的时候就进行比对
        return !!pagePath && this.tabBarList.some(t => addLeadingSlash(stripTrailing(t.pagePath)) === pagePath);
    }
    isDefaultNavigationStyle() {
        var _a, _b;
        let style = (_a = this.config.window) === null || _a === void 0 ? void 0 : _a.navigationStyle;
        if (typeof ((_b = this.pageConfig) === null || _b === void 0 ? void 0 : _b.navigationStyle) === 'string') {
            style = this.pageConfig.navigationStyle;
        }
        return style !== 'custom';
    }
    isSamePage(page) {
        const routePath = stripBasename(this.pathname, this.basename);
        const pagePath = stripBasename(page === null || page === void 0 ? void 0 : page.path, this.basename);
        return pagePath.startsWith(routePath + '?');
    }
    get search() {
        let search = '?';
        if (this.routerMode === 'hash') {
            const idx = location.hash.indexOf('?');
            if (idx > -1) {
                search = location.hash.slice(idx);
            }
        }
        else {
            search = location.search;
        }
        return search.substring(1);
    }
    get usingWindowScroll() {
        var _a;
        let usingWindowScroll = false;
        if (typeof ((_a = this.pageConfig) === null || _a === void 0 ? void 0 : _a.usingWindowScroll) === 'boolean') {
            usingWindowScroll = this.pageConfig.usingWindowScroll;
        }
        const win = window;
        win.__taroAppConfig || (win.__taroAppConfig = {});
        win.__taroAppConfig.usingWindowScroll = usingWindowScroll;
        return usingWindowScroll;
    }
    getQuery(stamp = '', search = '', options = {}) {
        search = search ? `${search}&${this.search}` : this.search;
        const query = search
            ? queryString.parse(search, { decode: false })
            : {};
        query.stamp = stamp;
        return Object.assign(Object.assign({}, query), options);
    }
    mount() {
        setHistory(this.history, this.basename);
        this.pathname = history.location.pathname;
        // Note: 注入页面样式
        this.animation && loadAnimateStyle(this.animationDuration);
        loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll, this.router.enhanceAnimation);
    }
    onReady(page, onLoad = true) {
        var _a;
        const pageEl = this.getPageContainer(page);
        if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
            const el = pageEl.firstElementChild;
            const componentOnReady = el === null || el === void 0 ? void 0 : el['componentOnReady'];
            if (componentOnReady) {
                componentOnReady === null || componentOnReady === void 0 ? void 0 : componentOnReady().then(() => {
                    requestAnimationFrame$1(() => {
                        var _a;
                        (_a = page.onReady) === null || _a === void 0 ? void 0 : _a.call(page);
                        pageEl['__isReady'] = true;
                    });
                });
            }
            else {
                (_a = page.onReady) === null || _a === void 0 ? void 0 : _a.call(page);
                pageEl['__isReady'] = true;
            }
            onLoad && (pageEl['__page'] = page);
        }
    }
    load(page, pageConfig = {}, stampId, pageNo = 0) {
        var _a, _b;
        if (!page)
            return;
        // NOTE: 页面栈推入太晚可能导致 getCurrentPages 无法获取到当前页面实例
        stacks.push(page);
        const param = this.getQuery(stampId, '', page.options);
        let pageEl = this.getPageContainer(page);
        if (pageEl) {
            pageEl.classList.remove('taro_page_shade');
            this.isTabBar(this.pathname) && pageEl.classList.add('taro_tabbar_page');
            this.isDefaultNavigationStyle() && pageEl.classList.add('taro_navigation_page');
            this.addAnimation(pageEl, pageNo === 0);
            (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
            this.navigationBarHandler.load();
            this.bindPageEvents(page, pageConfig);
            this.triggerRouterChange();
        }
        else {
            // FIXME 在 iOS 端快速切换页面时,可能不会执行回调注入对应类名导致 TabBar 白屏
            (_b = page.onLoad) === null || _b === void 0 ? void 0 : _b.call(page, param, () => {
                var _a;
                pageEl = this.getPageContainer(page);
                this.isTabBar(this.pathname) && (pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.add('taro_tabbar_page'));
                this.isDefaultNavigationStyle() && (pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.add('taro_navigation_page'));
                this.addAnimation(pageEl, pageNo === 0);
                (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
                this.navigationBarHandler.load();
                this.onReady(page, true);
                this.bindPageEvents(page, pageConfig);
                this.triggerRouterChange();
            });
        }
    }
    unload(page, delta = 1, top = false) {
        var _a, _b, _c;
        if (!page)
            return;
        stacks.delta = --delta;
        stacks.pop();
        if (this.animation && top) {
            if (this.unloadTimer) {
                clearTimeout(this.unloadTimer);
                (_b = (_a = this.lastUnloadPage) === null || _a === void 0 ? void 0 : _a.onUnload) === null || _b === void 0 ? void 0 : _b.call(_a);
                this.unloadTimer = null;
            }
            this.lastUnloadPage = page;
            const pageEl = this.getPageContainer(page);
            pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_stationed');
            pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_show');
            if (pageEl) {
                pageEl.style.zIndex = '1';
            }
            this.unloadTimer = setTimeout(() => {
                var _a, _b;
                this.unloadTimer = null;
                (_b = (_a = this.lastUnloadPage) === null || _a === void 0 ? void 0 : _a.onUnload) === null || _b === void 0 ? void 0 : _b.call(_a);
                eventCenter.trigger('__taroPageOnShowAfterDestroyed');
            }, this.animationDuration);
        }
        else {
            const pageEl = this.getPageContainer(page);
            pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_stationed');
            pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_show');
            (_c = page === null || page === void 0 ? void 0 : page.onUnload) === null || _c === void 0 ? void 0 : _c.call(page);
            setTimeout(() => {
                eventCenter.trigger('__taroPageOnShowAfterDestroyed');
            }, 0);
        }
        if (delta >= 1)
            this.unload(stacks.last, delta);
    }
    show(page, pageConfig = {}, pageNo = 0) {
        var _a, _b;
        if (!page)
            return;
        const param = this.getQuery(page['$taroParams']['stamp'], '', page.options);
        let pageEl = this.getPageContainer(page);
        if (pageEl) {
            pageEl.classList.remove('taro_page_shade');
            this.addAnimation(pageEl, pageNo === 0);
            (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
            this.navigationBarHandler.load();
            this.bindPageEvents(page, pageConfig);
            this.triggerRouterChange();
        }
        else {
            (_b = page.onLoad) === null || _b === void 0 ? void 0 : _b.call(page, param, () => {
                var _a;
                pageEl = this.getPageContainer(page);
                this.addAnimation(pageEl, pageNo === 0);
                (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
                this.navigationBarHandler.load();
                this.onReady(page, false);
                this.bindPageEvents(page, pageConfig);
                this.triggerRouterChange();
            });
        }
    }
    hide(page, animation = false) {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        if (!page)
            return;
        // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
        const pageEl = this.getPageContainer(page);
        if (pageEl) {
            if (animation) {
                if (this.hideTimer) {
                    clearTimeout(this.hideTimer);
                    this.hideTimer = null;
                    (_c = (_b = (_a = this.lastHidePage) === null || _a === void 0 ? void 0 : _a.classList) === null || _b === void 0 ? void 0 : _b.add) === null || _c === void 0 ? void 0 : _c.call(_b, 'taro_page_shade');
                }
                this.lastHidePage = pageEl;
                this.hideTimer = setTimeout(() => {
                    this.hideTimer = null;
                    pageEl.classList.add('taro_page_shade');
                }, this.animationDuration + this.animationDelay);
                (_d = page.onHide) === null || _d === void 0 ? void 0 : _d.call(page);
            }
            else {
                if (this.hideTimer) {
                    clearTimeout(this.hideTimer);
                    this.hideTimer = null;
                    (_g = (_f = (_e = this.lastHidePage) === null || _e === void 0 ? void 0 : _e.classList) === null || _f === void 0 ? void 0 : _f.add) === null || _g === void 0 ? void 0 : _g.call(_f, 'taro_page_shade');
                }
                (_h = page.onHide) === null || _h === void 0 ? void 0 : _h.call(page);
                pageEl.classList.add('taro_page_shade');
                this.lastHidePage = pageEl;
            }
        }
        else {
            setTimeout(() => this.hide(page), 0);
        }
    }
    addAnimation(pageEl, first = false) {
        if (!pageEl)
            return;
        if (this.animation && !first) {
            setTimeout(() => {
                pageEl.classList.add('taro_page_show');
                setTimeout(() => {
                    pageEl.classList.add('taro_page_stationed');
                }, this.animationDuration);
            }, this.animationDelay);
        }
        else {
            pageEl.classList.add('taro_page_show');
            pageEl.classList.add('taro_page_stationed');
        }
    }
    getPageContainer(page) {
        var _a;
        const path = page ? page === null || page === void 0 ? void 0 : page.path : (_a = Current.page) === null || _a === void 0 ? void 0 : _a.path;
        const id = path === null || path === void 0 ? void 0 : path.replace(/([^a-z0-9\u00a0-\uffff_-])/ig, '\\$1');
        if (page) {
            return document.querySelector(`.taro_page#${id}`);
        }
        const el = (id
            ? document.querySelector(`.taro_page#${id}`)
            : document.querySelector('.taro_page') ||
                document.querySelector('.taro_router'));
        return el;
    }
    getScrollingElement(page) {
        if (this.usingWindowScroll)
            return window;
        return this.getPageContainer(page) || window;
    }
    bindPageEvents(page, config = {}) {
        var _a;
        const scrollEl = this.getScrollingElement(page);
        const distance = config.onReachBottomDistance || ((_a = this.config.window) === null || _a === void 0 ? void 0 : _a.onReachBottomDistance) || 50;
        bindPageScroll(page, scrollEl, distance);
        bindPageResize(page);
    }
    triggerRouterChange() {
        /**
         * @tarojs/runtime 中生命周期跑在 promise 中,所以这里需要 setTimeout 延迟事件调用
         * TODO 考虑将生命周期返回 Promise,用于处理相关事件调用顺序
         */
        setTimeout(() => {
            eventCenter.trigger('__afterTaroRouterChange', {
                toLocation: {
                    path: this.pathname
                }
            });
        }, 0);
    }
}

const createStampId = incrementId();
let launchStampId = createStampId();
function createRouter(history, app, config, framework) {
    var _a, _b;
    if (typeof app.onUnhandledRejection === 'function') {
        window.addEventListener('unhandledrejection', app.onUnhandledRejection);
    }
    RouterConfig.config = config;
    const handler = new PageHandler(config, history);
    // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
    // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
    // 所以需要加一个锁来应对这个情况
    const pageLock = {};
    routesAlias.set(handler.router.customRoutes);
    const basename = handler.router.basename;
    const routes = handler.routes.map(route => {
        const routePath = addLeadingSlash(route.path);
        const paths = routesAlias.getAll(routePath);
        return {
            path: paths.length < 1 ? routePath : paths,
            action: route.load
        };
    });
    const router = new UniversalRouter(routes, { baseUrl: basename || '' });
    const launchParam = {
        path: handler.currentPage,
        query: handler.getQuery(launchStampId),
        scene: 0,
        shareTicket: '',
        referrerInfo: {}
    };
    eventCenter.trigger('__taroRouterLaunch', launchParam);
    (_a = app.onLaunch) === null || _a === void 0 ? void 0 : _a.call(app, launchParam);
    app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
    const render = (_c) => __awaiter(this, [_c], void 0, function* ({ location, action }) {
        var _d, _e, _f, _g, _h, _j, _k, _l;
        // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
        const currentPathname = decodeURI(location.pathname);
        if ((_d = window.__taroAppConfig) === null || _d === void 0 ? void 0 : _d.usingWindowScroll)
            window.scrollTo(0, 0);
        eventCenter.trigger('__taroRouterChange', {
            toLocation: {
                path: currentPathname
            }
        });
        let element, context, params;
        const routerPath = handler.router.forcePath || currentPathname;
        pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
        const currentLock = pageLock[routerPath];
        let postLock;
        try {
            const result = yield router.resolve(routerPath);
            [element, context, params] = yield Promise.all(result);
            postLock = pageLock[routerPath];
        }
        catch (error) {
            if (error.status === 404) {
                const notFoundEvent = {
                    isEntryPage: stacks.length === 0,
                    path: currentPathname,
                    query: handler.getQuery(createStampId()),
                };
                (_e = app.onPageNotFound) === null || _e === void 0 ? void 0 : _e.call(app, notFoundEvent);
                eventCenter.trigger('__taroRouterNotFound', notFoundEvent);
            }
            else if (/Loading hot update .* failed./.test(error.message)) {
                // NOTE: webpack5 与 prebundle 搭配使用时,开发环境下初次启动时偶发错误,由于 HMR 加载 chunk hash 错误,导致热更新失败
                window.location.reload();
            }
            else {
                throw error;
            }
        }
        if (!element || currentLock !== postLock)
            return;
        // Note: 异步结束后,在设置 handler.pathname
        // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
        handler.pathname = context.pathname;
        const { pathname, pageConfig } = handler;
        let enablePullDownRefresh = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.enablePullDownRefresh) || false;
        let navigationStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationStyle) || 'default';
        let navigationBarTextStyle = ((_h = config === null || config === void 0 ? void 0 : config.window) === null || _h === void 0 ? void 0 : _h.navigationBarTextStyle) || 'white';
        let navigationBarBackgroundColor = ((_j = config === null || config === void 0 ? void 0 : config.window) === null || _j === void 0 ? void 0 : _j.navigationBarBackgroundColor) || '#000000';
        if (pageConfig) {
            if (typeof pageConfig.enablePullDownRefresh === 'boolean') {
                enablePullDownRefresh = pageConfig.enablePullDownRefresh;
            }
            if (typeof pageConfig.navigationStyle === 'string') {
                navigationStyle = pageConfig.navigationStyle;
            }
            if (typeof pageConfig.navigationBarTextStyle === 'string') {
                navigationBarTextStyle = pageConfig.navigationBarTextStyle;
            }
            if (typeof pageConfig.navigationBarBackgroundColor === 'string') {
                navigationBarBackgroundColor = pageConfig.navigationBarBackgroundColor;
            }
        }
        eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
        const currentPage = Current.page;
        const methodName = (_k = stacks.method) !== null && _k !== void 0 ? _k : '';
        const cacheTabs = stacks.getTabs();
        let shouldLoad = false;
        stacks.method = '';
        if (methodName === 'reLaunch') {
            handler.unload(currentPage, stacks.length);
            // NOTE: 同时卸载缓存在tabs里面的页面实例
            for (const key in cacheTabs) {
                if (cacheTabs[key]) {
                    handler.unload(cacheTabs[key]);
                    stacks.removeTab(key);
                }
            }
            shouldLoad = true;
        }
        else if (currentPage && handler.isTabBar(pathname)) {
            if (handler.isSamePage(currentPage))
                return;
            if (handler.isTabBar(currentPage.path)) {
                // NOTE: 从 tabBar 页面切换到 tabBar 页面
                handler.hide(currentPage);
                stacks.pushTab(currentPage.path.split('?')[0]);
            }
            else if (stacks.length > 0) {
                const firstIns = stacks.getItem(0);
                if (handler.isTabBar(firstIns.path)) {
                    handler.unload(currentPage, stacks.length - 1, true);
                    stacks.pushTab(firstIns.path.split('?')[0]);
                }
                else {
                    handler.unload(currentPage, stacks.length, true);
                }
            }
            if (cacheTabs[pathname]) {
                stacks.popTab(pathname);
                return handler.show(stacks.getItem(0), pageConfig, 0);
            }
            shouldLoad = true;
        }
        else if (action === 'POP') {
            // NOTE: 浏览器事件退后多次时,该事件只会被触发一次
            const prevIndex = stacks.getPrevIndex(pathname);
            const delta = stacks.getDelta(pathname);
            // NOTE: Safari 内核浏览器在非应用页面返回上一页时,会触发额外的 POP 事件,此处需避免当前页面被错误卸载
            if (currentPage !== stacks.getItem(prevIndex)) {
                handler.unload(currentPage, delta, prevIndex > -1);
                if (prevIndex > -1) {
                    eventCenter.once('__taroPageOnShowAfterDestroyed', () => {
                        handler.show(stacks.getItem(prevIndex), pageConfig, prevIndex);
                    });
                }
                else {
                    shouldLoad = true;
                }
            }
        }
        else if (action === 'REPLACE') {
            const delta = stacks.getDelta(pathname);
            // NOTE: 页面路由记录并不会清空,只是移除掉缓存的 stack 以及页面
            handler.unload(currentPage, delta);
            shouldLoad = true;
        }
        else if (action === 'PUSH') {
            handler.hide(currentPage, true);
            shouldLoad = true;
        }
        if (shouldLoad || stacks.length < 1) {
            const el = (_l = element.default) !== null && _l !== void 0 ? _l : element;
            const loadConfig = Object.assign({}, pageConfig);
            const stacksIndex = stacks.length;
            delete loadConfig['path'];
            delete loadConfig['load'];
            let pageStampId = '';
            if (launchStampId) {
                pageStampId = launchStampId;
                launchStampId = '';
            }
            else {
                pageStampId = createStampId();
            }
            const page = createPageConfig(enablePullDownRefresh ? hooks.call('createPullDownComponent', el, pathname, framework, handler.PullDownRefresh, pageStampId) : el, pathname + stringify(handler.getQuery(pageStampId)), {}, loadConfig);
            if (params)
                page.options = params;
            handler.load(page, pageConfig, pageStampId, stacksIndex);
        }
    });
    const routePath = addLeadingSlash(stripBasename(history.location.pathname, handler.basename));
    if (routePath === '/') {
        history.replace(prependBasename(handler.homePage + history.location.search));
    }
    render({ location: history.location, action: Action.Push });
    (_b = app.onShow) === null || _b === void 0 ? void 0 : _b.call(app, launchParam);
    window.addEventListener('visibilitychange', () => {
        var _a, _b, _c, _d, _e, _f, _g;
        const currentPath = ((_a = Current.page) === null || _a === void 0 ? void 0 : _a.path) || '';
        const path = currentPath.substring(0, currentPath.indexOf('?'));
        const param = {};
        // app的 onShow/onHide 生命周期的路径信息为当前页面的路径
        Object.assign(param, launchParam, { path });
        if (document.visibilityState === 'visible') {
            (_b = app.onShow) === null || _b === void 0 ? void 0 : _b.call(app, param);
            // 单页面app显示后一刻会触发当前 page.onShow 生命周期函数
            (_d = (_c = Current.page) === null || _c === void 0 ? void 0 : _c.onShow) === null || _d === void 0 ? void 0 : _d.call(_c);
        }
        else {
            // 单页面app隐藏前一刻会触发当前 page.onHide 生命周期函数
            if ((_e = Current.page) === null || _e === void 0 ? void 0 : _e.path) {
                safeExecute((_f = Current.page) === null || _f === void 0 ? void 0 : _f.path, 'onHide');
            }
            (_g = app.onHide) === null || _g === void 0 ? void 0 : _g.call(app, param);
        }
    });
    return history.listen(render);
}

function handleAppMount(config, _, appId = config.appId || 'app') {
    let app = document.getElementById(appId);
    let isPosition = true;
    if (!app) {
        app = document.createElement('div');
        app.id = appId;
        isPosition = false;
    }
    const appWrapper = ((app === null || app === void 0 ? void 0 : app.parentNode) || (app === null || app === void 0 ? void 0 : app.parentElement) || document.body);
    app.classList.add('taro_router');
    if (!isPosition)
        appWrapper.appendChild(app);
    initNavigationBar(config, appWrapper);
}
function handleAppMountWithTabbar(config, history, appId = config.appId || 'app') {
    let app = document.getElementById(appId);
    let isPosition = true;
    if (!app) {
        app = document.createElement('div');
        app.id = appId;
        isPosition = false;
    }
    const appWrapper = ((app === null || app === void 0 ? void 0 : app.parentNode) || (app === null || app === void 0 ? void 0 : app.parentElement) || document.body);
    app.classList.add('taro_router');
    const container = document.createElement('div');
    container.classList.add('taro-tabbar__container');
    container.id = 'container';
    const panel = document.createElement('div');
    panel.classList.add('taro-tabbar__panel');
    panel.appendChild(app.cloneNode(true));
    container.appendChild(panel);
    if (!isPosition) {
        appWrapper.appendChild(container);
    }
    else {
        appWrapper.replaceChild(container, app);
    }
    initTabbar(config, history);
    initNavigationBar(config, container);
}

export { createMpaHistory, createMultiRouter, createRouter, getCurrentPages, handleAppMount, handleAppMountWithTabbar, history, isDingTalk, isWeixin, navigateBack, navigateTo, prependBasename, reLaunch, redirectTo, routesAlias, setHistory, setHistoryMode, setMpaTitle, setNavigationBarLoading, setNavigationBarStyle, setTitle, switchTab };