接到一个需求:点击页面链接时按住 Ctrl
按键则以新窗口形式打开该链接,原页面不进行跳转,这个需求比较棒,它保证了页面跳转时的灵活性。
分析功能点
- 需要获取到当前被按下的按键;
- 然后在链接跳转的时候判断是否以新窗口打开。
这个需求实现的重点是在何处添加判断是否以新窗口打开
的代码,比如在每个链接点击的地方加入逻辑判断,这是最差的实现,因为这种方法改动点很大,而且无法自动兼容新链接的添加。然后可能想到的是拦截 $router.push
行为,或者封装一个自定义指令,再在合适的地方添加指令,这些都是不是很好的实现方式,我们应该考虑如何以最小的改动并且向后兼容,那就是在 全局的 beforeEach 路由守卫
中添加逻辑。
记录键盘的按键
我们需要维护一个记载当前按键的数据,用来帮助我们判断 Ctrl
键是否按下。
首先我们在项目中维护公共函数的地方新建一个 keyboard.js
文件。
const keys = {}
export function addKeyboardKey (e) {
// 别用已经废弃的 keycode 字段
keys[e.key] = true
}
export function removeKeyboardKey (e) {
delete keys[e.key]
}
export function isCtrlPress(e) {
return keys['Control']
}
然后寻找一个合适的地方添加键盘的事件监听,比如在 App.vue
的 created
中。
// 下面只展示需求相关代码
import { removeKeyboardKey, addKeyboardKey } from '@/utils/keyboard'
export default {
created () {
// 添加监听
window.addEventListener('keydown', addKeyboardKey)
window.addEventListener('keyup', removeKeyboardKey)
// 记住添加事件和卸载事件总是成对存在
this.$once('hook:beforeDestroy', () => {
window.removeEventListener('keydown', addKeyboardKey)
window.removeEventListener('keyup', removeKeyboardKey)
})
}
}
至此我们已经完成了记录页面中的当前按下按键。
修改页面的跳转行为
我们在路由的全局守卫 beforeEach
中添加控制的代码。
// 下面只展示需求相关代码
import { isCtrlPress } from '@/utils/keyboard'
// 这里省略了router的创建,router是VueRouter的实例
router.beforeEach((to, from, next) => {
// 在每次路由跳转的时候进行判断
if (isCtrlPress()) {
// 如果 ctrl 按键被按下,则以新窗口打开目标页面
window.open('#' + to.fullPath)
// 并阻止当前页面的跳转
return next(false)
}
// 其他的代码,注意保证next至少和至多被调用一次
// ...
}
现在我们就已经完成了点击页面链接时按住 Ctrl
按键则以新窗口形式打开该页面 😀。
文章首发在我的个人博客,原文链接,欢迎转载,转载请注明出处 😀。