typescript不定参数-Vue3+TypeScript 回顾总结

2023-08-29 0 2,692 百度已收录

type ColorConfig = {
  [key in Type]: Colors;
};

使用接口只能像下面这样:

interface ColorConfig {
  [key: string]: Colors;
}

由于接口的索引只能是基本类型,因此类型别名也是不允许的。 类型索引可以是复合类型。

Vue3如何获取元素实例?

在vue3中,组件的逻辑可以放在setup函数上,而setup中没有this,所以vue2中this.$refs的用法很难在vue3中使用。

新的用法是:

将 ref 属性添加到元素。

声明一个与 setup.json 中的元素 ref 同名的变量

将 ref 变量作为 setup 的返回对象上的同名属性返回。

在onMounted生命周期中访问ref变量,即元素实例。

第一步:

<div class="point point-flicker" ref="point"></div>

第二步:

const point = ref<HTMLDivElement | null>(null);

请注意,类型填充在 HTMLDivElement 中,以便您可以享受类型推断。

第三步:

return { point };

这一步是必不可少的。 如果返回的对象不包含同名属性,则onMounted中访问的ref对象将为null。

第四步:

onMounted(() => {
  if (point?.value) {
    // logic
  }
});

如何操作伪类?

JavaScript 很难获取伪类元素,可以采用另一种思维方式。 伪类样式引用css变量,然后通过js控制css变量,完成间接操作伪类的效果。

例如,这是一个伪类:

.point-flicker:after {
  background-colorvar(--afterBg);
}

它依赖于 afterBg 变量。

如果需要改变它的内容,只需要使用js来操作afterBg的内容即可。

point.value.style.setProperty("--bg", colorConfig[props.type].bg);

API 更改 Vue3 中的组件如何更改自己的 props?

有一种不太常见的情况,组件需要更改父组件传递给自身的 Props。

例如抽屉组件、仿框架组件等。

vue2 中常见的用法是sync 和v-model。

vue3中只推荐v-model:xxx=""。

例如父组件传递:


组件:



...




// ...
props: {
visible: {
type: Boolean,
},
},

Vue3 中手表使用的变化

手表变得越来越简单。

import { watch } from "vue";

watch(source, (currentValue, oldValue) => {
    // logic
});

当源发生变化时,手动执行watch第二个参数传入的函数。

Vue3 中计算使用量的变化

计算也变得越来越简单。

import { computed } from "vue"

const v = computed(() => {
    return x
});

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

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 }}

<Menu
@select="select"
v-for="item in menu.children"
:key="item.id"
:menu="item"
/>



import { defineComponent } from "vue";

export default defineComponent({
name: "Menu",
props: {
menu: {
type: Object,
},
},
});

组件的名称可以直接在其本身使用,无需在组件中声明。

Vuex的一些坑:谨慎使用Map

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

type Code = number;
export type ModuleState = Map;

然而,我发现了一个问题。 当我改变Map中某个值的属性时,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会提示这些方法可用。 如果使用此方法,您将收到 UncaughtTypeError。

如果使用Object,就不会出现这个问题。

WebSocket异常很难被trycatch窃听

ws的异常只能在onerror和onclose这两场风暴中处理,而trycatch很难捕获。

有时onerror和onclose会连续执行,比如触发onerror,导致连接关闭typescript不定参数,然后触发onclose。

Vue开发工具

Vuedevtools 目前很难支持 Vue3。 不过,vuedevtools几乎是开发中不可或缺的工具。 目前,vuedevtools的测试版可以使用,但存在一些bug。

下载链接:

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

ESbuild安装依赖

使用vite启动服务时,安装依赖时特别容易遇到错误。

Error: EBUSY: resource busy or locked, open 'E:gxtproperty-relay-fednode_modulesesbuildesbuild.exe'

该问题的原因是vite依赖的编译工具esbuild.exe被占用。 解决办法很简单,就是停止vite,安装好依赖后重新启动vite。

Chrome中vite调试问题

系统中有一些联通页面,需要嵌入到App中才能使用。

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

然而,vconsole 并没有想象中那么好用。

图片.png

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

然而在调试过程中,我发现TS源码居然在Chrome调试工具上运行,直接认为TS的句型有错误。 (我使用的是Vite启动的开发服务。)

解决方案很简单,但相当低。 首先使用vitebuild将TS代码编译成JStypescript不定参数,然后使用vitepreview启动服务。

WebSocket

websocket与Vue3无关,这里简单提一下。

设备管理系统的核心概念是设备。 设备有很多属性,这些属性也称为硬件上的数据点。 这些属性通过一个特别长的链接传输到用户界面。 整体流程大致是:硬件通过tcp合约上传到接入网段,接入网段处理后通过mqtt合约上传到物联网平台,物联网平台经过规则引擎处理后发送通过webhookrestful到业务系统。 然后通过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的连接状态是非常麻烦的。 添加连接日志功能是一个很好的解决方案,这样可以看到不同时间的连接状态。

图片.png

需要注意的是,这种日志存储在用户浏览器的显存中,需要设置一个上限,达到上限后必须手动删除初始日志。

WebSocket 信令

websocket的信令是很多人容易忽视的一点。

在我的系统设计中,restfulAPI信令是通过将Authorization数组附加到requestheader并设置生成的JWT来实现的。

Websocket无法设置header,可以设置查询来实现类似的restful认证设计。

关于ws信令的过期、续订、权限等问题,与restful保持一致即可。

scriptsetup:越来越新鲜的API

scriptsetup 仍然是一个实验性功能,但它确实令人耳目一新。

单文件组件的setup一般用法如下:


import { defineComponent } from 'vue'

export default defineComponent({
setup () {
return {}
}
})

使用scriptsetup后,代码如下所示:




sciprt标签中顶层的变量和函数都会返回出来。

在这些模式下,减少了大量的代码,可以提高开发效率,减轻精神负担。

但此时也存在几个问题,比如如何使用scriptsetup中的生命周期和watch/compulated函数? 如何使用组件? 如何获取道具和上下文?

使用组件

直接导出组件后,Vue会手动识别,无需使用组件挂载。


import C from "component"

使用寿命和窃听来估计函数

和标准写法基本没有区别。


import { watch, computed, onMounted } from "vue"

使用道具和上下文

因为setup提升到了script标签,自然就没有办法接收props和context这两个参数了。

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

定义道具

DefineProps的用法与O​​ptionsAPI中props的用法几乎相同。

<script setup lang="ts">
import { defineProps } from "vue";

interface Props {
  moduleID: string;
}

const props = defineProps(["moduleID"]);
console.log(props.moduleID);
</script>

定义发射

DefineEmit的用法与O​​ptionsAPI中emit的用法几乎相同。

<script setup lang="ts">
import { defineEmit } from "vue";

const emit = defineEmit(["select"]);
console.log(emit("select"));
</script>

emit的第一个参数是事件的名称,它支持传递可变数量的参数。

使用上下文

useContext 是一个返回上下文对象的钩子函数。

const ctx = useContext()

原则

原理很简单。 编译过程减少一层,scriptsetup编译成标准模式代码。

而且实现上还有很多细节,所以即将发布的版本还没有发布。

Vue3Composition带来的模块化开发方式

这个技术栈给我带来最深的体会就是开发方式的改变。

在Vue2的开发中,OptionsAPI面对业务逻辑复杂的页面非常费力。 当逻辑长达数千行时,跟踪变量的变化确实是一件令人头痛的事情。

而有了CompositionAPI,这将不再是问题,它带来了一种新的开发方式,虽然有一种React的感觉,但这相比之前已经很不错了!

本项目中所有页面均采用hooks的形式开发。

在设备模块中,我的js代码是这样的。

<script lang="ts">
import { defineComponent, toRefs } from "vue";
import { useDeviceCreate } from "./create";
import { useDeviceQuery } from "./query";
import { useDeviceDelete } from "./delete";
import { useUnbind } from "./unbind";
import { useBind } from "./bind";
import { useDeviceEdit } from "./edit";
import { useState } from "./state";
import { useAssign } from "./assign";

export default defineComponent({
  setup() {
    const queryObj = useDeviceQuery();
    const { query, devices } = queryObj;
    const reload = query;
    return {
      ...toRefs(useDeviceCreate(reload)),
      ...toRefs(queryObj),
      ...toRefs(useDeviceDelete(reload)),
      ...toRefs(useUnbind(reload)),
      ...toRefs(useBind(reload)),
      ...toRefs(useDeviceEdit(reload)),
      ...toRefs(useState(devices)),
      ...toRefs(useAssign()),
    };
  },
});
</script>

每个模块各司其职,有自己的内部数据。 如果各个模块需要共享数据,可以通过Vuex传递,也可以在顶层组件的setup中传递,比如之前的reload函数。

我的目录结构是这样的。

图片.png

整体来说非常清爽,工程感越来越强。

后端架构与前端架构不同。

前端考虑更多的是高可用性、高性能、可扩展性。 后端考虑的问题更多的是如何实现高内聚低耦合的分层设计,架构就是设计。

良好的架构设计可以大大提高开发效率,减轻开发人员的心理负担。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 typescript typescript不定参数-Vue3+TypeScript 回顾总结 https://www.wkzy.net/game/177531.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务