评论

给小程序添加跳转历史管理,自动辨别跳转是否是标签页

给小程序添加跳转历史管理,自动辨别跳转是否是标签页

给小程序添加跳转历史管理,自动辨别跳转是否是标签页,项目地址在

https://gitee.com/ngaiwa/kuak.git



/**
 * @author Fa
 * @copyright Fa 2017
 */
import { noop } from '../utils/function';
import { isObject } from '../utils/type';
import { toRelRootPathname } from '../utils/url';
import { config } from './config';


export class History implements Kuak.History {
    protected pages: Kuak.Page[];
    maxLimit: Kuak.History['maxLimit'];
    constructor(maxLimit: History['maxLimit']) {
        this.maxLimit = maxLimit;
        this.pages = [];
    }
    at(index: number) {
        return this.pages[index < 0 ? this.pages.length + index : index];
    }
    getByIndex(index: number): Kuak.Page | void {
        return this.pages[index];
    }
    getByPath(path: string): Kuak.Page[] {
        return this.pages.reduce(
            (found, page) => {
                if (page.is === found.path) {
                    found.pages.push(page);
                }
                return found;
            },
            {
                path: path,
                pages: [] as any[],
            },
        ).pages;
    }
    getById(id: string): Kuak.Page | void {
        const found = this.pages.find((page) => page.id === id);
        id = null as any;
        return found;
    }
    indexOf(page: Kuak.Page) {
        return this.pages.indexOf(page);
    }
    indexOfById(id: string) {
        const index = this.pages.findIndex((page) => page.id === id);
        id = null as any;
        return index;
    }
    back() {
        return App.router.navigateBack();
    }
    forward() {
        const currentPage = this.currentPage;
        const index = this.indexOf(currentPage);
        const nextIndex = index + 1;
        const page = this.getByIndex(nextIndex);
        if (page) {
            return navigateTo(App.router as any, { url: page.url }, page) as Promise;
        }
        return Promise.resolve();
    }
    /**
     * @deprecated
     */
    go(index: number): Promise {
        return Promise.resolve(index);
    }
    currentOpened!: Kuak.Page;
    currentShowed!: Kuak.Page;
    get currentPage() {
        const currentPages = this.currentPages;
        const currentPage = currentPages[currentPages.length - 1];
        if (!this.currentOpened) {
            this.currentOpened = currentPage;
        }
        return currentPage;
    }
    get currentPages() {
        return getCurrentPages();
    }
    get length() {
        return this.pages.length;
    }
    get currentLength() {
        return this.currentPages.length;
    }
    restoredPage?: Kuak.Page;
    onPagesChange(option: { page: Kuak.Page; isNew?: boolean; isOld?: boolean }) {
        const currentPage = this.currentPage;
        const page = option.page;
        if (page !== currentPage) {
            this.currentOpened = currentPage;
            if (!option.isNew) {
                this.currentShowed = currentPage;
            }
            return;
        }


        const currentOpened = this.currentOpened;
        this.currentOpened = page;
        if (option.isNew) {
            const restoredPage = this.restoredPage;
            const index = this.indexOf(restoredPage!);
            this.restoredPage = null as any;
            if (restoredPage && restoredPage.__h_redirect_unloaded__) {
                unloadPage(restoredPage.__h_redirect_unloaded__);
                restoredPage.__h_redirect_unloaded__ = null;
            }
            if (index !== -1) {
                // rejectTo or navigateBack
                this.pages[index] = page;
                return;
            }
            if (checkFirstPage(this, page)) {
                return;
            }
            if (this.pages.indexOf(page) === -1) {
                // navigateTo
                if (currentOpened !== page) {
                    const index = this.indexOf(currentOpened);
                    if (index !== -1 && index < this.pages.length - 1) {
                        const unloadedList = this.pages.splice(index + 1, this.pages.length);
                        unloadPages(unloadedList);
                    }
                }
                this.pages.push(page);
            }
            return;
        }
        checkFirstPage(this, page);
        this.currentOpened = page;
        if (currentPage !== this.currentShowed) {
            this.currentShowed = page;
        }
    }
    getInfo() {
        return {
            openedId: this.currentOpened?.id,
            id: this.currentPage?.id,
            idList: this.pages.map((page) => page.id),
            currentIdList: this.currentPages.map((page) => page.id),
        };
    }
}
const checkFirstPage = function (history: any, page: Kuak.Page) {
    const currentPages = history.currentPages;
    if (currentPages.length === 1 && page === currentPages[0]) {
        // reLaunch switchTab
        unloadPages(history.pages.splice(0));
        history.pages.push(page);
        return true;
    }
    return false;
};
const unloadPage = function (page: any) {
    if (page && !page.__unloaded__ && page.__h_canUnload__) {
        try {
            if (page.__h_onUnload__) {
                page.__h_onUnload__();
            } else if (page.onUnload) {
                page.onUnload();
            }
        } catch (e) {
            console.error('onUnload Error', e);
        }
        page.__unloaded__ = true;
    }
};
const unloadPages = function (pages: any[]) {
    for (let i = 0; i < pages.length; i++) {
        unloadPage(pages[i]);
    }
};
interface Router extends Kuak.NavRouter {
    __switchTab__: AnyFunction;
    __reLaunch__: AnyFunction;
    __redirectTo__: AnyFunction;
    __navigateTo__: AnyFunction;
    __navigateBack__: AnyFunction;
    navHistory: Kuak.History;
    __nav_fn_bound__: true;
}


const navResultHandler = function (
    result: Promise,
    option: { success?: AnyFunction; fail?: AnyFunction; complete?: AnyFunction; [n: string]: any },
    history?: Kuak.History,
    oldPage?: Kuak.Page,
    newPage?: Kuak.Page,
) {
    const { success, fail, complete } = option;
    if (success) {
        result.then(success).catch(noop);
    }
    if (fail) {
        result.catch(fail).catch(noop);
    }
    if (complete) {
        result.finally(complete).catch(noop);
    }
    if (history && newPage) {
        result
            .catch((res: any) => {
                console.warn(res);
                if (history!.restoredPage === newPage) {
                    history!.restoredPage = null as any;
                    replacePage(history!, newPage!, oldPage!);
                }
            })
            .finally(() => {
                history = newPage = oldPage = null as any;
            });
    } else {
        result.catch(console.warn);
    }
    return result;
};
const replacePage = function (history: Kuak.History, page: Kuak.Page, newPage: Kuak.Page) {
    if (!newPage) {
        return;
    }
    const index = history.indexOf(page);
    if (index !== -1) {
        (history as any).pages[index] = newPage;
    }
};
const callNavFunc = function (func: AnyFunction, option: any) {
    return new Promise((success, fail) => {
        func({ ...option, success, fail, complete: null });
        func = option = null as any;
    });
};
const isTabPage = function (router: any, option: any) {
    return config.tabPagePaths.includes(
        option.pathname || toRelRootPathname(option.url, router.dir),
    );
};
const redirectPage = function (router: Router, option: any, newPage: any, oldPage?: any) {
    if (isTabPage(router, option)) {
        return router.switchTab(option);
    }
    const history = router.navHistory;
    oldPage = oldPage || history.currentPage;
    replacePage(history, history.currentPage, newPage);
    history.restoredPage = newPage;
    return navResultHandler(
        callNavFunc(router.__redirectTo__, option),
        option,
        history,
        oldPage,
        newPage,
    );
};
const navigateTo = function (router: Router, option: { url: string }, restoredPage: any) {
    if (isTabPage(router, option)) {
        return router.switchTab(option);
    }
    const history = router.navHistory;
    const currentPages = history.currentPages;
    const currentPage = currentPages[currentPages.length - 1];
    const max = history.maxLimit[currentPage?.renderer as 'skyline'] || history.maxLimit.webview;
    if (currentPages.length >= max) {
        return redirectPage(router, option, restoredPage);
    } else {
        history.restoredPage = restoredPage;
        return navResultHandler(callNavFunc(router.__navigateTo__, option), option, history);
    }
};
const toUrlOption = function (option: any) {
    return isObject(option) ? option : { url: option };
};
const toDeltaOption = function (option: any) {
    return isObject(option) ? option : { delta: option };
};
const routerFn: Router = {
    redirectTo(option: any) {
        option = toUrlOption(option);
        return redirectPage(this, option, {
            __h_redirect_unloaded__: this.navHistory.currentPage,
        });
    },
    navigateTo(option: any) {
        return navigateTo(this, toUrlOption(option), null);
    },
    navigateBack(option?: any) {
        const _option = toDeltaOption(option);
        const delta = Math.abs(+_option.delta || 1);
        const history = this.navHistory;
        const currentPages = history.currentPages;
        const currentPage = currentPages[currentPages.length - 1];
        const backPage = history.getByIndex(history.indexOf(currentPage) - delta);
        const currentBackPage = currentPages[currentPages.indexOf(currentPage) - delta];
        if (!backPage || backPage === currentPage) {
            return navResultHandler(Promise.resolve(), _option);
        }
        if (backPage !== currentBackPage) {
            if (isTabPage(this, backPage)) {
                return this.switchTab({ url: backPage.url });
            }
            return redirectPage(this, { ...option, url: backPage.url }, backPage, backPage);
        }
        return navResultHandler(
            callNavFunc(this.__navigateBack__, { ..._option, delta: delta }),
            _option,
        );
    },
    reLaunch(option: any) {
        return callNavFunc(this.__reLaunch__, toUrlOption(option));
    },
    switchTab(option: any) {
        return callNavFunc(this.__switchTab__, toUrlOption(option));
    },
    __nav_fn_bound__: true,
} as Router;
export const navFnHandler = function (router: Kuak.NavRouter, history?: Kuak.History) {
    if ((router as any).__nav_fn_bound__) {
        return router;
    }
    (router as any).navHistory = history || App.history;
    return Object.assign(
        router,
        {
            __navigateBack__: router.navigateBack,
            __navigateTo__: router.navigateTo,
            __redirectTo__: router.redirectTo,
            __reLaunch__: router.reLaunch,
            __switchTab__: router.switchTab,
        },
        routerFn,
    );
};
export const boundRouter = function (
    page: Kuak.Page,
    router: Kuak.Page['router'],
    history?: Kuak.History,
) {
    router = navFnHandler(router, history);
    if (page.router && page.router !== router) {
        page.router = router;
    }
    if (page.pageRouter && page.pageRouter !== router) {
        page.pageRouter = router;
    }
};



最后一次编辑于  01-17  
点赞 0
收藏
评论
登录 后发表内容