前言
vue
项目中 不少场景会遇到外部链接
的情况 vue-router
官方 提供了扩展RouterLink 的方式 封装成一个组件AppLink.vue. 但是这种扩展方案 存在以下问题
- 写法上 由
<router-link>
转变为<AppLink>
- 由于是封装的组件 就可能涉及到
style 样式
的作用域
不一样,可能会发生样式 失效 - 项目需要额外 维护
AppLink.vue
于是就想到采取另一种方案 扩展源码
来解决以上问题 , 实现 扩展版vue-router
,同时还可以增强一下 vue-router,使其 支持 restful 风格的链接
以下为修改的核心源码
functionqueryToString(query) { return ('?'+Object.keys(query) .map(key=> { constvalue=query[key]; if (value==null) return''; if (Array.isArray(value)) { returnvalue .map(val=>`${encodeURIComponent(key)}=${encodeURIComponent(val)}`) .join('&'); } return`${encodeURIComponent(key)}=${encodeURIComponent(value)}`; }) .filter(Boolean) .join('&')); } functionparamsToHref(to) { const { path, params } =to; constpathParams=Object.keys(params) .reduce((acc, key) => { acc[key] =params[key]; returnacc; }, {}); constpathWithParams=path.replace(/:(\w+)/g, (_, key) => { constvalue=pathParams[key]; if (value==null) return':'+key; if (Array.isArray(value)) { returnvalue .map(val=>encodeURIComponent(val)) .join('/'); } returnencodeURIComponent(value); }); return`${pathWithParams}`; } functioncheckExternalLink(to) { if (typeofto==='string'&&to.startsWith('http')) { return { isExternalLink: true, href: to, isJavascript: false }; } elseif ((typeofto==='string'&&to.startsWith('javascript:')) || (typeofto.path==='string'&&to.path.startsWith('javascript:'))) { return { isExternalLink: false, href: to, isJavascript: true }; } elseif (typeofto==='object'&&typeofto.path==='string'&&to.path.startsWith('http')) { letpath=typeofto.params==='object'?paramsToHref(to) : to.path; letqueryString=typeofto.query==='object'?queryToString(to.query) : ''; return { isExternalLink: true, href: path+queryString+ (to.hash?to.hash : ''), isJavascript: false }; } return { isExternalLink: false, href: '', isJavascript: false }; } constRouterLinkImpl=/*#__PURE__*/defineComponent({ name: 'RouterLink', props: { to: { type: [String, Object], required: true, }, replace: Boolean, activeClass: String, // inactiveClass: String,exactActiveClass: String, custom: Boolean, ariaCurrentValue: { type: String, default: 'page', }, }, useLink, setup(props, { slots }) { const { options } =inject(routerKey); const { isExternalLink, href, isJavascript } =checkExternalLink(props.to); constlink=!isExternalLink&&!isJavascript?reactive(useLink(props)) : { href: href, isActive: false, isExactActive: false, route: '', navigate: () =>Promise.resolve() }; constelClass=computed(() => ({ [getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive, // [getLinkClass(// props.inactiveClass,// options.linkInactiveClass,// 'router-link-inactive'// )]: !link.isExactActive, [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive, })); return () => { constchildren=slots.default&&slots.default(link); returnprops.custom?children : !isExternalLink?h('a', { 'aria-current': link.isExactActive?props.ariaCurrentValue : null, href: link.href, // this would override user added attrs but Vue will still add// the listener so we end up triggering bothonClick: link.navigate, class: elClass.value, }, children) : h('a', { href: link.href, target: !isJavascript?"_blank" : null, class: elClass.value, }, children); }; }, });
扩展版vue-router
vue2.0 的项目 详解可见 @npm-pkg/vue-router vue3.0 的项目 详解可见 @npkg/vue-router@next
扩展版vue-router
扩展支持自动跳转到外部链接
快速上手
- 通过CDN:
<script src="https://unpkg.com/@npkg/vue-router@next"></script>
- 将其添加到现有的Vue项目中:
npm install @npkg/vue-router@next | yarn add @npkg/vue-router@next
用法
将所有引用
vue-router
的地方用@npkg/vue-router
去替代
创建路由实例
//# /src/router/index.js/* * 原代码 */import { createRouter, createWebHistory, } from"vue-router"; // 创建路由实例exportconstrouter=createRouter({ history: createWebHistory(), routes: [{ }] } }); //----------------// 替换为以下代码//----------------/* * 新代码 */import { createRouter, createWebHistory, } from"@npkg/vue-router"; // 创建路由实例exportconstrouter=createRouter({ history: createWebHistory(), routes: [{ }] } }); /* * 其他使用 */import { useRoute, useLink } from"@npkg/vue-router"; letrouter=useRouter() router.push({path:'/'})
除了 Vue Router 原有用法,它还支持以下扩展写法
// 基础使用 <router-linkto="/"></router-link><router-linkto="/list"></router-link><router-linkto="https://github.com/npm-pkg/vue-router"></router-link><router-linkto="https://github.com/npm-pkg/vue-router?author=five-great"></router-link><router-linkto="https://github.com/npm-pkg/vue-router/tree/v4.0.15#readme"></router-link>//高级使用 restful 风格 <router-link:to="{path: '/'}"></router-link><router-link:to="{path: '/list'}"></router-link><router-link:to="{path:'https://github.com/npm-pkg/vue-router'}"></router-link><router-link:to="{path:'https://github.com/npm-pkg/vue-router', query:{author: 'five-great'}}"></router-link><router-link:to="{path:'https://github.com/npm-pkg/vue-router/tree/v4.0.15',hash:'#readme'}"></router-link><router-link:to="{path:'https://github.com/:org/:repo',params:{org:'npm-pkg',repo: 'vue-router'}}"></router-link><router-link:to="{path:'https://github.com/:org/:repo/tree/:v',query:{author: 'five-great'},params:{org:'npm-pkg',repo: 'vue-router',v:'v4.0.15'},hash:'#readme'}"></router-link>