中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue3+TypeScript完整項目的方法教程

發布時間:2021-10-26 09:24:12 來源:億速云 閱讀:160 作者:iii 欄目:web開發

本篇內容主要講解“Vue3+TypeScript完整項目的方法教程”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Vue3+TypeScript完整項目的方法教程”吧!

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

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

Vue3+TypeScript完整項目的方法教程

96.8%的代碼都是TypeScript,支持的力度也是相當大?

項目搭建

在官方倉庫的 Quickstart 中推薦用兩種方式方式來構建我們的 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/clivue create sail-vue3# select vue 3 preset

vite 是一個由原生ESM驅動的Web開發構建工具,打開 vite 依賴的 package.json 可以發現在 devDependencies  開發依賴里面已經引入了TypeScript ,甚至還有 vuex , vue-router , less , sass 這些本地開發經常需要用到的工具。vite  輕量,開箱即用的特點,滿足了大部分開發場景的需求,作為快速啟動本地 Vue 項目來說,這是一個非常完美的工具。

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

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

  • vue-cli ? TypeScript STEP1  

Vue3+TypeScript完整項目的方法教程

  • vue-cli ? TypeScript STEP2

Vue3+TypeScript完整項目的方法教程

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

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

vue add typescript

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

<script lang="ts">

Option API風格

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

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 要用 vue-class-component 強化 vue 組件,讓 Script 支持 TypeScript 裝飾器

  3. 用 vue-property-decorator 來增加更多結合 Vue 特性的裝飾器

  4. 引入 ts-loader 讓 webpack 識別 .ts .tsx 文件

  5. ..... 

然后出來的代碼風格是這樣的:

@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 風格的組件,各種裝飾器穿插在代碼中,有點感覺自己不是在寫 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<Student>,       required: true     }   },   data() {      return {         message: 'Vue3 code style'     }   },   computed: {     reversedMessage(): string {       return this.message.split(' ').reverse().join('')     }   } })

vue 對 props 進行復雜類型驗證的時候,就直接用 PropType 進行強制轉換, data  中返回的數據也能在不顯式定義類型的時候推斷出大多類型, computed 也只用返回類型的計算屬性即可,代碼清晰,邏輯簡單,同時也保證了 vue  結構的完整性。

Composition API風格

在 vue3 的 Composition API 代碼風格中,比較有代表性的api就是 ref 和 reactive  ,我們看看這兩個是如何做類型聲明的:

ref

import { defineComponent, ref } from 'vue'  const Component = defineComponent({ setup() {   const year = ref(2020)   const month = ref<string | number>('9')    month.value = 9 // OK   const result = year.value.split('') // => Property 'split' does not exist on type 'number'  } })

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

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

const Component = defineComponent(() => {     const year = ref(2020)     const month = ref<string | number>('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<Student>({ name: '阿勇', age: 16 })     // or     const student: Student = reactive({ name: '阿勇', age: 16 })     // or     const student = reactive({ name: '阿勇', age: 16, class: 'cs' }) as Student   } })

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

自定義Hooks

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

首先來看看這個 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     }   } }

貼上 useCount 的源碼:

import { ref, Ref, watch } from 'vue'  interface Range {   min?: number,   max?: number }  interface Result {   current: Ref<number>,   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 < range.min) {       current.value = range.min     } else if (range && range.max && newVal > range.max) {       current.value = range.max     }   })    return {     current,     inc,     dec,     set,     reset   } }

分析源碼

這里首先是對 hooks 函數的入參類型和返回類型進行了定義,入參的 Range 和返回的 Result  分別用一個接口來指定,這樣做了以后,最大的好處就是在使用 useCount  函數的時候,ide就會自動提示哪些參數是必填項,各個參數的類型是什么,防止業務邏輯出錯。

Vue3+TypeScript完整項目的方法教程

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

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

小建議

AnyScript

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

Vetur

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

Vue3+TypeScript完整項目的方法教程

一個完整的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寫法

<template>   ... </template>  <script lang="ts"> import dayjs from "dayjs"; import { ref, reactive, onMounted } from "vue"; import { Button, Step, Steps, NoticeBar } from "vant";  export default {   components: {     Button,     Step,     Steps,     NoticeBar,   },   setup() {     const nameinput = ref();     const selectionStart = ref(0);     const twoNow = dayjs().subtract(2, "day").format("YYYY-MM-DD HH:mm:ss");     const now = dayjs().format("YYYY-MM-DD HH:mm:ss");     const now2 = dayjs().add(2, "day").format("YYYY-MM-DD HH:mm:ss");     const formData = reactive({       name: "",       phone: "",       code: "",     });      onMounted(() => {       (nameinput.value as HTMLInputElement).focus();     });      const insertName = () => {       const index = (nameinput.value as HTMLInputElement).selectionStart;       if (typeof index !== "number") return;       formData.name =         formData.name.slice(0, index) + "哈哈" + formData.name.slice(index);     };      return {       nameinput,       formData,       insertName,       selectionStart,       twoNow,       now,       now2,     };   }, }; </script>
<template>    ... </template>  <script lang="ts"> import dayjs from "dayjs"; import { defineComponent } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src import { Button, Dialog, Toast } from "vant";  export default defineComponent({   name: "Home",   components: {     HelloWorld,     Button,   },   data() {     return {       direction: "top",       pinPadding: 0,       time: "",       timer: 0,       color: "red",     };   },   methods: {     showToast() {       Toast("字體顏色已改藍色");       this.color = "blue";     },     handleClick() {       Dialog({         title: "標題",         message: "這是一個全局按鈕組件",       });     },     initTime() {       this.time = dayjs().format("YYYY-MM-DD HH:mm:ss");       this.timer = setInterval(() => {         this.time = dayjs().format("YYYY-MM-DD HH:mm:ss");       }, 1000);     },   },   created() {     this.initTime();   },   beforeUnmount() {     clearInterval(this.timer);   }, }); </script>  <style vars="{ color }"> .text-color {   color: var(--color); } </style>
  •  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: '浙江省杭州市西湖區文三路 138 號東方通信大廈 7 樓 501 室',         isDefault: true,       },       {         id: '2',         name: '李四',         tel: '1310000000',         address: '浙江省杭州市拱墅區莫干山路 50 號',       },     ])     const disabledList = reactive([       {         id: '3',         name: '王五',         tel: '1320000000',         address: '浙江省杭州市濱江區江南大道 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 (         <div style="background:#f7f8fa">           <NavBar             title="地址管理"             left-text="返回"             right-text="Todo"             left-arrow             onClick-left={onClickLeft}             onClick-right={onClickRight}           />           <AddressList             vModel={chosenAddressId.value}             list={list}             disabledList={disabledList}             disabledText="以下地址超出配送范圍"             defaultTagText="默認"             onAdd={onAdd}             onEdit={onEdit}           />           <Popup vModel={[showEdit.value, 'show']} position="bottom" round style="height: 80%" >             <AddressEdit />           </Popup>         </div >       );     };   } };

到此,相信大家對“Vue3+TypeScript完整項目的方法教程”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武川县| 普格县| 花垣县| 桃源县| 合阳县| 凤山市| 吴旗县| 永川市| 东阿县| 紫金县| 夏邑县| 北安市| 柘荣县| 肥西县| 麻阳| 沂南县| 视频| 横峰县| 米林县| 嘉定区| 凭祥市| 和顺县| 江陵县| 扶风县| 定日县| 苏尼特左旗| 南川市| 甘孜县| 孝义市| 吴桥县| 乌兰浩特市| 乐清市| 尤溪县| 土默特左旗| 虹口区| 邢台市| 麟游县| 舞阳县| 扎兰屯市| 玛纳斯县| 甘德县|