vue3+typescript入門到精通

vue3.0入門到精通

附B站講解視頻

vue3+typescript入門到精通

vue3.0 安裝

前安裝過vue的2.0版本桅滋,你需要把2.0相關(guān)的刪除

npm uni -g vue-cli

安裝vue/cli腳架

npm i -g @vue/cli

檢查版本號,目前安裝vuecli 4.5.4

vue -V

創(chuàng)建:在命令窗口輸入指令

選擇default vue 3

vue create 項目名稱

vue composition API


vue3.0 側(cè)重于解決代碼組織與邏輯復(fù)用問題

目前日月,我們使用的是“options”API 構(gòu)建組件侠坎。 為了將邏輯添加到Vue組件中桃漾,我們填充(options)屬性量窘,如data榜配、methods岂津、computed等誊爹。 這種方法最大的缺點是贞远,它本身不是一個工作的JavaScript代碼畴博。 您需要確切地知道模板中可以訪問哪些屬性以及this關(guān)鍵字的行為。在底層蓝仲,Vue編譯器需要將此屬性轉(zhuǎn)換為工作代碼俱病。正因為如此,我們無法從自動建議或類型檢查中獲益袱结。

Composition API希望將通過當(dāng)前組件屬性亮隙、可用的機制公開為JavaScript函數(shù)來解決這個問題。 Vue核心團隊將組件Composition API描述為“一套附加的垢夹、基于函數(shù)的api溢吻,允許靈活地組合組件邏輯”。 使用Composition API編寫的代碼更易讀果元,并且場景不復(fù)雜促王,這使得閱讀和學(xué)習(xí)變得更容易。

讓我們看到一個非常簡單的組件示例而晒,它使用新的組件Composition API來理解它是如何工作的硼砰。

<template>

? <div id="app">

?? <img alt="Vue logo" src="./assets/logo.png">

?? <div>{{msg}}年齡為{{age}}</div>

?? <button @click="add"> + </button>

? </div>

</template>

?

<script>

?

?

export default {

? name: 'App',

? data() {

?? return {

? ?? msg:'王大合',

? ?? age:18

?? }

? },

? methods:{

?? add() {

? ?? this.age += 1

?? }

? }

?

}

</script>

setup

vue3.0將組件的邏輯都寫在了函數(shù)內(nèi)部,setup()會取代vue2.x的data()函數(shù),返回一個對象,暴露給模板,而且只在初始化的時候調(diào)用一次,因為值可以被跟蹤,所以我們通過vue3來改變編程習(xí)慣

首先引入ref

使用數(shù)據(jù)需要return

import {ref} from 'vue'

setup() {

?? const msg = ref('王大合')

?? const age = ref(18)

?? function add() {

? ?? age.value +=1

?? }

?? return {msg,age,add}

? }

computed

<template>

? <div id="app">

?? <img alt="Vue logo" src="./assets/logo.png">

?? <div>{{msg}}的年齡為{{age}}</div>

?? <div>{{double}}</div>

?? <button @click="add">+</button>

? </div>

</template>

?

<script>

import {computed, ref} from 'vue'

?

export default {

? name: 'App',

? setup() {

?? const msg = ref('王大合')

?? const age = ref(18)

?? const double = computed(() =>{

? ?? return age.value * 2

?? })

?? function add() {

? ?? age.value += 1

?? }

?? return {msg,age,add,double}


? }

}

</script>

?

?

?

reactive

在 setup 函數(shù)里面, 我們適應(yīng)了 Vue3.0 的第一個新接口 reactive 它主要是處理你的對象讓它經(jīng)過 Proxy 的加工變?yōu)橐粋€響應(yīng)式的對象欣硼,

toRefs

用于將響應(yīng)式對象變成普通對象

<template>

? <div id="app">

?? <img alt="Vue logo" src="./assets/logo.png">

?? <div>{{msg}}的年齡為{{age}}</div>

?? <div>{{double}}</div>

?? <button @click="add">+</button>

? </div>

</template>

?

<script>

import {computed, reactive,toRefs} from 'vue'

?

export default {

? name: 'App',

? setup() {

?? const state = reactive({

? ? ?? msg:'王大合',

? ? ?? age:18,

? ? ?? double : computed(() =>{

? ?? return state.age * 2

?? })

?? })

?

?? function add() {

? ?? state.age += 1

?? }

?? return {...toRefs(state),add}


? }

}

</script>

?

?

?

props 和 context

在 Vue2.0 中我們可以使用 props 屬性值完成父子通信题翰,在這里我們需要定義 props 屬性去定義接受值的類型,然后我們可以利用 setup 的第一個參數(shù)獲取 props 使用诈胜。

export default {

? name: 'App',

? components:{

?? Content

? },

? setup() {

?? const state = reactive({

? ? ?? msg:'王大合',

? ? ?? age:18,

? ? ?? double : computed(() =>{

? ?? return state.age * 2

?? })

?? })

?

?? function add() {

? ?? state.age += 1

?? }

?? return {...toRefs(state),add}


? }

}

我們在 App.vue 里面就可以使用該頭部組件豹障,有了上面的 props 我們可以根據(jù)傳進來的值,讓這個頭部組件呈現(xiàn)不同的狀態(tài)焦匈。

<template>

? <div id="app">

?? <img alt="Vue logo" src="./assets/logo.png">

?? <div>{{msg}}的年齡為{{age}}</div>

?? <div>{{double}}</div>

?? <Content :msg='msg' />

?? <button @click="add">+</button>

? </div>

</template>

這里我新建一個新的組件content,在app.vue中引入

<!--? -->

<template>

? <div>{{data}}</div>

</template>

?

<script>

import {ref} from 'vue'

export default {

name:'content',

props:{

? ? msg:String

},

setup(props) {

? ? const data = ref(props.msg)

? ? return {data}

}

}

?

</script>

setup 函數(shù)的第二個參數(shù)是一個上下文對象血公,這個上下文對象中包含了一些有用的屬性,這些屬性在 Vue2.0 中需要通過 this 才能訪問到缓熟,在 vue3.0 中累魔,訪問他們變成以下形式:

setup(props, ctx) {

? console.log(ctx) // 在 setup() 函數(shù)中無法訪問到 this

? console.log(this) // undefined

}

具體能訪問到以下有用的屬性:

- slot

- attrs

- emit

父組件

<template>

? <div id="app">

?? <img alt="Vue logo" src="./assets/logo.png">

?? <div>{{msg}}的年齡為{{age}}</div>

?? <div>{{double}}</div>

?? <Content :msg='msg' @change='showName' />

?? <button @click="add">+</button>

? </div>

</template>

?

<script>

import {computed, reactive,toRefs} from 'vue'

import Content from './components/content.vue'

export default {

? name: 'App',

? components:{

?? Content

? },


? setup() {

?? const state = reactive({

? ? ?? msg:'王大合',

? ? ?? age:18,

? ? ?? double : computed(() =>{

? ? ? ?? return state.age * 2

? ? ?? })

?? })

?? function showName(params) {

? ? ?? alert(params)

?? }

?

?? function add() {

? ?? state.age += 1

?? }

?? return {...toRefs(state),add,showName}


? }

}

</script>

?

?

?

子組件

<!--? -->

<template>

? <div>{{data}}</div>

? <button @click="changeName">打個招呼!</button>

</template>

?

<script>

import {ref} from 'vue'

export default {

name:'content',

props:{

? ? msg:String

},

setup(props,context) {

? ? const data = ref(props.msg)

?? function changeName() {

? ? ?? context.emit('change','Hello,王大合!')

?? }

? ? return {data,changeName}

}

}

?

</script>

watch

監(jiān)聽ref

不指定數(shù)據(jù)源

const a = ref(18)

?

watch(()=>{

? ? console.log(a.value)

})

指定數(shù)據(jù)源

const a = ref(18)

?

? watch(a,()=> {

?

? console.log(a.value)

?

? })

監(jiān)聽reactive

const state = reactive({

? ? ?? msg:'王大合',

? ? ?? age:18,

? ? ?? double : computed(() =>{

? ? ? ?? return state.age * 2

? ? ?? })

?? })

不指定數(shù)據(jù)源

watch(()=>{

? ? console.log(state.age)

})

指定數(shù)據(jù)源

watch(()=>state.age,()=>{

? ? console.log(state.age)

})

回調(diào)函數(shù)參數(shù)以及watche clean,使用clean時候是處理重復(fù)性的watch監(jiān)聽事件

watch(() => state.age,(newVal,oldVal,clean)=> {

? ? console.log(state.msg + "去年年紀:"+oldVal +"今年年紀:" + newVal)

? ? clean(

? ? ? ()=>{

? ? ? ? console.log('clean')

? ? ? }

? ? )

? })

vue3.X+vite+typescript

放棄webpack,使用vite安裝vue3.0

這個是尤大開發(fā)的新工具摔笤,目的是以后替代webpack,原理是利用瀏覽器現(xiàn)在已經(jīng)支持es6的import了垦写,遇到import會發(fā)送一個http請求去加載文件吕世,vite攔截這些請求,做一些預(yù)編譯梯投,省去了webpack冗長打包的時間命辖,提升開發(fā)體驗

npm install -g create-vite-app

create-vite-app vue3-vite

cd vue3-vite

npm install

npm run dev

# 或者使用yarn

yarn add -g create-vite-app

yarn create vite-app <project-name>

安裝依賴

yarn

使用yarn啟動項目

yarn dev

引入typescript

# 安裝 typescript

?

yarn add typescript -D

初始化tsconfig.json

# 然后在控制臺執(zhí)行下面命令

npx tsc --init

將main.js修改為main.ts,同時將index.html里面的引用也修改為main.ts,

然后在script 里添加 lang="ts"

<template>

? <img alt="Vue logo" src="./assets/logo.png" />

? <HelloWorld msg="Hello Vue 3.0 + Vite" />

</template>

?

<script lang="ts">

import HelloWorld from './components/HelloWorld.vue'

?

export default {

? name: 'App',

? components: {

?? HelloWorld

? }

}

</script>

?

修改完之后,重啟就可以訪問項目了分蓖。雖然這樣配置是可以了尔艇,但是打開main.ts會發(fā)現(xiàn)import App from App.vue會報錯:Cannot find module './App.vue' or its corresponding type declarations.,這是因為現(xiàn)在ts還沒有識別vue文件,需要進行下面的配置:

在項目根目錄添加shim.d.ts文件

# powerShell終端,也可以手動創(chuàng)建

New-Item shim.d.ts

添加以下內(nèi)容

declare module "*.vue" {

? import { Component } from "vue";

? const component: Component;

? export default component;

}

安裝vue-router

yarn add vue-router@4.0

這樣可以選擇最新的vue-router 4.0.0的測試版本,這里更新到beta.13

配置vue-router

在項目src目錄下面新建router目錄么鹤,然后添加index.ts文件终娃,在文件中添加以下內(nèi)容

import {createRouter, createWebHashHistory} from 'vue-router'

?

// 在 Vue-router新版本中,需要使用createRouter來創(chuàng)建路由

export default createRouter({

? // 指定路由的模式,此處使用的是hash模式

? history: createWebHashHistory(),

? // 路由地址

? routes: []

})

安裝vuex

同上

yarn add vuex@4.0

目前只能選擇最新測試版

在項目src目錄下面新建store目錄蒸甜,并添加index.ts文件尝抖,文件中添加以下內(nèi)容

import { createStore } from 'vuex'

?

interface State {

? userName: string

}

?

export default createStore({

? state:{

? userName:'王大合'

? }

});

main.ts中引入vuex和vue-router

import { createApp } from 'vue'

import App from './App.vue'

import './index.css'

import router from './router/index'

import vuex from './store/index'

?

const? app = createApp(App)

?

app.use(router)

app.use(vuex)

app.mount('#app')

?

上線小項目todoList

app.vue

<template>

? <div id="app">

?? <div id="nav">

? ?? <router-link to="/">todoList</router-link> |

? ?? <router-link to="/about">About</router-link>

?? </div>

?? <router-view/>

? </div>

</template>

?

<script lang="ts">

?

export default {

? name: 'App'

}

</script>

?

<style lang="scss">

? #app {

? font-family: Avenir, Helvetica, Arial, sans-serif;

? -webkit-font-smoothing: antialiased;

? -moz-osx-font-smoothing: grayscale;

? text-align: center;

? color: #2c3e50;

}

?

#nav {

? padding: 30px;

?

? a {

?? font-weight: bold;

?? color: #2c3e50;

?

?? &.router-link-exact-active {

? ?? color: #42b983;

?? }

? }

}

</style>

配置路由 router/index.ts

import {createRouter, createWebHashHistory} from 'vue-router'

?

// 在 Vue-router新版本中,需要使用createRouter來創(chuàng)建路由

export default createRouter({

? // 指定路由的模式,此處使用的是hash模式

? history: createWebHashHistory(),

? // 路由地址

? routes: [

?? {

?? path: '/',

?? // 必須添加.vue后綴

?? component: () => import('../views/todo-list.vue')

? ?? },

?? {

? ? ?? path: '/about',

? ? ?? name: 'About',


? ? ?? component: () => import('../views/About.vue')

? ?? }

]

})

store的index.ts新建vuex

import { createStore } from 'vuex'

?

interface State {

? userName: string

? taskList: any[]


}

?

export default createStore({

? state: {


? ?? userName: "王大合",

? ?? taskList: []


? },

? mutations:{


?? createTask (state:any, newTask:string) {

? ? ?? state.taskList.push(newTask)

? ?? },

? ?? deleteTask (state:any, index:number) {

? ? ?? state.taskList.splice(index, 1)

? ?? },

? ?? updateStatus (state:any, payload:any) {

? ? ?? const { index, status } = payload


? ? ?? state.taskList[index].isfinished = status

? ?? }

? }

});

在src目錄新建view文件夾,創(chuàng)建todoList和about

todoList

?

<template>

? <div class="home">

?? <!-- input輸入list內(nèi)容 -->

?? <div>

? ? ? <input

?? @keyup.enter="addTask"

? ?? class="input"

? ?? type="text"

? ?? v-model="inputValue"

? ?? placeholder="請輸入" />

?? </div>

?? <!-- todoList內(nèi)容展示和刪除 -->

? ? <ul class="ul">

? ?? <li class="item" v-for="(item, index) in taskList" :key="index">

? ? ?? <p

? ? ?? @click="updateStatus(index, !item.isfinished)"

? ? ?? class="content"

? ? ?? :class="item.isfinished ? 'active' : ''"

? ? ?? >{{item.lable}}</p>

? ? ?? <div class="item-delete" @click="deleteTask(index)">X</div>

? ?? </li>

? ?? <li v-if="taskList.length === 0" class="item-none">暫無數(shù)據(jù)</li>

?? </ul>

? </div>

</template>

?

?

<script lang="ts">

import { ref, computed } from 'vue';

import { useStore } from "vuex";

export default {


? setup() {

?? const store = useStore()

?? const taskList = computed(() => store.state.taskList);

?? const inputValue = ref('');

?? const addTask = () => {

? ?? store.commit('createTask', {

? ? ?? lable: inputValue.value,

? ? ?? isfinished: false

? ?? })

?

? ?? inputValue.value = ''

?? }

?

?? const updateStatus = (index, status) => {

? ?? store.commit('updateStatus', {

? ? ?? index,

? ? ?? status

? ?? })

?? }

?

?? const deleteTask = (index) => {

? ?? store.commit('deleteTask', index)

?? }

?

?? return {

? ?? inputValue,

? ?? taskList,

? ?? addTask,

? ?? updateStatus,

? ?? deleteTask

?? };

? }

}

</script>

?

<style scoped lang='scss'>

* {

? box-sizing: border-box;

? margin: 0;

? padding: 0;

}

ul,

li {

? list-style: none;

?

? text-align: left;

}

.home {

? max-width: 400px;

? margin: 0 auto;

? .input {

?? width: 100%;

?? height: 40px;

?? border-radius: 5px;

?? outline-style: none;

?? border: 2px solid #999;

?? padding: 5px 10px;

? }

? .ul {

?? margin-top: 10px;

? }

?

? .item {

?? height: 40px;

?? line-height: 40px;

?? padding-bottom: 5px;

?? border-bottom: 1px solid #dcdfe6;

?? color: #333333;

? }

? .item-none {

?? height: 40px;

?? line-height: 40px;

?? padding-bottom: 5px;

?? color: #333333;

?? text-align: center;

? }

? .content {

?? float: left;

?? height: 40px;

?? line-height: 40px;

?? cursor: pointer;

? }

? p.active {

?? text-decoration:line-through;

?? color: #999999;

? }

? .item-delete {

?? float: right;

?? width: 25px;

?? text-align: center;

?? cursor: pointer;

? }

}

</style>

about

<template>

? <div class="about">

?? <h1>{{name}}</h1>


?


? </div>

</template>

?

<script lang='ts'>

import { ref, watch } from 'vue';

?

export default {

? name: 'about',

? setup() {

?? const name = ref('王大合出品');

?


?

?

?


?? return {

? ?? name,


?? };

? }

};

</script>

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迅皇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子衙熔,更是在濱河造成了極大的恐慌登颓,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件红氯,死亡現(xiàn)場離奇詭異框咙,居然都是意外死亡,警方通過查閱死者的電腦和手機痢甘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門喇嘱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塞栅,你說我怎么就攤上這事者铜。” “怎么了放椰?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵作烟,是天一觀的道長。 經(jīng)常有香客問我砾医,道長拿撩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任如蚜,我火速辦了婚禮压恒,結(jié)果婚禮上影暴,老公的妹妹穿的比我還像新娘。我一直安慰自己探赫,他們只是感情好型宙,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著期吓,像睡著了一般早歇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上讨勤,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天箭跳,我揣著相機與錄音,去河邊找鬼潭千。 笑死谱姓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刨晴。 我是一名探鬼主播屉来,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼狈癞!你這毒婦竟也來了茄靠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蝶桶,失蹤者是張志新(化名)和其女友劉穎慨绳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體真竖,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡脐雪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恢共。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片战秋。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讨韭,靈堂內(nèi)的尸體忽然破棺而出脂信,到底是詐尸還是另有隱情,我是刑警寧澤透硝,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布吉嚣,位于F島的核電站,受9級特大地震影響蹬铺,放射性物質(zhì)發(fā)生泄漏尝哆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一甜攀、第九天 我趴在偏房一處隱蔽的房頂上張望秋泄。 院中可真熱鬧琐馆,春花似錦、人聲如沸恒序。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歧胁。三九已至滋饲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喊巍,已是汗流浹背屠缭。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留崭参,地道東北人呵曹。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像何暮,于是被迫代替她去往敵國和親奄喂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345