惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MyScale Blog
MyScale Blog
量子位
宝玉的分享
宝玉的分享
爱范儿
爱范儿
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
Apple Machine Learning Research
Apple Machine Learning Research
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
Simon Willison's Weblog
Simon Willison's Weblog
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
aimingoo的专栏
aimingoo的专栏
Cloudbric
Cloudbric
Blog — PlanetScale
Blog — PlanetScale
Latest news
Latest news
S
Security @ Cisco Blogs
Last Week in AI
Last Week in AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Vercel News
Vercel News
W
WeLiveSecurity
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
P
Proofpoint News Feed
P
Palo Alto Networks Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
The Blog of Author Tim Ferriss
腾讯CDC
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Stack Overflow Blog
Stack Overflow Blog
IT之家
IT之家
有赞技术团队
有赞技术团队
Microsoft Security Blog
Microsoft Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
美团技术团队
博客园 - 【当耐特】
D
DataBreaches.Net
I
InfoQ
G
GRAHAM CLULEY
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog

博客园 - Liaofy

前端新范式:用 AI 提效开发,用 E2E 保证迭代质量 把SPA的加载速度提升一倍,有没有搞头? 使用mumu模拟器抓包 andriod app Vue3 路由优化,使页面初次渲染效率翻倍 【eslint 插件开发】禁用 location 跳转外部链接 vue 项目使用 charles 代理线上页面到本地后显示404 避免使用单个数字作为对象的key 高扩展弹出层组件设计实现(H5&小程序) 轻松搞懂POST与PUT的区别 vite(or rollup) 实现 webpackChunkName webapp项目架构畅想(vue3).md vite试玩:老项目启动从6分钟到秒开 修剪AST树减少webapck打包尺寸 【uniapp】改善中大型uniapp小程序项目开发体验 vscode 调试 webpack 打包 5分钟,搞清 Unicode 与 UTF-8 的区别 deAsync.js 真正让异步变同步 盘的转——使用缓动函数完成动画 多个请求间断失败,如何优雅处理?
如何在本地给 vue-router4 扩展功能?
Liaofy · 2023-08-14 · via 博客园 - Liaofy

背景

前段时间给基于 vue3 的 H5 项目做一些优化,该项目经常会有一些页面间的通信,譬如选择地址、乘机人等信息后回填到上一个页面。对于这种简单、频繁的通信,实在不想搞成重火力(eg:pinia)。最好让使用者用完即走,不用操心除业务逻辑之外的任何事情。

路由控制页面通信

既然是页面间的通信,那么使用路由来控制是非常自然的,具体使用方式如下:

// A 页面跳转 B 页面时,传递 callback 回调函数
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({
  path: '/some/page/b',
  callback: dataFromB => {
    handleData(dataFromB)
  }
})

// B 页面,在某个时机(提交时)调用 callback,再返回 A 页面
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const address = {}
const tapSubmit = () => {
  if (route.callback) route.callback(address)
  router.back()
}

可以看到,我们通过熟悉的回调函数方式实现了页面间的数据通信。对使用者来说,几乎没有增加心智负担。

唯一的限制是:A 页面必须被keepAlive显然这是合理的,难道阁下希望回到 A 页面时,数据全部重新渲染一次?

处理 vue-router 类型限制

vue-router 4版本通过typescript严格限制了其参数类型,callback可不在其参数类型声明里面。直接使用上述方案,只会得到红线警告以及编译错误

所以,我们要在【本地】扩展vue-router的接口。

首先增加 callback 参数类型

新建vue-router.d.ts类型声明文件,为接口RouteLocationNormalizedLoaded增加callback字段。

import 'vue-router'

declare module 'vue-router' {
  // for router
  interface LocationAsRelativeRaw {
    callback?: anyFn
  }
  // for route
  interface RouteLocationNormalizedLoaded {
    callback?: anyFn
  }
}

其次重写 vue-router

通过重写useRouteuseRouter,处理生产和消费callback的逻辑:

// src/lib/vue-router/index.ts
import { anyFn } from '@/@types'
import {
  useRouter as rawUseRouter,
  useRoute as rawUseRoute,
  useLink,
  RouteLocationRaw,
  createRouter,
  createWebHistory,
  onBeforeRouteLeave,
  onBeforeRouteUpdate,
  isNavigationFailure,
} from '../../../node_modules/vue-router'

export {
  useRouter,
  useRoute,
  useLink,
  createRouter,
  createWebHistory,
  onBeforeRouteLeave,
  onBeforeRouteUpdate,
  isNavigationFailure,
}

const map: Record<string, anyFn | undefined> = {}

function useRoute() {
  const route = rawUseRoute()

  route.callback = map[route.path]

  return route
}

function useRouter() {
  const router = rawUseRouter()
  const newRouter = {
    ...router,
    push(to: RouteLocationRaw) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const opts = to as any

      if (map[opts.path]) map[opts.path] = void 0
      if (typeof opts === 'object' && opts.callback) {
        map[opts.path] = opts.callback
      }

      return router.push(opts)
    },
  }

  return newRouter
}

最后更改项目解析vue-router的地址

一般情况下,我们在项目中这样导入:import {} from vue-router。当 vite 构建项目时,会将其引用地址解析到node_modules中。所以,我们还需要更改这个地址解析流程,使其能够解析到我们自建的src/lib/vue-router/index.ts文件中。

好在 vite 已经提供了这个能力:

// vite.config.ts

{
  resolve: {
    alias: [
      //... 其他配置
      {
        find: /^vue-router$/,
        replacement: pathResolve('src/lib/vue-router/index.ts'),
      },
    ]
  }
}

完。