<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3+TypeScript 完整項目上手教程

          共 8284字,需瀏覽 17分鐘

           ·

          2020-09-29 09:15

          轉(zhuǎn)自:Vue3擁抱TypeScript的正確姿勢 :https://juejin.im/post/6875713523968802829

          一個完整的Vue3+Ts項目,支持.vue和.tsx寫法

          項目地址:https://github.com/vincentzyc/vue3-demo.git

          TypeScript 是JS的一個超集,主要提供了類型系統(tǒng)和對ES6的支持,使用 TypeScript 可以增加代碼的可讀性和可維護性,在 reactvue 社區(qū)中也越來越多人開始使用TypeScript。從最近發(fā)布的 Vue3 正式版本來看, Vue3 的源碼就是用 TypeScript 編寫的,更好的 TypeScript 支持也是這一次升級的亮點。當(dāng)然,在實際開發(fā)中如何正確擁抱 TypeScript 也是遷移至 Vue3 的一個小痛點,這里就針對 Vue3TypeScript 展開一些交流。

          46eeb9142f128e0796edd893e1c6b876.webp

          96.8%的代碼都是TypeScript,支持的力度也是相當(dāng)大?

          • Vue3入口: https://github.com/vuejs/vue-next

          項目搭建

          在官方倉庫的 Quickstart 中推薦用兩種方式方式來構(gòu)建我們的 SPA 項目:

          • vite
          npm?init?vite-app?sail-vue3?#?OR?yarn?create?vite-app?sail-vue3
          • vue-cli
          npm?install?-g?@vue/cli?#?OR?yarn?global?add?@vue/cli
          vue?create?sail-vue3
          #?select?vue?3?preset

          vite 是一個由原生ESM驅(qū)動的Web開發(fā)構(gòu)建工具,打開 vite 依賴的 package.json 可以發(fā)現(xiàn)在 devDependencies 開發(fā)依賴?yán)锩嬉呀?jīng)引入了TypeScript ,甚至還有 vuex , vue-router , less , sass 這些本地開發(fā)經(jīng)常需要用到的工具。vite 輕量,開箱即用的特點,滿足了大部分開發(fā)場景的需求,作為快速啟動本地 Vue 項目來說,這是一個非常完美的工具。

          后面的演示代碼也是用vite搭的

          vue2.x 走過來的掘友肯定知道 vue-cli 這個官方腳手架, vue3 的更新怎么能少得了 vue-cli 呢, vue-cli 更強調(diào)的是用 cli 的方式進行交互式的配置,選擇起來更加靈活可控。豐富的官方插件適配,GUI的創(chuàng)建管理界面,標(biāo)準(zhǔn)化開發(fā)流程,這些都是 vue-cli 的特點。

          • vue-cli ? TypeScript STEP1
          c10ddc705f7a67ce2620e84814104fba.webp
          • vue-cli ? TypeScript STEP2
          a08f984d5e7e24b4cd69ac79cd28660a.webp

          想要預(yù)裝TypeScript,就需要選擇手動配置,并check好TypeScript

          忘記使用選擇 TypeScript 也沒事,加一行cli命令就行了

          vue?add?typescript

          最后,別忘了在 .vue 代碼中,給 script 標(biāo)簽加上 lang="ts"

          <script?lang="ts">

          Option API風(fēng)格

          Vue2.x 使用過 TypeScript 的掘友肯定知道引入 TypeScript 不是一件簡單的事情:

          1. 要用 vue-class-component 強化 vue 組件,讓 Script 支持 TypeScript 裝飾器
          2. vue-property-decorator 來增加更多結(jié)合 Vue 特性的裝飾器
          3. 引入 ts-loaderwebpack 識別 .ts .tsx 文件
          4. .....

          然后出來的代碼風(fēng)格是這樣的:

          @Component({
          ????components:{?componentA,?componentB},
          })
          export?default?class?Parent?extends?Vue{
          ??@Prop(Number)?readonly?propA!:?number?|?undefined
          ??@Prop({?default:?'default?value'?})?readonly?propB!:?string
          ??@Prop([String,?Boolean])?readonly?propC!:?string?|?boolean?|?undefined

          ??//?data信息
          ??message?=?'Vue2?code?style'

          ??//?計算屬性
          ??private?get?reversedMessage?():?string[]?{
          ??????return?this.message.split('?').reverse().join('')
          ??}

          ??//?method
          ??public?changeMessage?():?void?{
          ????this.message?=?'Good?bye'
          ??}
          }

          class 風(fēng)格的組件,各種裝飾器穿插在代碼中,有點感覺自己不是在寫 vue ,些許凌亂?,所以這種曲線救國的方案在 vue3 里面肯定是行不通的。

          vue3 中可以直接這么寫:

          import?{?defineComponent,?PropType?}?from?'vue'

          interface?Student?{
          ??name:?string
          ??class:?string
          ??age:?number
          }

          const?Component?
          =?defineComponent({
          ??props:?{
          ????success:?{?type:?String?},
          ????callback:?{
          ??????type:?Function?as?PropType<()?=>?void>
          ????},
          ????student:?{
          ??????type:?Object?as?PropType,
          ??????required:?true
          ????}
          ??},
          ??data()?{
          ?????return?{
          ????????message:?'Vue3?code?style'
          ????}
          ??},
          ??computed:?{
          ????reversedMessage():?string?{
          ??????return?this.message.split('?').reverse().join('')
          ????}
          ??}
          })

          vueprops 進行復(fù)雜類型驗證的時候,就直接用 PropType 進行強制轉(zhuǎn)換, data 中返回的數(shù)據(jù)也能在不顯式定義類型的時候推斷出大多類型, computed 也只用返回類型的計算屬性即可,代碼清晰,邏輯簡單,同時也保證了 vue 結(jié)構(gòu)的完整性。

          Composition API風(fēng)格

          vue3Composition API 代碼風(fēng)格中,比較有代表性的api就是 refreactive ,我們看看這兩個是如何做類型聲明的:

          ref

          import?{?defineComponent,?ref?}?from?'vue'

          const?Component?=?defineComponent({
          setup()?{
          ??const?year?=?ref(2020)
          ??const?month?=?ref('9')

          ??month.value?=?9?//?OK
          ??const?result?=?year.value.split('')?//?=>?Property?'split'?does?not?exist?on?type?'number'
          ?}
          })

          分析上面的代碼,可以發(fā)現(xiàn)如果我們不給定 ref 定義的類型的話, vue3 也能根據(jù)初始值來進行類型推導(dǎo),然后需要指定復(fù)雜類型的時候簡單傳遞一個泛型即可。

          Tips:如果只有setup方法的話,可以直接在defineComponent中傳入setup函數(shù)

          const?Component?=?defineComponent(()?=>?{
          ????const?year?=?ref(2020)
          ????const?month?=?ref('9')

          ????month.value?=?9?//?OK
          ????const?result?=?year.value.split('')?//?=>?Property?'split'?does?not?exist?on?type?'number'
          })

          reactive

          import?{?defineComponent,?reactive?}?from?'vue'

          interface?Student?{
          ??name:?string
          ??class?:?string
          ??age:?number
          }

          export?default?defineComponent(
          {
          ??name:?'HelloWorld',
          ??setup()?{
          ????const?student?=?reactive({?name:?'阿勇',?age:?16?})
          ????//?or
          ????const?student:?Student?=?reactive({?name:?'阿勇',?age:?16?})
          ????//?or
          ????const?student?=?reactive({?name:?'阿勇',?age:?16,?class:?'cs'?})?as?Student
          ??}
          })

          聲明 reactive 的時候就很推薦使用接口了,然后怎么使用類型斷言就有很多種選擇了,這是 TypeScript 的語法糖,本質(zhì)上都是一樣的。

          自定義Hooks

          vue3 借鑒 react hooks 開發(fā)出了 Composition API ,那么也就意味著 Composition API 也能進行自定義封裝 hooks ,接下來我們就用 TypeScript 風(fēng)格封裝一個計數(shù)器邏輯的 hooksuseCount ):

          首先來看看這個 hooks 怎么使用:

          import?{?ref?}?from?'/@modules/vue'
          import??useCount?from?'./useCount'

          export?default?{
          ??name:?'CountDemo',
          ??props:?{
          ????msg:?String
          ??},
          ??setup()?{
          ????const?{?current:?count,?inc,?dec,?set,?reset?}?=?useCount(2,?{
          ??????min:?1,
          ??????max:?15
          ????})
          ????const?msg?=?ref('Demo?useCount')

          ????return?{
          ??????count,
          ??????inc,
          ??????dec,
          ??????set,
          ??????reset,
          ??????msg
          ????}
          ??}
          }

          出來的效果就是:

          eb9565d958627ef9a47558fbd33b5057.webp

          貼上 useCount 的源碼:

          import?{?ref,?Ref,?watch?}?from?'vue'

          interface?Range?{
          ??min?:?number,
          ??max?:?number
          }

          interface?Result?{
          ??current:?Ref,
          ??inc:?(delta?:?number)?=>?void,
          ??dec:?(delta?:?number)?=>?void,
          ??set:?(value:?number)?=>?void,
          ??reset:?()?=>?void
          }

          export?default?function?useCount(initialVal:?number,?range?:?Range):?Result?{
          ??const?current?=?ref(initialVal)
          ??const?inc?=?(delta?:?number):?void?=>?{
          ????if?(typeof?delta?===?'number')?{
          ??????current.value?+=?delta
          ????}?else?{
          ??????current.value?+=?1
          ????}
          ??}
          ??const?dec?=?(delta?:?number):?void?=>?{
          ????if?(typeof?delta?===?'number')?{
          ??????current.value?-=?delta
          ????}?else?{
          ??????current.value?-=?1
          ????}
          ??}
          ??const?set?=?(value:?number):?void?=>?{
          ????current.value?=?value
          ??}
          ??const?reset?=?()?=>?{
          ????current.value?=?initialVal
          ??}

          ??watch(current,?(newVal:?number,?oldVal:?number)?=>?{
          ????if?(newVal?===?oldVal)?return
          ????if?(range?&&?range.min?&&?newVal???????current.value?=?range.min
          ????}?else?if?(range?&&?range.max?&&?newVal?>?range.max)?{
          ??????current.value?=?range.max
          ????}
          ??})

          ??return?{
          ????current,
          ????inc,
          ????dec,
          ????set,
          ????reset
          ??}
          }

          分析源碼

          這里首先是對 hooks 函數(shù)的入?yún)㈩愋秃头祷仡愋瓦M行了定義,入?yún)⒌?Range 和返回的 Result 分別用一個接口來指定,這樣做了以后,最大的好處就是在使用 useCount 函數(shù)的時候,ide就會自動提示哪些參數(shù)是必填項,各個參數(shù)的類型是什么,防止業(yè)務(wù)邏輯出錯。

          edbf5adbc35f86ed8bbe511e43cad1cb.webp

          接下來,在增加 inc 和減少 dec 的兩個函數(shù)中增加了 typeo 類型守衛(wèi)檢查,因為傳入的 delta 類型值在某些特定場景下不是很確定,比如在 template 中調(diào)用方法的話,類型檢查可能會失效,傳入的類型就是一個原生的 Event

          關(guān)于 ref 類型值,這里并沒有特別聲明類型,因為 vue3 會進行自動類型推導(dǎo),但如果是復(fù)雜類型的話可以采用類型斷言的方式:ref(initObj) as Ref

          小建議 ?

          AnyScript

          在初期使用 TypeScript 的時候,很多掘友都很喜歡使用 any 類型,硬生生把TypeScript 寫成了 AnyScript ,雖然使用起來很方便,但是這就失去了 TypeScript 的類型檢查意義了,當(dāng)然寫類型的習(xí)慣是需要慢慢去養(yǎng)成的,不用急于一時。

          Vetur

          vetur 代碼檢查工具在寫vue代碼的時候會非常有用,就像構(gòu)建 vue 項目少不了 vue-cli 一樣,vetur 提供了 vscode 的插件支持,趕著升級 vue3 這一波工作,順帶也把 vetur 也帶上吧。

          d66286aaa50435cbaf52cfa1a9059e34.webp

          一個完整的Vue3+ts項目

          ├─public
          │??????favicon.ico
          │??????index.html
          └─src
          ????│??App.vue
          ????│??main.ts
          ????│??shims-vue.d.ts
          ????├─assets
          ????│??│??logo.png
          ????│??└─css
          ????│??????????base.css
          ????│??????????main.styl
          ????├─components
          ????│??│??HelloWorld.vue
          ????│??└─base
          ????│??????????Button.vue
          ????│??????????index.ts
          ????│??????????Select.vue
          ????├─directive
          ????│??????focus.ts
          ????│??????index.ts
          ????│??????pin.ts
          ????├─router
          ????│??????index.ts
          ????├─store
          ????│??????index.ts
          ????├─utils
          ????│??│??cookie.ts
          ????│??│??deep-clone.ts
          ????│??│??index.ts
          ????│??│??storage.ts
          ????│??└─validate
          ????│??????????date.ts
          ????│??????????email.ts
          ????│??????????mobile.ts
          ????│??????????number.ts
          ????│??????????system.ts
          ????└─views
          ????????│??About.vue
          ????????│??Home.vue
          ????????│??LuckDraw.vue
          ????????│??TodoList.vue
          ????????└─address
          ????????????????AddressEdit.tsx
          ????????????????AddressList.tsx
          • .vue寫法







          "{?color?}">
          .text-color?{
          ??color:?var(--color);
          }

          • tsx寫法
          import?{?ref,?reactive?}?from?"vue";
          import?{?AddressList,?NavBar,?Toast,?Popup?}?from?"vant";
          import?AddressEdit?from?'./AddressEdit'
          import?router?from?'@/router'

          export?default?{
          ??setup()?{
          ????const?chosenAddressId?=?ref('1')
          ????const?showEdit?=?ref(false)

          ????const?list?=?reactive([
          ??????{
          ????????id:?'1',
          ????????name:?'張三',
          ????????tel:?'13000000000',
          ????????address:?'浙江省杭州市西湖區(qū)文三路?138?號東方通信大廈?7?樓?501?室',
          ????????isDefault:?true,
          ??????},
          ??????{
          ????????id:?'2',
          ????????name:?'李四',
          ????????tel:?'1310000000',
          ????????address:?'浙江省杭州市拱墅區(qū)莫干山路?50?號',
          ??????},
          ????])
          ????const?disabledList?=?reactive([
          ??????{
          ????????id:?'3',
          ????????name:?'王五',
          ????????tel:?'1320000000',
          ????????address:?'浙江省杭州市濱江區(qū)江南大道?15?號',
          ??????},
          ????])

          ????const?onAdd?=?()?=>?{
          ??????showEdit.value?=?true
          ????}
          ????const?onEdit?=?(item:?any,?index:?string)?=>?{
          ??????Toast('編輯地址:'?+?index);
          ????}

          ????const?onClickLeft?=?()?=>?{
          ??????router.back()
          ????}

          ????const?onClickRight?=?()?=>?{
          ??????router.push('/todoList')
          ????}

          ????return?()?=>?{
          ??????return?(
          ????????
          ??????????????????????title="地址管理"
          ????????????left-text="返回"
          ????????????right-text="Todo"
          ????????????left-arrow
          ????????????onClick-left={onClickLeft}
          ????????????onClick-right={onClickRight}
          ??????????/>
          ??????????????????????vModel={chosenAddressId.value}
          ????????????list={list}
          ????????????disabledList={disabledList}
          ????????????disabledText="以下地址超出配送范圍"
          ????????????defaultTagText="默認"
          ????????????onAdd={onAdd}
          ????????????onEdit={onEdit}
          ??????????/>
          ??????????
          ????????????
          ??????????
          ????????
          ??????);
          ????};
          ??}
          };

          結(jié)束

          不知不覺, Vue 都到3的One Piece時代了, Vue3 的新特性讓擁抱 TypeScript 的姿勢更加從容優(yōu)雅, Vue 面向大型項目開發(fā)也更加有底氣了。

          ??愛心三連擊

          1.看到這里了就點個在看支持下吧,你的點贊在看是我創(chuàng)作的動力。

          2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入Node進階交流群!「在這里有好多 Node 開發(fā)者,會討論 Node 知識,互相學(xué)習(xí)」!

          3.也可添加微信【ikoala520】,一起成長。


          “在看轉(zhuǎn)發(fā)”是最大的支持

          瀏覽 66
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色毛片一区二区 | 免费的三级网站在线观看 | 亚洲黄色视频电影 | 美女操逼AV| 国产品黄色大片免费的 |