Vue3 + TypeScript 复盘总结,前端篇

import { computed } from “vue”

const v = computed(() => {

return x

});

computed 返回的变量是一个响应式对象。

Vue3 中组件循环自身的技巧

这是一种开发组件的技巧。

假设你有一个不确定深度的树状结构数据。

{

“label”: “root”,

“children”: [

{

“label”: “a”,

“children”: [

{

“label”: “a1”,

“children”: []

},

{

“label”: “a2”,

“children”: []

}

]

}

]

}

它的类型定义如下:

export interface Menu {

id: string;

label: string;

children: Menu | null;

}

你需要实现一种树状组件来渲染它们。这时就需要用到这种技巧。

{{ menu.label }}

@select=“select”

v-for=“item in menu.children”

:key=“item.id”

:menu=“item”

/>

组件的 name 可以在自身中直接使用,而不需要在 component 中声明。

一些坑


Vuex:慎用 Map

在 Vuex 中,我设计了一个数据结构用于存储模块(业务概念)不同的状态。

type Code = number;

export type ModuleState = Map<Code, StateProperty>;

但是我发现一个问题,当我修改 Map 中某一个 value 中的属性时,不会触发 Vuex 的监听。

所以我只好将数据结构修改为对象的形式。

export type ModuleState = { [key in Code]: StateProperty };

ts 中索引不可以使用类型别名,但是可以写成下面这样:

type Code = number;

export type ModuleState = { [key in Code]: StateProperty };

除此之外,Map 还存在另外一个问题。

当一个 Map 类型的 Proxy 对象作为参数被传递时,是无法使用 get、set、clear 等 Map 方法的,但是 TypeScript 会提示这些方法可用。如果使用了这些方法,会得到一个 Uncaught TypeError。

如果使用 Object 则不会产生这个问题。

WebSocket 发生异常无法被 try catch 监听

ws 的异常只能在 onerror 和 onclose 两个事件中进行处理,try catch 是无法捕获的。

有些时候,onerror 和 onclose 会连续执行,比如触发 onerror,导致连接关闭,就会紧接着触发 onclose。

Vue Devtools

vue devtools 目前无法支持 Vue3,但是 vue devtools 几乎是开发中必不可少的工具,目前可以使用 vue devtools beta 版本,但存在一些 Bug。

下载地址:

https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg?utm_source=chrome-ntp-icon

用法非常简单,安装后重启浏览器就可以。不需要设置 vue.config.devtools = true,在 vue3 中 vue.config 实例不存在 devtools 属性。

ESbuild 安装依赖

在使用 vite 启动服务的同时安装依赖,非常容易碰到一个错误。

Error: EBUSY: resource busy or locked, open ‘E:\gxt\property-relay-fed\node_modules\esbuild\esbuild.exe’

这个问题的原因是 vite 依赖的编译工具 esbuild.exe 被占用所导致的,解决方法很简单,就是停掉 vite,安装完依赖后再重新启动 vite。

Vite 在 Chrome 中调试的问题

系统中有一些移动页面,需要嵌入在 App 中使用。

常见的调试 WebView 的方法有两种,一种简单的方式是使用腾讯开源的 vcosnole,另一种麻烦一些的调试方式是使用 Chrome 的 DevTools。

但是 vconsole 并没有想象中那么好用。

image.png

所以我选择使用 Chrome 调试,chrome://inspect/#devices

但是在调试过程中我发现 Chrome 调试工具里面竟然运行的是 TS 源码,TS 的语法直接被认为语法错误。(我是使用 Vite 启动的开发服务。)

解决方案很简单,但挺 Low。先使用 vite build 把 TS 代码编译成 JS,再使用 vite preview 启动服务。

WebSocket


websocket 和 Vue3 没什么关系,但是在这里简单提一下。

设备管理系统的核心概念是设备,设备会有很多属性,在硬件上也被称作数据点。这些属性会经历非常长的链路传输到用户界面上。整体流程大概是:硬件通过 tcp 协议上传到接入网关,接入网关处理后再通过 mqtt 协议上传到物联网平台,物联网平台再经过规则引擎处理,通过 webhook restful 的形式发送到业务系统,业务系统再通过 websocket 推送到前端。

虽然数据通过层层编解码、不同的协议绕了非常远的距离呈现到用户面前,但是前端只需要关心 websocket 就足够了。

WebSocket 重连

在做重连时,需要注意 onerror 和 onclose 连续执行的问题,通常是使用类似防抖的方法来解决。

我的做法是增加一个变量来控制重连次数。

let connecting = false; // 断开连接后,先触发 onerror,再触发 onclose,主要用于防止重复触发

conn();

function conn() {

connecting = false;

if (ctx.state.stateWS.instance && ctx.state.stateWS.instance.close) {

ctx.state.stateWS.instance.close();

}

const url = ctx.state.stateWS.url + “?Authorization=” + getAuthtication();

ctx.state.stateWS.instance = new WebSocket(url);

ctx.state.stateWS.instance.onopen = () => {

ctx.commit(ActionType.SUCCESS);

};

ctx.state.stateWS.instance.onclose = () => {

if (connecting) return;

ctx.commit(ActionType.CLOSE);

setTimeout(() => {

conn();

}, 10 * 1000);

connecting = true;

};

ctx.state.stateWS.instance.onerror = () => {

if (connecting) return;

ctx.commit(ActionType.ERROR);

setTimeout(() => {

conn();

}, 10 * 1000);

connecting = true;

};

ctx.state.stateWS.instance.onmessage = function (

this: WebSocket,

ev: MessageEvent

) {

// logic

} catch (e) {

console.log(“e:”, e);

}

};

}

WebSocket 连接活动日志

系统是设计成 7*24 小时不间断运行。所以 websocket 很容易受到一些网络因素或者其它因素的影响发生断开,重连是一项非常重要的功能,同时还应该具备重连日志功能。

在用户的不同环境中,排查 WebSocket 的连接状态很麻烦,添加一个连接日志功能是比较不错的方案,这样可以很好的看到不同时间的连接情况。

image.png

需要注意,这些日志是存储在用户的浏览器内存中的,需要设置上限,到达上限要自动清除早期日志。

WebSocket 鉴权

websocket 的鉴权是很多人容易忽视的一个点。

我在系统设计中,restful API 的鉴权是通过在 request header 上附带 Authorization 字段,设置生成的 JWT 来实现的。

websocket 无法设置 header,但是可以设置 query,实现思路类似 restful 的认证设计。

关于 ws 鉴权的过期、续期、权限等问题,和 restful 保持一致即可。

script setup:更加清爽的 API


script setup 至今仍是一个实验性特性,但它确实非常清爽。

单文件组件的 setup 常规用法像下面这样:

使用 script setup 后,代码变成了下面这样:

在 sciprt 标签中的顶层变量、函数都会 return 出去。

在这种模式下,减少了大量代码,可以提高开发效率、降低心智负担。

但这时也存在几个问题,比如在 script setup 中怎么使用生命周期和 watch/computed 函数?怎么使用组件?怎么获取 props 和 context?

使用组件

直接导入组件后,vue 会自动识别,无需使用 component 挂载。

使用生命周期和监听计算函数

和标准写法基本无差异。

使用 props 和 context

由于 setup 被提升到 script 标签上了,自然也就没办法接收 props 和 context 这两个参数。

所以 vue 提供了 defineProps、defineEmit、useContext 函数。

defineProps

defineProps 的用法和 OptionsAPI 中的 props 用法几乎一致。

defineEmit

defineEmit 的用法和 OptionsAPI 中的 emit 用法也几乎一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值