亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

開始切入正題之前,有必要告知大家一下,這篇文章可能有一些深度,初學者可能理解會有些吃力。我會盡量把復雜問題簡單化,爭取讓每個閱讀的童鞋們都能看得懂。希望你對element-ui,vue-router,KeepAlive組件有一點了解。現在,我們開始吧。

熟悉element-ui的童鞋們都知道,ElMenuItem和ElSubMenu都需要一個index屬性,該屬性必須是唯一的。現在,我們想把路由配置直接應用于ElMenu,該如何確保index的唯一性呢?我們需要有一個生成唯一index的函數。如下是genKey函數的定義,是不是很簡單?

export const genKey = ((k = 1) => () => k++)()

現在,我們創建addRouteMetaKey函數,該函數對路由樹進行遞歸遍歷,為每一個路由配置的meta屬性動態添加key字段。這個函數很簡單,屬于最基礎的遞歸使用例子,我就不做太多解釋了。

提示:數組的forEach方法不是純函數,因為它有副作用,所以forEach方法不能稱之為函數式編程工具。

/** @param {import('vue-router').RouteRecordRaw[]} routes */
const addRouteMetaKey = routes => {
  routes.forEach(route => {
    if (route.meta) {
      route.meta.key = genKey()
    } else {
      route.meta = { key: genKey() }
    }
    route.children && addRouteMetaKey(route.children)
  })
  return routes
}

通過addRouteMetaKey函數,我們可以把路由的meta.key作為index的值了。

現在,我們想實現另一個功能,就是基于標簽頁的路由組件緩存控制。使用過Vuejs KeepAlive組件的童鞋們,應該多多少少都遇到一些坑吧?在我們的項目中,有一個頂部標簽頁導航,每個tab項對應一個url,以每個url對應路由的title作為tab項標題,當切換tab的時候加載緩存中的url對應的路由組件,關閉tab項,下次打開該路由url,重新掛載對應的路由組件,而不是從緩存中加載。

當路由層級不確定的時候,KeepAlive會變的難以手動控制。所以,我劍走偏鋒,嘗試了一種簡單的解決方案,實踐證明:這是非常有效的。我的方案就是把無限層級的路由樹轉化為一維數組。通過為meta添加必要的字段,進行頁面結構個性化定制。

我們需要把每層路由配置的path轉化為全路徑,所以需要一個函數:getRouteFullPath,該函數定義如下:

/**
 * 獲取路由全路徑
 * @description 如果path以 / 開頭(屬于絕對路徑),則直接返回,否則拼接路徑
 * @param {string} path
 * @param {string} parentPath
 */
export const getRouteFullPath = (path, parentPath) => {
  return !parentPath || path.startsWith('/') ? path : joinPath(parentPath, path)
}

getRouteFullPath函數中使用到的joinPath函數用于將多個路徑字符串拼接為1個完整的路徑,定義如下:

/** @param {string[]} paths */
export const joinPath = (...paths) => {
  const j = '/'
  const [a, ...b] = paths
  return (a.endsWith('/') ? a.replace(/(/+)$/gm, j) : a + j) + b.map(_ => _.replace(/^(/+)|(/+)$/gm, '')).join(j)
}

現在,我們把路由樹轉化為一維數組。我們定義toFlatRoutes函數,該函數使用了數組的reduce方法對路由樹進行聚合遞歸,將路由配置中的path屬性的值替換為全路徑,還順便給路由配置添加了name屬性,返回一個新的一維路由配置數組。這是函數式編程和遞歸結合的一個例子。

/**
 * @param {import('vue-router').RouteRecordRaw[]} routes
 * @returns {import('vue-router').RouteRecordRaw[]}
*/
const toFlatRoutes = (routes, parentPath) => {
  return routes.reduce((t, r) => {
    const path = getRouteFullPath(r.path, parentPath)
    return [
      ...t,
      ...(r.children
          ? toFlatRoutes(r.children, path)
          : [{ ...r, path, name: r.name || `name-${genKey()}` }]
        )
    ]
  }, [])
}

以上,我們解決了KeepAlive的緩存控制問題;現在,我們又有了一個新的用戶體驗上的需求,就是我們想根據url對應的路由,自動展開該路由meta.key所屬的側邊菜單;我們通過查閱element-ui文檔得知,ElMenu有一個open方法,接收index作為參數,展開index對應的菜單。

現在的問題是,我們的路由對應的index是ElMenuItem的,而路由樹已經被我們轉化為了一維數組,通過路由的matched字段是得不到我們想要的菜單index的。所以,我們需要遍歷原始路由樹

如下代碼,我們定義getMenuKey函數,該函數接收的參數為route對象。如果路由存在,我們進行查找。首先進行簡單查找,如果找到一個菜單menu,則返回該菜單的meta.key;如果簡單查找無果,則對路由樹進行遞歸查找;這是函數式編程和遞歸結合的另一個例子。

/**
 * @param {import('vue-router').RouteRecordRaw} item
 * @returns {number|undefined}
*/
export const getMenuKey = item => {
  if (item) {
    const menu = state.menus.find(m => item.path.startsWith(m.path))
    if (menu) {
      return menu.meta.key
    }
    const itemKey = item.meta.key
    return (function findFunc (menus) {
      /** @param {import('vue-router').RouteRecordRaw} m */
      const fn = m => m.meta.key === itemKey ? true : m.children && m.children.some(fn)
      const curMenu = menus.find(fn)
      return curMenu && curMenu.meta.key
    })(state.menus) // state是響應式對象,定義:const state = reactive({ menus: [] })
  }
}

現在,我們大功告成了;以上就是本節的知識點,童鞋們理解了嗎?只要我們熟悉遞歸的使用,其實操作樹很簡單。如果大家還有不懂的,可以評論區問我。感謝閱讀!

分享到:
標簽:函數 JS
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定