93 lines
2.7 KiB
TypeScript
93 lines
2.7 KiB
TypeScript
import type { ComputedRef, MaybeRefOrGetter } from 'vue'
|
|
import { isLinkExternal, isLinkWithProtocol } from '@vuepress/helper/client'
|
|
import { computed, toValue } from 'vue'
|
|
import { resolveRoute, resolveRouteFullPath, useRoute } from 'vuepress/client'
|
|
import { useData } from './data.js'
|
|
|
|
interface UseLinkResult {
|
|
/**
|
|
* 外部链接
|
|
*/
|
|
isExternal: ComputedRef<boolean>
|
|
/**
|
|
* 外部链接协议
|
|
* 此项不包含 target="_blank" 的情况
|
|
*/
|
|
isExternalProtocol: ComputedRef<boolean>
|
|
link: ComputedRef<string | undefined>
|
|
}
|
|
|
|
export function useLink(
|
|
href: MaybeRefOrGetter<string | undefined>,
|
|
target?: MaybeRefOrGetter<string | undefined>,
|
|
): UseLinkResult {
|
|
const route = useRoute()
|
|
const { page } = useData()
|
|
|
|
// 预判断是否可以直接认为是外部链接
|
|
// 在此时并不能完全确认是否一定是内部链接
|
|
const maybeIsExternal = computed(() => {
|
|
const link = toValue(href)
|
|
const rawTarget = toValue(target)
|
|
if (!link)
|
|
return false
|
|
if (rawTarget === '_blank' || isLinkExternal(link))
|
|
return true
|
|
return false
|
|
})
|
|
|
|
// 预处理链接,尝试转为内部的链接
|
|
const preProcessLink = computed(() => {
|
|
const link = toValue(href)
|
|
if (!link || maybeIsExternal.value)
|
|
return link
|
|
|
|
const currentPath = page.value.filePathRelative ? `/${page.value.filePathRelative}` : undefined
|
|
const path = resolveRouteFullPath(link, currentPath)
|
|
if (path.includes('#')) {
|
|
// 将路径 + 锚点 与 当前路由路径进行比较
|
|
// 转为锚点链接,避免页面发生刷新
|
|
if (path.slice(0, path.indexOf('#')) === route.path) {
|
|
return path.slice(path.indexOf('#'))
|
|
}
|
|
}
|
|
return path
|
|
})
|
|
|
|
const isExternal = computed(() => {
|
|
const link = preProcessLink.value
|
|
if (maybeIsExternal.value)
|
|
return true
|
|
|
|
if (!link || link[0] === '#')
|
|
return false
|
|
|
|
// 判断是否为不存在的路由
|
|
const routePath = link.split(/[?#]/)[0]
|
|
const currentPath = page.value.filePathRelative ? `/${page.value.filePathRelative}` : undefined
|
|
const { notFound } = resolveRoute(routePath, currentPath)
|
|
|
|
if (__VUEPRESS_DEV__)
|
|
notFound && console.warn(`[VuePress Dead Link] "${toValue(href)}" is not found in (${page.value.filePathRelative || page.value.path})`)
|
|
|
|
return notFound
|
|
})
|
|
|
|
const link = computed(() => {
|
|
// 外部链接保持原样
|
|
if (isExternal.value) {
|
|
return toValue(href)
|
|
}
|
|
return preProcessLink.value
|
|
})
|
|
|
|
const isExternalProtocol = computed(() => {
|
|
if (!link.value || link.value[0] === '#')
|
|
return false
|
|
|
|
return isLinkWithProtocol(link.value)
|
|
})
|
|
|
|
return { isExternal, isExternalProtocol, link }
|
|
}
|