Vue3?? TypeScript? ???? ??
May 13, 2023 pm 11:46 PMenum??? ??? ???? ??? ???? ??? ??????
??? ?? ?? ??? ??? ???? ?? ???? ??? ????? ? ???.
??? ? 6? ??? ??? Type? ??? ?????.
enum?Type?{????primary?=?"primary",????success?=?"success",????warning?=?"warning",????warn?=?"warn",?//?warning?alias????danger?=?"danger",????info?=?"info",??}
TypeScript?? ?????? ????? ? ?? ?? ?? ???? ????. ???? ?? ? ???? ??? ??? ? ??? ??? ????.
??? ???? ??:
type?ColorConfig?=?{????[key?in?Type]:?Colors;??};
?????? ????? ??? ??? ?????.
interface?ColorConfig?{????[key:?string]:?Colors;??}
?????? ???? ?? ??? ???? ?? ??? ??? ? ????. ??? ???? ?? ??? ? ????.
Vue 3?? ?? ????? ?? ??? ??????
vue3??? ????? ??? setup ??? ??? ? ??? setup?? ? ?? this? ???? vue2? this.$refs ???? vue3??? ??? ? ????.
??? ???? ??? ????.
??? ref ??? ?????.
??? ?? ??? ??? ??? ?? ??? ?????.
??? ?? ??? ref ??? ??? ??? ???? ?????.
?? ????? onMounted ??? ???? ref ??? ??????.
1??:
<div></div>
2??:
const?point?=?ref<htmldivelement>(null);</htmldivelement>
HTMLDivElement? ??? ??? ?? ??? ?? ? ??? ?? ?????.
3??:
return?{?point?};
? ??? ?????. ??? ??? ??? ??? ? ??? ???? ?? ??? onMounted?? ???? ref ??? null? ???.
4??:
onMounted(()?=>?{????if?(point?.value)?{??????//?logic????}??});
?? ???? ???? ??? ??????
JavaScript? ?? ??? ??? ??? ? ??? ??? ??? ? ????. ?? ??? ???? CSS ??? ??? ? js? ?? CSS ??? ???? ?? ???? ????? ????? ??? ?????.
?? ?? ??? ?? ??????.
.point-flicker:after?{????background-color:?var(--afterBg);??}
afterBg ??? ?? ????.
???? ???? ?? ?? js? ???? afterBg? ???? ???? ???.
point.value.style.setProperty("--bg",?colorConfig[props.type].bg);
API ??
Vue3? ?? ??? ??? ?? ??? ??????
?? ??? ?? ?? ??? ?? ????? ??? Prop? ???? ?? ??? ??? ????.
?? ?? ??, ?? ?? ?? ?? ?
vue2? ???? ???? sync? v-model???.
vue3??? v-model:xxx=""? ?????.
?? ?? ?? ?? ??? ??? ?????.
<ws-log></ws-log>
?? ?? ??:
<template>??????<div>??????...?????</div>??</template>??<script> // ... props: { visible: { type: Boolean, }, }, </script>
Vue3? ?? ??? ??
watch? ? ??????.
import?{?watch?}?from?"vue";??watch(source,?(currentValue,?oldValue)?=>?{??????//?logic??});
??? ???? watch? ? ?? ????? ??? ??? ???? ?????.
Vue3
computed? ?? ??? ??? ? ???????.
import?{?computed?}?from?"vue"??const?v?=?computed(()?=>?{??????return?x??});
computed?? ??? ??? ??? ?????.
Vue3?? ???? ??? Looping?? ??
????? ???? ?????.
??? ???? ?? ??? ???? ??? ??? ?????.
{????"label":?"root",????"children":?[??????{????????"label":?"a",????????"children":?[??????????{????????????"label":?"a1",????????????"children":?[]??????????},??????????{????????????"label":?"a2",????????????"children":?[]??????????}????????]??????}????]??}
??? ??? ?? ?????.
export?interface?Menu?{????id:?string;????label:?string;????children:?Menu?|?null;??}
?????? ?? ?? ??? ???? ???. ? ??? ??? ????.
<template>??????<div>{{?menu.label?}}</div>??????<menu></menu>??</template>??<script> import { defineComponent } from "vue"; export default defineComponent({ name: "Menu", props: { menu: { type: Object, }, }, }); </script>
???? ??? ?????? ???? ?? ? ??? ?? ??? ? ????.
? ?? ??
Vuex: Map? ???? ?????
Vuex??? ??? ??? ??(???? ??)? ???? ??? ??? ??????.
type?Code?=?number;??export?type?ModuleState?=?Map<code>;</code>
??? ?? ?? ?? ??? ???? 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 ?? ??? ??? ? ??? ? ?? ??? ????.
???? ?? ?????. ?? ? ????? ?? ???? ???. vue.config.devtools = true? ??? ??? ????. devtools ??? vue3? vue.config ????? ???? ????.
ESbuild ?? ???
vite? ???? ???? ???? ?? ???? ??? ? ??? ???? ?? ????.
Error:?EBUSY:?resource?busy?or?locked,?open?'E:\gxt\property-relay-fed\node_modules\esbuild\esbuild.exe'
? ??? ??? vite? ???? ??? ?? esbuild.exe? ???? ?? ?????. ?? ??? ?? ?????. ?, vite? ???? ???? ??? ?? vite? ?? ???? ????.
Chrome?? Vite ??? ?? ??
???? ?? ???? ?? ?? ??? ???? ????.
常見的調(diào)試 WebView 的方法有兩種,一種簡(jiǎn)單的方式是使用騰訊開源的 vcosnole,另一種麻煩一些的調(diào)試方式是使用 Chrome 的 DevTools。
但是 vconsole 并沒有想象中那么好用。
所以我選擇使用 Chrome 調(diào)試,chrome://inspect/#devices
但是在調(diào)試過程中我發(fā)現(xiàn) Chrome 調(diào)試工具里面竟然運(yùn)行的是 TS 源碼,TS 的語(yǔ)法直接被認(rèn)為語(yǔ)法錯(cuò)誤。(我是使用 Vite 啟動(dòng)的開發(fā)服務(wù)。)
解決方案很簡(jiǎn)單,但挺 Low。先使用 vite build 把 TS 代碼編譯成 JS,再使用 vite preview 啟動(dòng)服務(wù)。
WebSocket
websocket 和 Vue3 沒什么關(guān)系,但是在這里簡(jiǎn)單提一下。
設(shè)備管理系統(tǒng)的核心概念是設(shè)備,設(shè)備會(huì)有很多屬性,在硬件上也被稱作數(shù)據(jù)點(diǎn)。這些屬性會(huì)經(jīng)歷非常長(zhǎng)的鏈路傳輸?shù)接脩艚缑嫔稀Uw流程大概是:硬件通過 tcp 協(xié)議上傳到接入網(wǎng)關(guān),接入網(wǎng)關(guān)處理后再通過 mqtt 協(xié)議上傳到物聯(lián)網(wǎng)平臺(tái),物聯(lián)網(wǎng)平臺(tái)再經(jīng)過規(guī)則引擎處理,通過 webhook restful 的形式發(fā)送到業(yè)務(wù)系統(tǒng),業(yè)務(wù)系統(tǒng)再通過 websocket 推送到前端。
雖然數(shù)據(jù)通過層層編解碼、不同的協(xié)議繞了非常遠(yuǎn)的距離呈現(xiàn)到用戶面前,但是前端只需要關(guān)心 websocket 就足夠了。
WebSocket 重連
在做重連時(shí),需要注意 onerror 和 onclose 連續(xù)執(zhí)行的問題,通常是使用類似防抖的方法來解決。
我的做法是增加一個(gè)變量來控制重連次數(shù)。
let connecting = false; // 斷開連接后,先觸發(fā) onerror,再觸發(fā) onclose,主要用于防止重復(fù)觸發(fā)
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 連接活動(dòng)日志
系統(tǒng)是設(shè)計(jì)成 7*24 小時(shí)不間斷運(yùn)行。所以 websocket 很容易受到一些網(wǎng)絡(luò)因素或者其它因素的影響發(fā)生斷開,重連是一項(xiàng)非常重要的功能,同時(shí)還應(yīng)該具備重連日志功能。
在用戶的不同環(huán)境中,排查 WebSocket 的連接狀態(tài)很麻煩,添加一個(gè)連接日志功能是比較不錯(cuò)的方案,這樣可以很好的看到不同時(shí)間的連接情況。
image.png
需要注意,這些日志是存儲(chǔ)在用戶的瀏覽器內(nèi)存中的,需要設(shè)置上限,到達(dá)上限要自動(dòng)清除早期日志。
WebSocket 鑒權(quán)
websocket 的鑒權(quán)是很多人容易忽視的一個(gè)點(diǎn)。
我在系統(tǒng)設(shè)計(jì)中,restful API 的鑒權(quán)是通過在 request header 上附帶 Authorization 字段,設(shè)置生成的 JWT 來實(shí)現(xiàn)的。
websocket 無法設(shè)置 header,但是可以設(shè)置 query,實(shí)現(xiàn)思路類似 restful 的認(rèn)證設(shè)計(jì)。
關(guān)于 ws 鑒權(quán)的過期、續(xù)期、權(quán)限等問題,和 restful 保持一致即可。
script setup:更加清爽的 API
script setup 至今仍是一個(gè)實(shí)驗(yàn)性特性,但它確實(shí)非常清爽。
單文件組件的 setup 常規(guī)用法像下面這樣:
<script> import { defineComponent } from 'vue' export default defineComponent({ setup () { return {} } }) </script>
使用 script setup 后,代碼變成了下面這樣:
<script> </script>
在 sciprt 標(biāo)簽中的頂層變量、函數(shù)都會(huì) return 出去。
在這種模式下,減少了大量代碼,可以提高開發(fā)效率、降低心智負(fù)擔(dān)。
但這時(shí)也存在幾個(gè)問題,比如在 script setup 中怎么使用生命周期和 watch/computed 函數(shù)?怎么使用組件?怎么獲取 props 和 context?
使用組件
直接導(dǎo)入組件后,vue 會(huì)自動(dòng)識(shí)別,無需使用 component 掛載。
<script> import C from "component" </script>
使用生命周期和監(jiān)聽計(jì)算函數(shù)
和標(biāo)準(zhǔn)寫法基本無差異。
<script> import { watch, computed, onMounted } from "vue" </script>
使用 props 和 context
由于 setup 被提升到 script 標(biāo)簽上了,自然也就沒辦法接收 props 和 context 這兩個(gè)參數(shù)。
所以 vue 提供了 defineProps、defineEmit、useContext 函數(shù)。
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 的第一個(gè)參數(shù)是事件名稱,后面支持傳遞不定個(gè)數(shù)的參數(shù)。
useContext
useContext 是一個(gè) hook 函數(shù),返回 context 對(duì)象。
const?ctx?=?useContext()
原理
原理相當(dāng)簡(jiǎn)單。增加了一層編譯過程,將 script setup 編譯成標(biāo)準(zhǔn)模式的代碼。
但是實(shí)現(xiàn)上有非常多的細(xì)節(jié),所以導(dǎo)致至今仍未推出正式版。
Vue3 Composition 所帶來的模塊化開發(fā)方式
這套技術(shù)棧帶給我最深的感受還是開發(fā)方式上的變化。
在 Vue2 的開發(fā)中,Options API 在面對(duì)業(yè)務(wù)邏輯復(fù)雜的頁(yè)面時(shí)非常吃力。當(dāng)邏輯長(zhǎng)達(dá)千行時(shí),追蹤一個(gè)變量的變化是一件非常頭痛的事情。
但是有了 Composition API 后,這將不再是問題,它帶來了一種全新的開發(fā)方式,雖然有種 React 的感覺,但這相比之前已經(jīng)非常棒了!
這項(xiàng)目中所有的頁(yè)面,我都使用 hooks 的方式開發(fā)。
在設(shè)備模塊中,我的 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>
每個(gè)模塊各司其職,各自有自己的內(nèi)部數(shù)據(jù),各個(gè)模塊如果需要共享數(shù)據(jù),可以通過 Vuex,或者在頂層組件的 setup 中傳遞,比如上面的 reload 函數(shù)。
我的目錄結(jié)構(gòu)是這樣的。
? ??? Vue3?? TypeScript? ???? ??? ?? ?????. ??? ??? PHP ??? ????? ?? ?? ??? ?????!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

???? ????? ?? ???? ?? ?? ??(dom)? ?? ???? ???? ???. Vue?? ? ??? ?? ?? ?? ??? v-if ???? ???? ????. Vue2??? v-if ??? ???? ?? DOM? ?? ????? ? ??? ? ? ?? ??? ?? ?? ????. ?? ???? ?? ??? ? ?? ? ? ?? ?? ???? ??? ?? ?? ??? ? ????. ? ?? ???? beforeRouteEnter ??. ?? ??? ?? Vue3.X?? ?? ?? ??? ???? ??? ?? ?? DOM? ?? ???? ?? ?? ??? ???? ?????. Vue3.X? scriptsetup ??? ?? ?? ??? ????

?? ??? VueCropper ???? Yarnaddvue-cropper@next? ???? ????. ?? ?? ?? Vue2??? ?? ??? ???? ????? ?? ?? npm ??: ?? ????? ?????. ?????? ???? ???? ?? ?? ?????. ???? ?? ????? ?? ??? ??? ????? ?? ???. ???? import{userInfoByRequest}from'../js/api? ???? ???. ? ?? ?? ???? import{VueCropper}from'vue-cropper&

vue3+ts+axios+pinia? ???? ?? ??? ?????. 1. ?? ?????? aiXos ? pinianpmipinia? ???????--savenpminstallaxios--save2. AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess

MySQL? ???? TypeScript?? ??? ?? ?? ??? ???? ?? ??: ??? ?? ??? ? ??????? ??? ? ?? ???? ?? ?????. ??????? ??? ???? ??? ?, ?? MySQL? ??? ??????? ??? ? ?? ??? ???? ??? ???? ???? ?? ??? ????. ? ????? MySQL? ???? TypeScript?? ??? ?? ??? ???? ??? ???? ?? ??? ?????. 1. ??: ??

Vue? ???? ??? ?? ?? ?? WebComponents? ???? ??? ??? ??? ?? ??(customelements)? ??? ? ?? ? ???? API ??? ??? ?????. ??? ?? ??? ?? ??? ????? ??? ?? ???????? ??? ? ??? ????. ?? ??? ?? ?? ??? ???? ?? ???? ???? ??? ???? ?? ??? ?? ?? ???? ?? ??????? ????? ??? ??????. Vue? WebComponents? ???? ???? Vue? ??? ?? ??? ???? ???? ? ??? ??? ?????. ??? ?? ??? ?? Vue ??????? ????? Vue? ???? ??? ? ????.

Redis ? TypeScript? ???? ??? ??? ??? ???? ?? ??: Redis? ???? ???? ?? ?? ?? ???? ??? ?? ???? ??????. TypeScript? ?? ???? ? ?? ?? ?? ??? ???? JavaScript? ?? ?????. Redis? TypeScript? ???? ??? ??? ??? ???? Redis? ??? ?? ? ??? ??? ??? ??? ? ?? ???? ??? ??? ??? ? ????. ? ????? ?? ??? ?????.

?? ?? createApp ??? packages/runtime-dom/src/index.ts ??? ???? ????. importconstcreateApp=((...args)=>{constapp=ensureRenderer().createApp(...args)if(__DEV__){ injectNativeTagCheck(app)injectCompilerOptionsCheck(app)}const{mount}=appapp.mount=(containerOrSelector

vue3? ??: 1, ?? ?, 2, ???, 3, ??? ?, 4, ????, 5, ???? ?, 6, ?????, 7, ?? ?, 8, ???, 9, ????, 10, ?????, 11, ?? ???; 12 、getDerivedStateFromProps
