目錄

[toc](Vue3 學(xué)習(xí)筆記梳理)
Author:Gorit
Date:2021/4/24
Refer:網(wǎng)易云課堂
2021年發(fā)表博文: 17/50
Vue3 學(xué)習(xí)
學(xué)習(xí)文檔
如果是第一次接觸 Vue3,可以看這個(gè) Vue3 初體驗(yàn)
零、Vue3.0 與 Vue2.x 的性能對(duì)比
- 框架內(nèi)部做了大量的性能優(yōu)化,包括虛擬 DOM,編譯模板、Proxy 的新數(shù)據(jù)監(jiān)聽(tīng),更小的打包文件等
- 新的組合式 API (composition-api),更適合大型項(xiàng)目的編寫(xiě)方式
- 對(duì) TypeScript 支持更好,去除繁瑣的 this 操作,更強(qiáng)大的類型推導(dǎo)
一、搭建環(huán)境
- node 8.9.0 以上
- 安裝好 npm
- 安裝 vue
- 安裝 Vue Cli4 腳手架
二、創(chuàng)建項(xiàng)目
- vue create vue3-demo

- 其他的選擇默認(rèn)配置即可
- 安裝 yarn :cnpm i yarn -g (提升安裝速度)
- 測(cè)試:yarn --versin
項(xiàng)目結(jié)構(gòu)介紹
- package.json 項(xiàng)目全局管理
- node_modules 項(xiàng)目依賴包,占用大量空間
- public 入口文件
- src:main.js 為入口文件,項(xiàng)目代碼在這里編寫(xiě)
三、Vue3 Composition API
Vue3 是向下兼容 Vue2 API 的,但是 Vue3 中提供了一種全新的 <font color="red">Composition API</font>
3.1 ref() or setup() ? reactive()
setup() 作為 Vue3.0 的入口函數(shù)
reactive() 作聲明式渲染,用來(lái)響應(yīng)數(shù)據(jù)
ref() 顯示響應(yīng)式數(shù)據(jù),配合 reactve()
3.1.1 非響應(yīng)式數(shù)據(jù)顯示 (reactive)
直接返回?cái)?shù)據(jù)
<template>
<div>直接返回 state【非響應(yīng)式的數(shù)據(jù)】:{{count}}</div>
</template>
<script>
// 如果是 Vue2 項(xiàng)目,想要用 Vue3 的語(yǔ)法,需要安裝 @vue/composition-api
// import { xxx } from '@vue/composition-api'
import {
reactive
} from 'vue'
export default {
name: 'App',
// Vue3.0 的入口函數(shù),編寫(xiě) Vue3 代碼,beforeCreate之前進(jìn)行觸發(fā), 需要 return
setup() {
const state = reactive({
count: 0
});
// 不具備數(shù)據(jù)響應(yīng)式的效果,1s 后數(shù)據(jù)沒(méi)有任何變化
setTimeout(()=> {
state.count++;
},1000)
return state;
}
}
</script>
3.1.2 響應(yīng)式數(shù)據(jù)顯示 (reactive)
通過(guò)對(duì)象的形式
<template>
<div>返回 state 對(duì)象 【響應(yīng)式數(shù)據(jù)】{{state.count}}</div>
</template>
<script>
import {
reactive
} from 'vue'
export default {
name: 'App',
// Vue3.0 的入口函數(shù),編寫(xiě) Vue3 代碼,beforeCreate之前進(jìn)行觸發(fā), 需要 return
setup() {
// 具備數(shù)據(jù)響應(yīng)式, 返回對(duì)象
const state = reactive({
count: 0
});
setTimeout(()=> {
state.count++;
},1000)
return { state };
// 對(duì)返回的結(jié)果 解構(gòu),這樣數(shù)據(jù)就可以只顯示 {{ count }} 就可以了
// return {
// count: state.count
//}
}
}
</script>
3.1.3 響應(yīng)式數(shù)據(jù)展示(整合 ref() )
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>ref 實(shí)現(xiàn)響應(yīng)式對(duì)象 {{ count }}</div>
</template>
<script>
import {
ref
} from 'vue'
export default {
name: 'App',
setup() {
// 使用 ref() 實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)
const count = ref(0); // 這樣 count 就實(shí)現(xiàn)了響應(yīng)式的效果
setInterval(()=> {
count.value++;
},1000)
return {
count
};
}
}
</script>
因此,我們既要響應(yīng)式,又要展示數(shù)據(jù),折中的方案是直接使用 ref
3.1.4 小案例:實(shí)現(xiàn)一個(gè)計(jì)數(shù)器
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div class="my-app">
<!-- Vue3 無(wú)法直接拿到值 -->
<h3>{{counter}}</h3>
<button @click="increment(1)">increment</button>
<button @click="decrement(1)">decrement</button>
</div>
</template>
<script>
import { ref } from 'vue'
/**
* Options API Vue2 Class
* Composition API Vue3 Function
*/
export default {
name: 'App',
setup() {
const counter = ref(1000)
// console.log(counter.value)
const increment = () => {
counter.value += 1;
}
const decrement = () => {
counter.value -= 1;
}
// 必須 return,外部才能拿到值
return { counter, increment,decrement }
}
}
</script>
3.2 toRefs() ? toRef()
在上面的代碼中,我們使用 ref() 和 reactive() 分別可以實(shí)現(xiàn)響應(yīng)式的數(shù)據(jù),我們是否可以兩者一起使用呢?
3.2.1 ref() 和 reactive() 連用
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>ref() 和 reactive() 實(shí)現(xiàn)響應(yīng)式對(duì)象 {{ count }}</div>
</template>
<script>
// 如果是 Vue2 項(xiàng)目,想要用 Vue3 的語(yǔ)法,需要安裝 @vue/composition-api
// import { xxx } from '@vue/composition-api'
import {
ref,
reactive
} from 'vue'
export default {
name: 'App',
setup() {
// ---------------------------- ref 和 reactive 連用
const count = ref(0);
const state = reactive({
count
})
setInterval(()=> {
state.count++;
},1000)
return {
count
};
}
}
</script>
3.2.2 使用 toRefs() 和 reactive()
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>實(shí)現(xiàn)響應(yīng)式對(duì)象 {{ count }}</div>
</template>
<script>
import {
reactive,
toRefs
} from 'vue'
export default {
name: 'App',
setup() {
// ---------------------------- //使用 toRefs() 將 reactive 轉(zhuǎn)換為 Ref
const state = reactive({
count: 0
});
const { count } = toRefs(state); // toRefs() 作用:將普通類型數(shù)據(jù),轉(zhuǎn)換為 Ref 響應(yīng)式數(shù)據(jù)
setInterval(()=> {
state.count++;
},1000)
return {
count
};
}
}
</script>
3.2.3 使用 toRef() 和 reactive()
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>實(shí)現(xiàn)響應(yīng)式對(duì)象 {{ count }}</div>
</template>
<script>
import {
reactive,
toRefs
} from 'vue'
export default {
name: 'App',
setup() {
// ---------------------------- //使用 toRefs() 將 reactive 轉(zhuǎn)換為 Ref
const state = reactive({
count: 0
});
const count = toRef(state, 'count'); // toRef() 作用:將普通類型數(shù)據(jù),轉(zhuǎn)換為 Ref 響應(yīng)式數(shù)據(jù),指定單個(gè)數(shù)據(jù)轉(zhuǎn)換
setInterval(()=> {
state.count++;
},1000)
return {
count
};
// toRefs === {}
}
}
</script>
ref 和 reactive 分別是兩種響應(yīng)式數(shù)據(jù)的變量風(fēng)格,具體看個(gè)人情況使用
3.3 computed 計(jì)算屬性
3.3.1 配合 ref() 使用 實(shí)現(xiàn)響應(yīng)式
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>
{{count}} , {{double}}
</div>
</template>
<script>
import {
ref,
computed
} from 'vue'
export default {
name: 'App',
setup() {
// 使用計(jì)算屬性
const count = ref(1)
const double = computed(()=>count.value * 2)
setTimeout(()=>{
count.value++
},1000)
return {
count,double
}
}
}
</script>
3.3.2 配合 toRefs() 和 reactive() 實(shí)現(xiàn)響應(yīng)式
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>
{{count}} , {{double}}
</div>
</template>
<script>
import {
reactive,
toRefs,
computed
} from 'vue'
export default {
name: 'App',
setup() {
const state = reactive({
count: 1,
double: computed(()=>state.count * 2)
})
setTimeout(()=>{
state.count++
},1000)
return toRefs(state)
}
}
</script>
3.4 定義函數(shù)
3.4.1 函數(shù)與 watch
<template>
<img alt="Vue logo" src="./assets/logo.png">
<div>
事件:{{count}}
</div>
<button @click="add">添加</button>
</template>
<script>
import {
ref,
watch
} from 'vue'
export default {
name: 'App',
setup() {
// =============== 事件
const count = ref(1)
const add = () => { // 事件方法
count.value++;
}
// 配合偵聽(tīng)器
watch(count ,(count, prevCount) => {
console.log(count, prevCount)
})
return {count, add}
}
}
</script>
3.4.2 Vue3.0 函數(shù)與生命周期函數(shù)
新的生命周期函數(shù)鉤子要在 setup() 中使用
- onMounted
- onUpdated
- onUnmounted
export default {
setup() {
// mounted
onMounted(() => {
console.log('Component is mounted!')
})
}
}
四、Vue3 組件化(拆分+傳值+注冊(cè))
這里主要是回顧 組件化編程
拆分的方式同 Vue2,注冊(cè) + 引入
組件拆分的案例我們沿用上面的計(jì)數(shù)器來(lái)實(shí)現(xiàn) (參考 3.1.4 小節(jié)的內(nèi)容)
4.1 組件拆分
預(yù)覽效果:
編碼如下:
- 定義一個(gè)新的 vue 文件,命名為 CounterView.vue 文件
- 使用 props 接受父組件 App.vue 穿過(guò)來(lái)的值
<template>
<div>
我是子組件 CounterView
{{counter}}
</div>
</template>
<script>
export default {
name: 'CounterView',
// props: ['counter'] vue2 一般都是這么寫(xiě)的
// 下面的這種寫(xiě)法會(huì)更加規(guī)范
props: {
counter: {
type: Number,
required: true,
default: 500
}
}
}
</script>
- 修改父組件 App.vue,改為引用 CounterView.vue ,并注冊(cè)為組件
<template>
<div>
<img alt="Vue logo" src="./assets/logo.png" />
<!-- 屬性綁定 -->
<counter-view :counter="counter"/>
<button @click="increament(1)">增加</button>
<button @click="increament(-1)">減少</button>
</div>
</template>
<script>
import { ref } from "vue";
import CounterView from '@/components/CounterView.vue'
export default {
name: "App",
components: {
CounterView
},
setup() {
const counter = ref(1000);
console.log(counter.value);
// 定義函數(shù)
const increament = (num) => {
counter.value += num;
};
return { counter,increament };
},
};
</script>
<style>
</style>
4.2 事件拆分
這里我們?cè)谏厦娴幕A(chǔ)上,將 setup() 中定義的事件,拆分至另一個(gè)新的 vue 文件
首先我們需要補(bǔ)充一些前置概念:
- 在 setup() 中是沒(méi)有 this 關(guān)鍵字的
-
setup() 是可以接受兩個(gè)參數(shù)的 (props, context),然后我們打印接受到的值如下
在這里插入圖片描述 - cotext 中,可以看到 emit 關(guān)鍵字,是不是很熟悉,vue2 中我們要子組件傳事件給父組件,用的是
this.$emit("事件名稱", '值"), 在 Vue3 中也會(huì)用到類似的,后面會(huì)有具體的演示 - 編碼如下:
在子組件完成事件注冊(cè)
<template>
<div>
<button @click="increament(1)">增加</button>
<button @click="increament(-1)">減少</button>
</div>
</template>
<script>
export default {
name: 'CounterController',
setup(props,ctx) {
console.log(props, ctx) // 這里打印的就是我們剛剛上面看到的
const increament = (num) => {
// ctx.emit 等價(jià)于 vue2 中 this.$emit("xxx",xxx)。 在 vue3 中 setup() 函數(shù)是沒(méi)有 this 的概念的
ctx.emit("onIncreament",num) // 完成事件注冊(cè),將操作的邏輯交給父組件來(lái)完成
}
return {increament}
},
}
</script>
在父組件完成事件調(diào)用
<template>
<div>
<img alt="Vue logo" src="./assets/logo.png" />
<!-- 屬性綁定 -->
<counter-view :counter="counter"/>
<!-- <button @click="increament(1)">增加</button>
<button @click="increament(-1)">減少</button> -->
<!-- 子組件事件注冊(cè)完畢后,交給父組件進(jìn)行觸發(fā), 處理的函數(shù)需要傳 $event 就可以實(shí)現(xiàn)和上面一樣的效果了 -->
<counter-controller @onIncreament="increament($event)" />
</div>
</template>
<script>
import { ref } from "vue";
import CounterView from '@/components/CounterView.vue'
import CounterController from '@/components/CounterController.vue'
export default {
name: "App",
components: {
CounterView,
CounterController
},
setup() {
const counter = ref(1000);
// 定義函數(shù)
const increament = (num) => {
counter.value += num;
};
return { counter,increament };
},
};
</script>
五、總結(jié)
我們來(lái)回顧一下所學(xué)內(nèi)容
- setup(props, context), setup() 是代碼的入口
- 響應(yīng)式 API:reactive() 、ref()、toRef()、toRefs()
- 計(jì)算屬性 computed 和 watch 偵聽(tīng)器的使用
- 組件化思想
