V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xpyusrs
V2EX  ›  Vue.js

vue3+ts 根据路由来写生成侧边栏菜单, 总感觉 ts 用起来太别扭, 教教我正确用法

  •  
  •   xpyusrs · 2022-12-16 11:49:38 +08:00 · 2164 次点击
    这是一个创建于 712 天前的主题,其中的信息可能已经有所发展或是发生改变。
    <template>
      <div class="sidebar">
        <div>{{ t('menu.dashboard') }}</div>
        <n-scrollbar>
          <n-menu :options="menuOptions" />
        </n-scrollbar>
      </div>
    </template>
    
    <script lang="ts" setup>
    import { h, Component, ref, watch } from 'vue'
    import { useI18n } from 'vue-i18n'
    import { RouteRecordRaw, RouterLink } from 'vue-router'
    import { useRouter } from 'vue-router'
    import { computed } from 'vue'
    import { useAppStore } from '@/store'
    import type { MenuOption } from 'naive-ui'
    import { NIcon } from 'naive-ui'
    import { DashboardOutlined as DashboardIcon } from '@vicons/antd'
    
    const router = useRouter()
    
    const { t, locale } = useI18n()
    
    console.log(router.getRoutes())
    const appStore = useAppStore()
    const routers = computed(() => {
      return appStore.routers.filter(value => !value.meta?.hidden)
    })
    const menuOptions = ref<MenuOption[]>([])
    
    const iconMap: { [index: string]: any } = {
      Dashboard: DashboardIcon
    }
    
    function renderIcon(icon: Component) {
      return () => h(NIcon, null, { default: () => h(icon) })
    }
    
    const genMenu = () => {
      menuOptions.value = []
      for (const item of routers.value) {
        const children = []
        for (const item2 of item?.children || []) {
          children.push({
            label: () =>
              h(
                RouterLink,
                {
                  to: {
                    name: item2.name
                  }
                },
                { default: () => t(item2.meta?.locale as string) }
              ),
            key: item2.name as string
          })
        }
        const menu: MenuOption = {
          key: item.name as string,
          label: t(item.meta?.locale as string),
          icon: renderIcon(iconMap[item.name as string]),
          children
        }
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        menuOptions.value.push(menu)
      }
    }
    
    genMenu()
    
    watch(
      () => locale.value,
      () => {
        genMenu()
      }
    )
    </script>
    
    

    vue-router 的类型 RouteRecordRaw, 一个属性有好几种类型, 然后用起来 ts 总是报类型不匹配, 用了大量 as string 来解决报错, 好难受, 我之前都是写 js, 可能对 ts 理解有误, 怎么才能优雅的使用, 有个报错说我嵌套太深, 还不得不用 // @ts-ignore 来解决

    13 条回复    2022-12-16 20:25:54 +08:00
    gogogo2000
        1
    gogogo2000  
       2022-12-16 12:17:47 +08:00
    vue 对 ts 的兼容性一向来都不太好,这也是 react 的重大优势之一,有时候没办法只能 as any……
    wunonglin
        2
    wunonglin  
       2022-12-16 12:39:39 +08:00
    你 routers 的类型推断出来了吗?还是什么问题单单代码看不出,你去 stackblitz.com 写个例子。
    xpyusrs
        3
    xpyusrs  
    OP
       2022-12-16 12:39:44 +08:00
    @gogogo2000 用 react 就没有这个问题了嘛? 如果这样的话我可以转 react
    anguiao
        5
    anguiao  
       2022-12-16 13:38:17 +08:00
    路由的元信息是可以预先声明的呀,文档里面有写。
    https://router.vuejs.org/zh/guide/advanced/meta.html#typescript
    chengxy
        6
    chengxy  
       2022-12-16 13:42:21 +08:00
    你用法不对,你的 routers 类型应该和 MenuOption 类型对上的,RouteRecordRaw 里面的参数你可以使用重写功能去重写。
    chengxy
        7
    chengxy  
       2022-12-16 13:47:28 +08:00
    @gogogo2000 #1 都 24 年了,现在完全不是问题了
    xpyusrs
        8
    xpyusrs  
    OP
       2022-12-16 14:05:25 +08:00
    @chengxy 重写能给个示例么, 我好模仿一下
    chengxy
        9
    chengxy  
       2022-12-16 14:07:02 +08:00
    @xpyusrs #8 5 楼给了
    ZoeeoZ
        10
    ZoeeoZ  
       2022-12-16 14:47:19 +08:00
    @xpyusrs ts 官方为 react 做了兼容..你说呢,所以 react+ts 才好用
    ccyu220
        11
    ccyu220  
       2022-12-16 15:32:25 +08:00
    我建议 menu 这种,你直接换成 tsx 来写。
    wunonglin
        12
    wunonglin  
       2022-12-16 17:40:40 +08:00
    @xpyusrs #4

    噢噢。router meta 这个问题在 vue2 时代也是这样,只能类型覆盖。

    虽然但是,不建议直接把路由当做 navmenu 以及把路由表引到 ui 层使用,路由归路由,menu 归 menu 。这是个很标准的错误用法,虽然可以这么用,但是建议不。
    Bingchunmoli
        13
    Bingchunmoli  
       2022-12-16 20:25:54 +08:00 via Android
    没有 vue3 的一些代码示例,,pinia 什么的 ts 都不太会用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4875 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:01 · PVG 18:01 · LAX 02:01 · JFK 05:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.