写点什么

vue-router 如何实现支持外部链接

作者:Five
  • 2022 年 8 月 05 日
  • 本文字数:3344 字

    阅读完需:约 11 分钟

vue-router 如何实现支持外部链接

前言

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>
复制代码


发布于: 2022 年 08 月 05 日阅读数: 43
用户头像

Five

关注

有事多研究,没事瞎琢磨 2022.08.02 加入

CSDN 前端领域优质创作者 , 博客专家认证。 退役ACMer, IT技术狂热爱好者 擅长领域,web前端,算法, 业务架构,可视化,富文本编辑器等。 github: https://github.com/Five-great

评论

发布
暂无评论
vue-router 如何实现支持外部链接_vue-router_Five_InfoQ写作社区