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

简介: vue项目中 不少场景会遇到外部链接的情况 vue-router官方 提供了扩展RouterLink 的方式 封装成一个组件AppLink.vue. 但是这种扩展方案 存在以下问题• 写法上 由 <router-link> 转变为 <AppLink>• 由于是封装的组件 就可能涉及到 style 样式的 作用域 不一样,可能会发生样式 失效• 项目需要额外 维护 AppLink.vue于是就想到采取另一种方案 扩展源码 来解决以上问题 , 实现 扩展版vue-router ,同时还可以增强一下 vue-router,使其 支持 restful 风格的链接

前言

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>
目录
相关文章
|
4月前
|
JavaScript 前端开发 数据安全/隐私保护
Vue3——如何实现页面访问拦截
Vue3——如何实现页面访问拦截
|
JavaScript 前端开发
前端经典面试题 | Vue组件间的通信方式
前端经典面试题 | Vue组件间的通信方式
|
1月前
|
存储 JavaScript 容器
【Vue面试题十一】、Vue组件之间的通信方式都有哪些?
这篇文章介绍了Vue中组件间通信的8种方式,包括`props`传递、`$emit`事件触发、`ref`、`EventBus`、`$parent`或`$root`、`attrs`与`listeners`、`provide`与`inject`以及`Vuex`,以解决不同关系组件间的数据共享问题。
|
2月前
|
前端开发 JavaScript Java
前端 JS 经典:如何实现私有字段
前端 JS 经典:如何实现私有字段
19 1
|
4月前
|
JavaScript 前端开发 API
【前端--Vue】组件之间的多种通信方式,一文彻底搞懂组件通信!
【前端--Vue】组件之间的多种通信方式,一文彻底搞懂组件通信!
【前端--Vue】组件之间的多种通信方式,一文彻底搞懂组件通信!
|
4月前
|
前端开发 API SEO
vue-router原理以及两种模式区别
vue-router原理以及两种模式区别
29 1
|
4月前
|
JavaScript
请提供一个具体的示例代码,展示如何使用Vue异步组件技术实现路由懒加载。
请提供一个具体的示例代码,展示如何使用Vue异步组件技术实现路由懒加载。
22 0
|
4月前
|
JavaScript
uniapp 跳转外部链接
uniapp 跳转外部链接
121 0
|
JSON JavaScript 中间件
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
260 2
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
|
4月前
|
移动开发 前端开发 JavaScript
推荐几个vue3开源二次封装框架【收藏起来以后一定用的到】
推荐几个vue3开源二次封装框架【收藏起来以后一定用的到】
210 0