vue 2 升級 3 過程中 vue-router 的變化

參考
Vue Router v4 已準備好為您的 Vue 3 應(yīng)用程序帶來最好的路由祠丝,包括改進的包大小、TypeScript 集成抓艳、新功能和現(xiàn)代應(yīng)用程序的一致性改進住涉。(hui 項目當(dāng)前依賴 vue-router@3.5.0)

在 Vue Router API 從 v3(Vue2)到 v4(Vue3)的重寫過程中癞揉,大部分的 Vue Router API 都沒有變化阅束,但是在遷移你的程序時细疚,你可能會遇到一些破壞性的變化躁垛。

破壞性變化

  1. new Router 變成 createRouter

Vue Router 不再是一個類犁柜,而是一組函數(shù)≈摒現(xiàn)在你不用再寫 new Router(),而是要調(diào)用 createRouter:

// 以前是
// import Router from 'vue-router'
// router = new Router(opts);
import { createRouter } from 'vue-router'

const router = createRouter({
  // ...
})
  1. 新的 history 配置取代 mode

mode: 'history' 配置已經(jīng)被一個更靈活的 history 配置所取代馋缅。根據(jù)你使用的模式扒腕,你必須用適當(dāng)?shù)暮瘮?shù)替換它:

  • "history": createWebHistory()
  • "hash": createWebHashHistory()
  • "abstract": createMemoryHistory()
    下面是一個完整的代碼段:
// {
//    routes: [],
//    mode: "hash"
// }

import { createRouter, createWebHistory } from 'vue-router'
// 還有 createWebHashHistory 和 createMemoryHistory

createRouter({
  history: createWebHistory(),
  routes: [],
})
  1. 移動了 base 配置

現(xiàn)在,base 配置被作為 createWebHistory (其他 history 也一樣)的第一個參數(shù)傳遞:

// {
//    routes: [],
//    base: "/"
// }

import { createRouter, createWebHistory } from 'vue-router'
createRouter({
  history: createWebHistory('/base-directory/'),
  routes: [],
})
  1. 刪除了 fallback 屬性

創(chuàng)建路由時不再支持 fallback 屬性:

-new VueRouter({
+createRouter({
-  fallback: false,
// other options...
})

原因: Vue支持的所有瀏覽器都支持 HTML5 History API萤悴,因此我們不再需要使用 location.hash瘾腰,而可以直接使用 history.pushState()

5.刪除了 (星標或通配符)路由
現(xiàn)在必須使用自定義的 regex 參數(shù)來定義所有路由(
覆履、/*):

6.將 onReady 改為 isReady

// 將
router.onReady(onSuccess, onError)
// 替換成
router.isReady().then(onSuccess).catch(onError)
// 或者使用 await:
try {
  await router.isReady()
  // 成功
} catch (err) {
  // 報錯
}
  1. scrollBehavior 的變化

scrollBehavior 中返回的對象與 ScrollToOptions 類似:x 改名為 left蹋盆,y 改名為 top

// scrollBehavior: () => ({ x: 0, y: 0 })

8.<router-view>、<keep-alive> 和 <transition>
transition 和 keep-alive 現(xiàn)在必須通過 v-slot API 在 RouterView 內(nèi)部使用:

<!--  <keep-alive>
   <router-view></router-view>
</keep-alive> -->

<router-view v-slot="{ Component }">
  <transition>
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </transition>
</router-view>
  1. 刪除 <router-link> 中的 append 屬性
    <router-link> 中的 append 屬性已被刪除硝全。你可以手動將值設(shè)置到現(xiàn)有的 path 中:
將
<router-link to="child-route" append>to relative child</router-link>
替換成
<router-link :to="append($route.path, 'child-route')">
  to relative child
</router-link>

你必須在 App 實例上定義一個全局的 append 函數(shù):

app.config.globalProperties.append = (path, pathToAppend) =>
  path + (path.endsWith('/') ? '' : '/') + pathToAppend

原因:append 使用頻率不高栖雾,用戶可以很容易地實現(xiàn)。

  1. 刪除 <router-link> 中的 event 和 tag 屬性
    <router-link> 中的 eventtag 屬性都已被刪除伟众。你可以使用 v-slot API 來完全定制 <router-link>
將
<router-link to="/about" tag="span" event="dblclick">About Us</router-link>
替換成
<router-link to="/about" custom v-slot="{ navigate }">
  <span @click="navigate" @keypress.enter="navigate" role="link">About Us</span>
</router-link>

原因:這些屬性經(jīng)常一起使用岩灭,以使用與 <a> 標簽不同的東西,但這些屬性是在 v-slot API 之前引入的赂鲤,并且沒有足夠的使用噪径,因此沒有足夠的理由為每個人增加 bundle 包的大小。

  1. 刪除 <router-link> 中的 exact 屬性
    exact 屬性已被刪除数初,因為不再存在要修復(fù)的警告找爱,所以你應(yīng)該能夠安全地刪除它。但泡孩,有兩件事你應(yīng)該注意:
  • 路由現(xiàn)在是基于它們所代表的路由記錄來激活的车摄,而不是路由地址對象及其 pathqueryhash 屬性來激活的
  • 只匹配 path 部分仑鸥,queryhash 不再考慮

如果你想自定義這種行為吮播,例如考慮到 hash 部分,你應(yīng)該使用 v-slot API 來擴展<router-link>眼俊。

  1. 忽略 mixins 中的導(dǎo)航守衛(wèi)
    目前不支持 mixins 中的導(dǎo)航守衛(wèi)意狠,你可以在 vue-router#454 追蹤它的支持情況。

  2. 刪除 router.match 改為 router.resolve

router.matchrouter.resolve 已合并到 router.resolve 中疮胖,簽名略有不同环戈。

返回路由地址標準化版本闷板。還包括一個包含任何現(xiàn)有 basehref 屬性。

函數(shù)簽名:

resolve(to: RouteLocationRaw): RouteLocation & {
  href: string
}

原因:將用于同一目的的多種方法統(tǒng)一起來院塞。

  1. 刪除 router.getMatchedComponents()
    router.getMatchedComponents 方法現(xiàn)在被刪除遮晚,因為匹配的組件可以從 router.currentRoute.value.matched 中獲取:
router.currentRoute.value.matched.flatMap(record =>
  Object.values(record.components)
)

原因:這個方法只在 SSR 中使用拦止,并且是用戶一行就能完成的操作县遣。

  1. 所有的導(dǎo)航現(xiàn)在都是異步的

所有的導(dǎo)航,包括第一個導(dǎo)航汹族,現(xiàn)在都是異步的艺玲,這意味著,如果你使用一個 transition鞠抑,你可能需要等待路由 ready 好后再掛載程序:

app.use(router)
// 注意:在服務(wù)器端饭聚,你需要手動跳轉(zhuǎn)到初始地址。
router.isReady().then(() => app.mount('#app'))

否則會有一個初始過渡搁拙,就像你提供了 appear 屬性到 transition 一樣秒梳,因為路由會顯示它的初始地址(什么都沒有),然后顯示第一個地址箕速。

請注意酪碘,如果在初始導(dǎo)航時有導(dǎo)航守衛(wèi),你可能不想阻止程序渲染盐茎,直到它們被解析兴垦,除非你正在進行服務(wù)器端渲染。否則字柠,在這種情況下探越,不等待路由準備好掛載應(yīng)用會產(chǎn)生與 Vue2 中相同的結(jié)果。

  1. 刪除 router.app

router.app 用于表示注入路由的最后一個根組件(Vue 實例)窑业。Vue Router 現(xiàn)在可以被多個 Vue 程序同時安全使用钦幔。你仍然可以在使用路由時添加它:

app.use(router)
router.app = app

你也可以擴展 Router 接口的 TypeScript 定義來添加 app 屬性。

原因:Vue3 寫的程序不能在 Vue2 中使用常柄,現(xiàn)在我們使用同一個 Router 實例來支持多個程序鲤氢,因此擁有 app 屬性可能會產(chǎn)生誤導(dǎo),因為它是程序而不是根實例西潘。

  1. 將內(nèi)容傳遞給路由組件的 <slot>
    之前你可以直接傳遞一個模板卷玉,通過嵌套在 <router-view> 組件下,由路由組件的 <slot> 來渲染:
<router-view>
  <p>In Vue Router 3, I render inside the route component</p>
</router-view>

由于 <router-view> 引入了 v-slot API喷市,你必須使用 v-slot API 將其傳遞給 <component>:

<router-view v-slot="{ Component }">
  <component :is="Component">
    <p>In Vue Router 3, I render inside the route component</p>
  </component>
</router-view>
  1. 將 parent 從路由地址中刪除
    parent 屬性已從標準化路由地址(this.$route 和 router.resolve 返回的對象)中刪除相种。你仍然可以通過 matched 數(shù)組訪問它:
const parent = this.$route.matched[this.$route.matched.length - 2]

原因:同時存在 parent 和 children 會造成不必要的循環(huán)引用,而屬性可以通過 matched 來檢索东抹。

  1. 刪除 pathToRegexpOptions

路由的 pathToRegexpOptionscaseSensitive 屬性已被 createRouter()sensitivestrict 配置取代÷熳樱現(xiàn)在沃测,當(dāng)使用 createRouter() 創(chuàng)建路由時缭黔,它們也可以直接傳遞食茎。path-to-regexp 的任何其他特定配置已被刪除,因為 path-to-regexp 已不再用于解析路徑馏谨。

  1. 刪除未命名的參數(shù)
    由于取消了 path-to-regexp别渔,所以不再支持未命名的參數(shù):
  • /foo(/foo)?/suffix 變成 /foo/:_(foo)?/suffix
  • /foo(foo)? 變成 /foo:_(foo)?
  • /foo/(.*) 變成 /foo/:_(.*)

請注意,你可以使用任何名稱代替 _ 作為參數(shù)惧互。重點是要提供一個名字哎媚。

  1. history.state 的用法
    Vue Router 將信息保存在 history.state 上。如果你有任何手動調(diào)用 history.pushState() 的代碼喊儡,你應(yīng)該避免它拨与,或者用的 router.push() 和 history.replaceState() 進行重構(gòu):
// 將
history.pushState(myState, '', url)
// 替換成
await router.push(url)
history.replaceState({ ...history.state, ...myState }, '')

同樣,如果你在調(diào)用 history.replaceState() 時沒有保留當(dāng)前狀態(tài)艾猜,你需要傳遞當(dāng)前 history.state:

// 將
history.replaceState({}, '', url)
// 替換成
history.replaceState(history.state, '', url)

原因:我們使用歷史狀態(tài)來保存導(dǎo)航信息买喧,如滾動位置,以前的地址等匆赃。

  1. options 中需要配置 routes

options 中的 routes 屬性現(xiàn)在是必需的淤毛。

// v3
initRouter(routes, opts) {
  router = new Router(opts);
  if (routes) {
    router.addRoutes(routes);
  }
}
// v4
createRouter({ routes: [] })

原因:路由的設(shè)計是為了創(chuàng)建路由,盡管你可以在以后添加它們算柳。在大多數(shù)情況下低淡,你至少需要一條路由,一般每個應(yīng)用都會編寫一次瞬项。

  1. 不存在的命名路由
    跳轉(zhuǎn)或解析不存在的命名路由會產(chǎn)生錯誤:
// 哎呀蔗蹋,我們的名字打錯了
router.push({ name: 'homee' }) // 報錯
router.resolve({ name: 'homee' }) // 報錯

原因:以前,路由會導(dǎo)航到 /囱淋,但不顯示任何內(nèi)容(而不是主頁)纸颜。拋出一個錯誤更有意義,因為我們不能生成一個有效的 URL 進行導(dǎo)航

  1. 命名路由缺少必要的 params

在沒有傳遞所需參數(shù)的情況下跳轉(zhuǎn)或解析命名路由绎橘,會產(chǎn)生錯誤:

// 給與以下路由:
const routes = [{ path: '/users/:id', name: 'user', component: UserDetails }]

// 缺少 `id` 參數(shù)會失敗
router.push({ name: 'user' })
router.resolve({ name: 'user' })
  1. 帶有空 path 的命名子路由不再添加斜線

給予任何空 path 的嵌套命名路由:

const routes = [
  {
    path: '/dashboard',
    name: 'dashboard-parent',
    component: DashboardParent,
    children: [
      { path: '', name: 'dashboard', component: DashboardDefault },
      {
        path: 'settings',
        name: 'dashboard-settings',
        component: DashboardSettings,
      },
    ],
  },
]

現(xiàn)在胁孙,導(dǎo)航或解析到命名的路由 dashboard 時,會產(chǎn)生一個不帶斜線的 URL:

router.resolve({ name: 'dashboard' }).href // '/dashboard'

這對子級 redirect 有重要的副作用称鳞,如下所示:

const routes = [
  {
    path: '/parent',
    component: Parent,
    children: [
      // 現(xiàn)在將重定向到 `/home` 而不是 `/parent/home`
      { path: '', redirect: 'home' },
      { path: 'home', component: Home },
    ],
  },
]

請注意涮较,如果 path 是 /parent/,這也可以冈止,因為 home 到 /parent/ 的相對地址確實是 /parent/home狂票,但 home 到 /parent 的相對地址是 /home。

原因:這是為了使尾部的斜線行為保持一致:默認情況下熙暴,所有路由都允許使用尾部的斜線闺属』哦ⅲ可以通過使用 strict 配置和手動添加(或不添加)斜線來禁用它。

// frame-layout

initRouter(
  [
    {
      path: '/',
      component: initRouterLayout((layout) => {
        return import('@/layouts/' + layout + '.vue')
      }),
      children: [
        {
          name: '403',
          path: '403',
          component: _403,
        }
      ],
    },
  ],
  { base: '/frame-layout/', mode: 'history' }
)

  1. $route 屬性編碼
    無論在哪里啟動導(dǎo)航掂器,params亚皂、queryhash 中的解碼值現(xiàn)在都是一致的(舊的瀏覽器仍然會產(chǎn)生未編碼的 pathfullPath)。初始導(dǎo)航應(yīng)產(chǎn)生與應(yīng)用內(nèi)部導(dǎo)航相同的結(jié)果国瓮。

給定任何規(guī)范化的路由地址:

  • path, fullPath中的值不再被解碼了灭必。例如,直接在地址欄上寫 "https://example.com/hello world"乃摹,將得到編碼后的版本:"https://example.com/hello world"禁漓,而 "path "和 "fullPath "都是"/hello%20world"。
  • hash 現(xiàn)在被解碼了孵睬,這樣就可以復(fù)制過來播歼。router.push({ hash: $route.hash }) 可以直接用于 scrollBehaviorel 配置中。
  • 當(dāng)使用 push掰读、resolvereplace 并在對象中提供 string 地址或 path 屬性時秘狞,必須進行編碼(像以前的版本一樣)。另一方面磷支,params谒撼、queryhash 必須以未編碼的版本提供。
  • 斜線字符(/)現(xiàn)在已在 params 內(nèi)正確解碼雾狈,同時仍在 URL 上產(chǎn)生一個編碼版本:%2F廓潜。

原因:這樣,在調(diào)用 router.push()router.resolve() 時善榛,可以很容易地復(fù)制一個地址的現(xiàn)有屬性辩蛋,并使產(chǎn)生的路由地址在各瀏覽器之間保持一致。router.push() 現(xiàn)在是冪等的移盆,這意味著調(diào)用 router.push(route.fullPath)悼院、router.push({ hash: route.hash })router.push({ query: route.query })router.push({ params: route.params }) 不會產(chǎn)生額外的編碼咒循。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末据途,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叙甸,更是在濱河造成了極大的恐慌颖医,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裆蒸,死亡現(xiàn)場離奇詭異熔萧,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門佛致,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贮缕,“玉大人,你說我怎么就攤上這事俺榆「兄纾” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我台谊,道長粗仓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任奸绷,我火速辦了婚禮梗夸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘号醉。我一直安慰自己反症,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布畔派。 她就那樣靜靜地躺著铅碍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪线椰。 梳的紋絲不亂的頭發(fā)上胞谈,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機與錄音憨愉,去河邊找鬼烦绳。 笑死,一個胖子當(dāng)著我的面吹牛配紫,可吹牛的內(nèi)容都是我干的径密。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼躺孝,長吁一口氣:“原來是場噩夢啊……” “哼享扔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起植袍,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤惧眠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后奋单,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锉试,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了呆盖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拖云。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖应又,靈堂內(nèi)的尸體忽然破棺而出宙项,到底是詐尸還是另有隱情,我是刑警寧澤株扛,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布尤筐,位于F島的核電站,受9級特大地震影響洞就,放射性物質(zhì)發(fā)生泄漏盆繁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一旬蟋、第九天 我趴在偏房一處隱蔽的房頂上張望油昂。 院中可真熱鬧,春花似錦倾贰、人聲如沸冕碟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽安寺。三九已至,卻和暖如春首尼,著一層夾襖步出監(jiān)牢的瞬間挑庶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工饰恕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挠羔,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓埋嵌,卻偏偏與公主長得像破加,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子雹嗦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容