V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhennann
V2EX  ›  前端开发

在 Vue3 中如何为路由 Query 参数标注类型

  •  
  •   zhennann ·
    zhennann · 70 天前 · 602 次点击
    这是一个创建于 70 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    最近发布了一款支持 IOC 容器的 Vue3 框架:Zova。与以往的 OOP 或者 Class 方案不同,Zova 在界面交互层面仍然采用 Setup 语法,仅仅在业务层面引入 IOC 容器。IOC 容器犹如一把钥匙,为我们打开了业务工程化的大门,允许我们探索更多工程化方面的设计和能力。有网友提出一个非常好的建议:可否提供一些业务场景,说明有哪些是 Class 可做而 Composable 做不了的,这样才更有说服力。

    首先说明一点,其实没有哪些业务需求是这个能做而那个不能做的。不同的编程范式带来的是不同的代码风格,不同的编程体验,从不同的路径指向开发效率和代码可维护性方面的评估。因此,最终根据用户自身的偏好和业务实际需求而定。

    那么,在这里,我们就针对这个话题如何为路由 Query 参数标注类型为例,看看 Composable 和 IOC 容器的代码风格究竟有什么不同。

    需求说明

    这里有一个页面组件 User ,可以通过 Query 传递三个参数:

    参数名 类型 缺省值
    id number 0
    name string ''
    married boolean false

    Composable:原生

    1. 访问页面

    const router = useRouter();
    router.push({
      path: '/test/demo/user',
      query: {
        id: 1,
        name: 'kevin',
        married: false.toString(),
      },
    });
    

    从 Typescript 类型的角度来看,这段代码有以下两个问题:

    1. path:没有类型约束和智能提示。这会存在以下三个隐患:
      1. 记不住:如果路径较长,或者单词较复杂,就记不住路径,需要从源文件查找
      2. 写错了:如果不小心写错了,没有提示,只有到实际运行时才会暴露错误
      3. 被改了:如果后续维护代码时,路径有了变更,那么这里的代码同样没有提示,只有到实际运行时才会暴露错误
    2. query:只有有限的类型约束,与业务类型并不一致
      1. 比如不支持 Boolean 类型,必须强制转换为 String 类型

    2. 获取参数

    const route = useRoute();
    const id = parseInt(route.query.id ?? 0);
    const name = route.query.name ?? '';
    const married = route.query.married === 'true' ? true : false;
    

    由于没有提供类型工具,需要针对每一个参数单独处理

    Composable:useRouteQuery

    1. 访问页面

    (同上)

    2. 获取参数

    import { useRouteQuery } from '@vueuse/router';
    
    const id = useRouteQuery('id', 0, { transform: Number });
    const name = useRouteQuery('name', '');
    const married = useRouteQuery('married', 'false', {
      transform: value => {
        return value === 'true' ? true : false;
      },
    });
    

    IOC 容器

    1. 定义类型

    import { zz } from 'zova';
    
    export const QuerySchema = zz.object({
    +  id: zz.number().default(0),
    +  name: zz.string().default(''),
    +  married: zz.boolean().default(false),
    });
    
    • zz 是在 zod 基础上做的加强版,特别针对路由参数做了处理,支持 array 数组和 json 对象,具体参见:Zova: zod
    • 在定义类型的同时可以指定缺省值

    route-query-1-1.gif

    2. 访问页面

    const url = this.$router.resolvePath('/test/demo/user', {
      id: 0,
      name: 'kevin',
      married: false,
    });
    this.$router.push(url);
    
    • resolvePath 的参数都有类型约束和智能提示,并且与业务类型保持一致

    route-query-2.gif

    3. 获取参数

    const id = this.$query.id;
    const name = this.$query.name;
    const married = this.$query.married;
    
    • 直接通过this.$query获取参数值,有明确的类型,并且不需要处理缺省值

    route-query-3.gif

    总结

    从上面的示例对比可以看出,采用 IOC 容器,可以实现定义使用的分离,而且定义侧可以通过工具来创建脚手架,进一步简化定义的书写。由于 TS 类型和缺省值等规范性代码都在定义侧完成了,那么在使用侧代码就更加简洁直观了。不知您的代码风格偏好是什么,是否还有更好的表达方式,欢迎在评论区交流。

    参考资料

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5872 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:14 · PVG 10:14 · LAX 19:14 · JFK 22:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.