vue-router 如何实现支持外部链接
- 2022 年 8 月 05 日
本文字数:3344 字
阅读完需:约 11 分钟
前言
vue
项目中 不少场景会遇到外部链接
的情况 vue-router
官方 提供了扩展 RouterLink 的方式 封装成一个组件AppLink.vue. 但是这种扩展方案 存在以下问题
写法上 由
<router-link>
转变为<AppLink>
由于是封装的组件 就可能涉及到
style 样式
的作用域
不一样,可能会发生样式 失效项目需要额外 维护
AppLink.vue
于是就想到采取另一种方案 扩展源码
来解决以上问题 , 实现 扩展版vue-router
,同时还可以增强一下 vue-router,使其 支持 restful 风格的链接
以下为修改的核心源码
function queryToString(query) {
return ('?' +
Object.keys(query)
.map(key => {
const value = query[key];
if (value == null)
return '';
if (Array.isArray(value)) {
return value
.map(val => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`)
.join('&');
}
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
})
.filter(Boolean)
.join('&'));
}
function paramsToHref(to) {
const { path, params } = to;
const pathParams = Object.keys(params)
.reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});
const pathWithParams = path.replace(/\:(\w+)/g, (_, key) => {
const value = pathParams[key];
if (value == null)
return ':' + key;
if (Array.isArray(value)) {
return value
.map(val => encodeURIComponent(val))
.join('/');
}
return encodeURIComponent(value);
});
return `${pathWithParams}`;
}
function checkExternalLink(to) {
if (typeof to === 'string' && to.startsWith('http')) {
return { isExternalLink: true, href: to, isJavascript: false };
}
else if ((typeof to === 'string' && to.startsWith('javascript:')) || (typeof to.path === 'string' && to.path.startsWith('javascript:'))) {
return { isExternalLink: false, href: to, isJavascript: true };
}
else if (typeof to === 'object' && typeof to.path === 'string' && to.path.startsWith('http')) {
let path = typeof to.params === 'object' ? paramsToHref(to) : to.path;
let queryString = typeof to.query === 'object' ? queryToString(to.query) : '';
return { isExternalLink: true, href: path + queryString + (to.hash ? to.hash : ''), isJavascript: false };
}
return { isExternalLink: false, href: '', isJavascript: false };
}
const RouterLinkImpl = /*#__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);
const link = !isExternalLink && !isJavascript ? reactive(useLink(props)) : { href: href, isActive: false, isExactActive: false, route: '', navigate: () => Promise.resolve() };
const elClass = 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 () => {
const children = slots.default && slots.default(link);
return props.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 both
onClick: 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";
// 创建路由实例
export const router = createRouter({
history: createWebHistory(),
routes: [{
...
}]
}
});
//----------------
// 替换为以下代码
//----------------
/*
* 新代码
*/
import {
createRouter,
createWebHistory,
} from "@npkg/vue-router";
// 创建路由实例
export const router = createRouter({
history: createWebHistory(),
routes: [{
...
}]
}
});
/*
* 其他使用
*/
import { useRoute, useLink } from "@npkg/vue-router";
let router = useRouter()
router.push({path:'/'})
除了 Vue Router 原有用法,它还支持以下扩展写法
// 基础使用
<router-link to="/"></router-link>
<router-link to="/list"></router-link>
<router-link to="https://github.com/npm-pkg/vue-router"></router-link>
<router-link to="https://github.com/npm-pkg/vue-router?author=five-great"></router-link>
<router-link to="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>
版权声明: 本文为 InfoQ 作者【Five】的原创文章。
原文链接:【http://xie.infoq.cn/article/0a8a19044031d8f679c853213】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
Five
有事多研究,没事瞎琢磨 2022.08.02 加入
CSDN 前端领域优质创作者 , 博客专家认证。 退役ACMer, IT技术狂热爱好者 擅长领域,web前端,算法, 业务架构,可视化,富文本编辑器等。 github: https://github.com/Five-great
评论