protocols.uts 2.8 KB
Newer Older
DCloud-yyl's avatar
DCloud-yyl 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
import {
    APP_LAUNCH,
    NAVIGATE_TO,
    REDIRECT_TO,
    SWITCH_TAB,
    addLeadingSlash,
    findPageRoute,
    getNavigatorLockUrl,
    getTabBarIndex,
    parseUrl,
    setNavigatorLockUrl,
} from '@dcloudio/uni-runtime'

type NormalizeRouteOptionsResult = {
    errMsg: string
    url: string
}
export function normalizeRouteOptions(
    type: string,
    url: string,
): NormalizeRouteOptionsResult {
    if (url == null || url!.length == 0) {
        return {
            errMsg: `Missing required args: url`,
            url,
        } as NormalizeRouteOptionsResult
    }
    // 格式化为绝对路径路由
    url = normalizeRoute(url)
    const pagePath = parseUrl(url!).path
    const pageRoute = findPageRoute(pagePath)
    if (pageRoute == null) {
        return {
            errMsg: `page ${url} is not found`,
            url,
        } as NormalizeRouteOptionsResult
    }
    // 检测不同类型跳转
    const tabIndex = getTabBarIndex(url)
    if ((type == NAVIGATE_TO || type == REDIRECT_TO) && tabIndex !== -1) {
        return {
            errMsg: `can not ${type} a tabbar page`,
            url,
        } as NormalizeRouteOptionsResult
    } else if (type == SWITCH_TAB) {
        if (tabIndex == -1) {
            return {
                errMsg: `can not switch to no-tabBar page`,
                url,
            } as NormalizeRouteOptionsResult
        } else {
            // switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
            url = pagePath
        }
    }

    // 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
    if (getNavigatorLockUrl() == url && type != APP_LAUNCH) {
        return { errMsg: `${url} locked`, url } as NormalizeRouteOptionsResult
    }

    setNavigatorLockUrl(url)

    return { errMsg: '', url } as NormalizeRouteOptionsResult
}

function normalizeRoute(toRoute: string): string {
    if (toRoute.indexOf('/') == 0) {
        return toRoute
    }
    let fromRoute = ''
    const pages = getCurrentPages()
    if (pages.length > 0) {
        fromRoute = pages[pages.length - 1].route
    }
    return getRealRoute(fromRoute, toRoute)
}

function getRealRoute(fromRoute: string, toRoute: string): string {
    if (toRoute.indexOf('/') == 0) {
        return toRoute
    }
    if (toRoute.indexOf('./') == 0) {
        return getRealRoute(fromRoute, toRoute.slice(2))
    }
    const toRouteArray = toRoute.split('/')
    const toRouteLength = toRouteArray.length
    let i = 0
    for (; i < toRouteLength && toRouteArray[i] == '..'; i++) {
        // noop
    }
    toRouteArray.splice(0, i)
    toRoute = toRouteArray.join('/')
    const fromRouteArray = fromRoute.length > 0 ? fromRoute.split('/') : []
    fromRouteArray.splice(fromRouteArray.length - i - 1, i + 1)
    return addLeadingSlash(fromRouteArray.concat(toRouteArray).join('/'))
}