当前位置:网站首页 > 技术博客 > 正文

ts在vue中的用法



本文是《Vue3 + TS 最佳实践 》的补充篇,笔者之所以“执着于”在 Vue 中使用 JSX,一方面是因为之前使用 React 形成的编码习惯。但更重要的是在使用 React v16.8+ 的过程中,深刻体会到 JSX 与 TS 的结合是最完美的,因为 JSX 本质上只是一种语法糖,并没有超出 JS 的范畴,自然与 TS 配合完美。

所以本文会聚焦于 Vue3 下 JSX + TS,即 TSX 的实现,来探索 TS 在 Vue3 下是否有另一种最佳实践。归根结底,还是为了 TS 的落地。

在笔者的另一个短篇文章《为什么 React 比 Vue 更适合集成 TS》(以下简称“短篇”)里,简单论述了以下内容:

  • React 在结合 TS 方面为什么会这么成功
  • JSX 在其中充当的角色
  • JSX vs. Vue Template(SFC) 按照短篇中的逻辑,如果使用 JSX,就要放弃一些 Vue Template 带来的特性,比如一些自带的性能优化、状态驱动的动态 CSS 等。需要像 React 一样手动去做这些处理,这也就意味着有可能会降低整体工程质量的下限,当然好处就是更加顺滑的 TS 体验。对于这些点的取舍,还要同学们根据实际情况自己判断。毕竟软件开发本质上,是一项寻求平衡的妥协的艺术。

言归正传,先简单整理下 JSX 对 template 的优劣点:

优势

  1. 除了“标签语法”外,都是 JS 原生的语法,学习成本较小
  2. 同时意味着更灵活,可控性强,留给开发者全部的发挥空间
  3. 与 TS 完美结合
  4. 可以随着 ES、TS 的迭代升级自然进化,能力与开发体验都会不断提升
  5. 相较于 template 的 props、attrs、emits、slots 等概念,JSX 只有 props 一个概念,心智负担较小

劣势

  1. 部分人对于在 JS 里混入 HTML 语法表示很抗拒,感觉违背了逻辑与表现分离的原则
  2. 灵活意味着代码质量与程序员的水平强相关,也就是不好保证代码质量的下限
  3. 相应的,一些优化点需要程序员自己控制,比如 React 中的 useCallback、useMemo,相信能彻底弄明白的人不是多数
  4. 没有 template(SFC) 提供的 style 处理能力,如 scoped、module、状态驱动等

其实最关键的点就是如何把 template 中的特殊语法映射到 JSX 上,比如 slots、emits 等。这要靠查看官网 渲染函数 的说明来推测,下面我们用一个实际例子来具体看下怎么做。建议先看下本文的结论,心里先有个底。

image.png

  1. 分为 ParentChild 两个组件。分别都会用 Vue3 + TS 最佳实践 和 TSX 的方式各实现一版。
  2. Parent,蓝色背景,组件内部维护一个 响应式变量,当点击 [Count++ 按钮] 时触发 方法自增,并动态展示在 Parent 中
  3. Child,黄色背景,组件的内部没有任何响应式的声明,只接收 Parent 传入的 、、
  4. Child 组件接收的 有 :count="count"、style; 有 #header 和 #default; 有 @childClick="handleIncrease"
  5. Child 会展示 以及 ,[Child Count++ 按钮] 的点击会触发 ,即触发 Parent count 的改变

为方便对比,这部分的代码用的图片,且做了对齐处理,文末会有文本代码,方便大家复制。

image.png 关键点如下:

  1. TSX 要用 包裹,并且只使用 (没有 data、methods、computed 等一级声明),返回值要是一个 ,里面采用 JSX 的写法;
  2. TSX(defineComponent) 中 、、 等的声明是省不了的, 的声明我们看下文 Child 的实现;
  3. 在 TSX 中要变为 ,自定义 也要由 变为 。不过这里要注意,正如“短篇”中提到的,如果用了 TSX,像 onClick 这种可能引起无效重复 render 的问题,就需要使用者自己解决了;

注:如果在 template 中同时传入 @childClick 和 :onChildClick 会发生什么呢?

答案是:不管传入顺序如何,:onChildClick 都会覆盖掉 @childClick,有兴趣的同学可以验证一下。所以在 template 中,事件还是老老实实的用 @ 的好。

  1. TSX 中的 ref 对象还是需要使用 结尾,有点麻烦,但是编辑器会自动补全;
  2. 如果有多个,TSX 要像例子中一样,通过一个对象传入子组件。对象的 key 为 slot 的名字,value 为要传入的组件;

综上,需要特别注意的就是 和 的特殊处理。另外,上例当中还存在一个比较大的问题,即 实际上会被编译器提示 TS 校验错误,但代码又是可运行的。要想解决这个问题,只能要求子组件不声明 emits,全部用 props.onXXX 代替,即放弃使用 (感觉不太合适)。这点现在是最难受的,笔者还没有想到一个好的解决方案。

image.png 上图中 TSX 的例子是用 Functional Component 形式实现的,这种组件使用 TSX 可谓是最舒服的,关键点如下:

  1. 注意两者 声明的不同,SFC 中参考官网的例子(仅限类型的 props/emit 声明),TSX 中 Emit 的声明一定要是 格式而不能是 ,这是由 内部泛型处理逻辑决定的;
  2. TSX 中可以使用解构赋值,这是一个组件二次封装的场景下很常用的一个语法;
  3. 在 TSX 中以函数的形式调用,注意例子中的容错写法,防止没有 slot 传入时的报错; 综上,在 Functional Componet 的场景下,选择 TSX 是个不错的决定。如果用 的方式实现 Child 应该是什么样呢?也顺便解答一下上面留下的一个疑问,关于 props 声明的问题。
 
  

关键点如下:

  1. 要想 有很好的提示,必须要按照上例的方式,用 来声明各种属性的类型;
  2. 目前没有找到很好的 TS 声明的方法。即使用验证模式去写,也很不理想,毕竟我们要声明的是 emit 本身,而不是它的验证函数,意义都变了; 只能说太尴尬了,如果 TS 是这么使用的话,实在是太别扭了。也许对 进行 TS 加强后,能够一定程度的优化这个问题吧。

本文通过一个典型的父子组件场景,来模拟实践中可能遇到的各种情况,最终的结论如下:

  1. Functional Component(即只有 、、 传入的组件),可以完美的使用 TSX;
  2. 没有 和 传入的组件(如本文的 Parent 组件),使用 TSX 还算可以接受,但是实际上组件内部没有太多的利用上 TS;
  3. 普通组件,尤其是带了 和 的组件,用 TSX 形式实在是有点强人所难; 所以想要愉快的在 Vue3 中使用 TS,还是首选 Vue3 + TS 最佳实践 的方式吧。如果项目解耦的特别好,有大量的 Functional Component,可以考虑用 TSX。不过 Vue3 官网有这样一句话:
  • 在 3.x 中,2.x 带来的函数式组件的性能提升可以忽略不计,因此我们建议只使用有状态的组件

好吧,笔者已经找不出其他理由使用 TSX 了(除了 React 带来的惯性)。所以,Vue3 + TSX 可以说目前还不存在足够“佳”的实践,更不用说是最佳实践了。否定的结论也是结论,最后希望整个问题的思考过程,也能够带给大家一些收获吧。

"I have not failed. I've just found 10,000 ways that won't work." —— Thomas A. Edison

  1. 尤雨溪vue 3.0直播你学到了什么?
 
  
 
  
 
  
 
  

                            

版权声明


相关文章:

  • phython入门2025-08-03 07:30:05
  • 文件描述符号2025-08-03 07:30:05
  • 地理空间数据索引2025-08-03 07:30:05
  • 思科模拟器怎么给交换机配ip地址2025-08-03 07:30:05
  • 服务器硬件是什么2025-08-03 07:30:05
  • 蒙特卡洛算法的matlab程序2025-08-03 07:30:05
  • post请求例子2025-08-03 07:30:05
  • 什么是内连接、外连接?mysql支持哪些外连接?2025-08-03 07:30:05
  • 倒排索引的应用2025-08-03 07:30:05
  • textview文字大小2025-08-03 07:30:05