Heim  >  Artikel  >  Web-Frontend  >  So verwenden Sie TypeScript in Vue3

So verwenden Sie TypeScript in Vue3

WBOY
WBOYnach vorne
2023-05-13 23:46:04880Durchsuche

Wie deklariere ich einen Typ, dessen Feldname eine Aufzählung ist?

Entsprechend dem Design sollte das Typfeld ein Aufzählungswert sein und nicht willkürlich vom Aufrufer festgelegt werden.

Das Folgende ist die Aufzählungsdeklaration des Typs mit insgesamt 6 Feldern.

enum Type {    primary = "primary",    success = "success",    warning = "warning",    warn = "warn", // warning alias    danger = "danger",    info = "info",  }

Es gibt zwei Schlüsselwörter zum Deklarieren von Typen in TypeScript, interface und type, die sich beim Deklarieren von Feldern mit undefinierten Schlüsseltypen geringfügig unterscheiden.

Typ zum Deklarieren verwenden:

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

Die Verwendung der Schnittstelle kann nur so sein:

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

Da der Index der Schnittstelle nur der Basistyp sein kann , Typaliase gibt es auch nicht. Der Typindex kann ein zusammengesetzter Typ sein.

Vue 3 Wie bekomme ich eine Elementinstanz?

In vue3 kann die Logik der Komponente in der Setup-Funktion platziert werden, aber es gibt kein this mehr im Setup, sodass die Verwendung von this.$refs in vue2 nicht in vue3 verwendet werden kann.

Die neue Verwendung lautet:

Fügen Sie dem Element das ref-Attribut hinzu.

Deklarieren Sie eine Variable mit demselben Namen wie die Elementreferenz im Setup.

Gibt die Ref-Variable als Eigenschaft mit demselben Namen im Rückgabeobjekt von Setup zurück.

Greifen Sie auf die Ref-Variable im onMounted-Lebenszyklus zu, bei der es sich um eine Elementinstanz handelt.

Schritt eins:

<div></div>

Schritt zwei:

const point = ref<htmldivelement>(null);</htmldivelement>

Beachten Sie, dass der Typ in HTMLDivElement ausgefüllt werden muss, damit Sie Typinferenz genießen können.

Der dritte Schritt:

return { point };

Dieser Schritt ist wichtig. Wenn das zurückgegebene Objekt diese Eigenschaft mit demselben Namen nicht enthält, ist das Referenzobjekt, auf das in onMounted zugegriffen wird, null.

Schritt 4:

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

Wie betreibt man Pseudoklassen?

JavaScript kann keine Pseudoklassenelemente erhalten, aber Sie können es sich anders vorstellen. Der Pseudoklassenstil bezieht sich auf CSS-Variablen und steuert dann die CSS-Variablen über js, um den Effekt der indirekten Bedienung der Pseudoklasse zu vervollständigen.

Zum Beispiel ist dies eine Pseudoklasse:

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

Es hängt von der Variable afterBg ab.

Wenn Sie den Inhalt ändern müssen, müssen Sie nur js verwenden, um den Inhalt von afterBg zu bedienen.

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

API-Änderungen

Wie modifizieren Komponenten ihre eigenen Requisiten in Vue3?

Es kommt nicht sehr häufig vor, dass eine Komponente die von der übergeordneten Komponente an sie selbst übergebenen Requisiten ändern muss.

Zum Beispiel Schubladenkomponenten, Blindboxkomponenten usw.

Allgemeine Verwendung in Vue2 ist Synchronisierung und V-Modell.

vue3 empfiehlt nur die Verwendung von v-model:xxx="".

Zum Beispiel übergibt die übergeordnete Komponente:

<ws-log></ws-log>

Untergeordnete Komponente:

<template>      <div>      ...     </div>  </template>  <script>  // ...   props: {      visible: {        type: Boolean,      },    },  </script>

Änderungen in der Uhrennutzung in Vue3

#🎜🎜 #Änderungen beobachten Das muss einfacher sein.

import { watch } from "vue";  watch(source, (currentValue, oldValue) => {      // logic  });
Wenn sich die Quelle ändert, wird die im zweiten Parameter von watch übergebene Funktion automatisch ausgeführt.

Änderungen bei der Computernutzung in Vue3

computed ist ebenfalls einfacher geworden.

import { computed } from "vue"  const v = computed(() => {      return x  });
computed Die zurückgegebene Variable ist ein reaktives Objekt.

Die Technik der Komponentenschleife in Vue3

Dies ist eine Technik zur Entwicklung von Komponenten.

Angenommen, Sie haben baumstrukturierte Daten mit ungewisser Tiefe.

{    "label": "root",    "children": [      {        "label": "a",        "children": [          {            "label": "a1",            "children": []          },          {            "label": "a2",            "children": []          }        ]      }    ]  }
Sein Typ ist wie folgt definiert:

export interface Menu {    id: string;    label: string;    children: Menu | null;  }
Sie müssen eine Baumkomponente implementieren, um sie zu rendern. Hier bietet sich diese Technik an.

<template>      <div>{{ menu.label }}</div>      <menu></menu>  </template>  <script>  import { defineComponent } from "vue";  export default defineComponent({    name: "Menu",    props: {      menu: {        type: Object,      },    },  });  </script>
Der Name der Komponente kann direkt in sich selbst verwendet werden, ohne in der Komponente deklariert zu werden.

Einige Fallstricke

Vuex: Karte mit Vorsicht verwenden

In Vuex habe ich eine Datenstruktur für den Status verschiedener Speichermodule (Geschäftskonzepte) entworfen.

type Code = number;  export type ModuleState = Map<code>;</code>
Aber ich habe ein Problem festgestellt, wenn ich ein Attribut in einem Wert in der Karte ändere, wird die Überwachung von Vuex nicht ausgelöst.

Also musste ich die Datenstruktur in die Form eines Objekts ändern.

export type ModuleState = { [key in Code]: StateProperty };
ts kann keine Typaliase für Indizes verwenden, kann aber wie folgt geschrieben werden:

type Code = number;  export type ModuleState = { [key in Code]: StateProperty };
Darüber hinaus hat Map ein weiteres Problem.

Wenn ein Proxy-Objekt vom Typ Map als Parameter übergeben wird, können Map-Methoden wie get, set, clear usw. nicht verwendet werden, aber TypeScript fordert Sie auf, dass diese Methoden verfügbar sind. Wenn Sie diese Methoden verwenden, erhalten Sie einen Uncaught TypeError.

Wenn Sie Object verwenden, tritt dieses Problem nicht auf.

WebSocket-Ausnahmen können nicht durch Try Catch überwacht werden.

WS-Ausnahmen können nur in onerror- und onclose-Ereignissen behandelt werden, und Try Catch kann sie nicht abfangen.

Manchmal werden onerror und onclose kontinuierlich ausgeführt. Wenn beispielsweise onerror ausgelöst wird und die Verbindung geschlossen wird, wird onclose sofort ausgelöst.

Vue Devtools

vue devtools unterstützt Vue3 derzeit nicht, aber vue devtools ist ein nahezu unverzichtbares Tool in der Entwicklung. Die Betaversion von vue devtools kann derzeit verwendet werden, es gibt jedoch einige Käfer.

Die Verwendung ist sehr einfach, starten Sie einfach den Browser nach der Installation neu. Es ist nicht erforderlich, vue.config.devtools = true festzulegen, da das devtools-Attribut in der vue.config-Instanz in vue3 nicht vorhanden ist.

ESbuild-Installationsabhängigkeiten

Bei der Installation von Abhängigkeiten kann es sehr leicht zu einem Fehler kommen, während Vite zum Starten des Dienstes verwendet wird.

Error: EBUSY: resource busy or locked, open 'E:\gxt\property-relay-fed\node_modules\esbuild\esbuild.exe'
Der Grund für dieses Problem ist, dass das Kompilierungstool esbuild.exe, von dem Vite abhängt, belegt ist. Die Lösung ist sehr einfach: Stoppen Sie Vite, installieren Sie die Abhängigkeiten und starten Sie Vite dann neu.

Vite-Debugging-Probleme in Chrome

Es gibt einige mobile Seiten im System, die in die App eingebettet werden müssen.

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

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

所以我选择使用 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 的连接状态很麻烦,添加一个连接日志功能是比较不错的方案,这样可以很好的看到不同时间的连接情况。

So verwenden Sie TypeScript in Vue3

image.png

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

WebSocket 鉴权

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

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

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

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

script setup:更加清爽的 API

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

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

<script> import { defineComponent } from &#39;vue&#39;  export default defineComponent({   setup () {      return {}    }  })  </script>

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

<script>    </script>

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

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

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

使用组件

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

<script>    import C from "component"  </script>

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

和标准写法基本无差异。

<script>    import { watch, computed, onMounted } from "vue"  </script>

使用 props 和 context

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

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

defineProps

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

<script>  import { defineProps } from "vue";  interface Props {    moduleID: string;  }  const props = defineProps<Props>(["moduleID"]);  console.log(props.moduleID);  </script>

defineEmit

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

<script>  import { defineEmit } from "vue";  const emit = defineEmit(["select"]);  console.log(emit("select"));  </script>

emit 的第一个参数是事件名称,后面支持传递不定个数的参数。

useContext

useContext 是一个 hook 函数,返回 context 对象。

const ctx = useContext()

原理

原理相当简单。增加了一层编译过程,将 script setup 编译成标准模式的代码。

但是实现上有非常多的细节,所以导致至今仍未推出正式版。

Vue3 Composition 所带来的模块化开发方式

这套技术栈带给我最深的感受还是开发方式上的变化。

在 Vue2 的开发中,Options API 在面对业务逻辑复杂的页面时非常吃力。当逻辑长达千行时,追踪一个变量的变化是一件非常头痛的事情。

但是有了 Composition API 后,这将不再是问题,它带来了一种全新的开发方式,虽然有种 React 的感觉,但这相比之前已经非常棒了!

这项目中所有的页面,我都使用 hooks 的方式开发。

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

<script>  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 函数。

我的目录结构是这样的。

So verwenden Sie TypeScript in Vue3

Das obige ist der detaillierte Inhalt vonSo verwenden Sie TypeScript in Vue3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen