文章目錄
- day 1
- 1. 創建vue3工程
- 3. 響應式數據
- 4. 計算屬性
- day 2
- 5. watch 監視
- 6. watchEffect
- 7. 標簽的`ref`屬性
- 8. 回顧TS中的接口_泛型_自定義類型
day 1
1. 創建vue3工程
相關代碼如下:
## 創建vue工程
npm create vue@lastest## 安裝node_modules
npm install // npm i
創建工程完畢之后,進入文件夾可以發現有如下文件,下圖是文件介紹:

入口文件介紹:

這里main.ts
是與index.html
建立聯系的;

通過.mount('#app')
這樣 main.ts
就與index.html
建立起了聯系;
其中main.ts
的代碼格式如下:
<template><div><h1>你好</h1></div>
</template><script setup lang="ts">// js或者ts
</script><style scoped>/* 樣式 */
</style>
App.vue
的代碼格式如下:
<template><div class="app"><h1>你好</h1></div>
</template><script setup lang="ts">// js或者ts
</script><style scoped>/* 樣式 */.app {background-color: #ddd;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}
</style>
網頁調試vue可以在chrome應用商店search vue.js devtools
下載安裝就好;

你好
感覺vue2和vue3的主要不同就在于vue文件中script部分;其中vue2是選項式OptionsAPI
的,vue3是組合式Composition
的;

選項式API相關代碼如下:
注意,這里并沒有setup
;
<script lang="ts">export default {// 定義組件名字name: 'Person',// 定義數據data(){return {name: '張三',age: 18,tel: '138888888'}},// 定義方法methods:{changeName(){this.name = 'zhang-san'},changeAge(){this.age += 1},showTel(){alert(this.tel)}},}
</script>
組合式相關代碼如下:
注意,這里的setup比beforecreate執行得還要早,setup的返回值也可以是渲染函數,data,method,setup可以同時存在,setup不可以讀取data中的數據,反之則可以,因為setup是執行得最早的;
<script lang="ts">export default {name: 'Person',setup(){// 數據let name = '張三' // 此時name,age,tel 不是響應式的 應該改為ref或者reactivelet age = 18 // 此時name,age,tel 不是響應式的 應該改為ref或者reactivelet tel = '138888888' // 此時name,age,tel 不是響應式的 應該改為ref或者reactive// 方法function changeName(){name = 'zhang-san'}function changeAge(){age += 1}function showTel(){alert(tel)}// 把數據和方法交出去return {name, age, changeAge, changeName, showTel}}}
</script>
setup語法糖簡化后代碼如下:
<script lang="ts">export default {name: 'Person',}
</script><script setup lang="ts">// 數據let name = '張三' // 此時name,age,tel 不是響應式的 應該改為ref或者reactivelet age = 18 // 此時name,age,tel 不是響應式的 應該改為ref或者reactivelet tel = '138888888' // 此時name,age,tel 不是響應式的 應該改為ref或者reactive// 方法function changeName(){name = 'zhang-san'}function changeAge(){age += 1}function showTel(){alert(tel)}// 此時不需要return 自動提交
</script>
3. 響應式數據
響應式數據創建有兩種方法,一種是ref
,一種是reactive
ref
定義基本類型的數據
使用的相關代碼如下:
<template><div class="app"><h2>姓名:{{ name }}</h2> // 利用大括號包起來的是不需要.value的<h2>年齡:{{ age }}</h2> // 利用大括號包起來的是不需要.value的<button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="showTel">查看聯系方式</button></div>
</template><script setup lang="ts">import {ref} from 'vue'let name = ref('張三')let age = ref(18) let tel = ref('138888888')// 在ref包裹住后,需要操作值都需要.valuefunction changeName(){name.value = 'zhang-san'}function changeAge(){age.value += 1}function showTel(){alert(tel.value)}
這里值用ref
包裹起來之后,變量會變成一個RefImpl
類的數據,這時要修改值直接對變量操作是無意義的,我們需要對.value
進行操作;這里要注意的是,ref
也可以定義對象類的響應式數據,實現原理是先用ref
包裹,再用reactive
包裹,即取值還是需要用value
;

reactive
定義對象類型的數據
使用的相關代碼如下:
<template><div class="app"><h2>姓名:{{ student.name }}</h2><h2>年齡:{{ student.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button></div>
</template><script lang="ts">export default {name: 'Person',}
</script><script setup lang="ts">import {reactive} from 'vue'let student = reactive({name:'張三', age:18})function changeName(){student.name = 'zhang-san'}function changeAge(){student.age += 1}</script><style scoped>/* 樣式 */.app {background-color: #ddd;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}button {margin: 10px;}
</style>
用reactive
包起來后,對象變成了一個Proxy
的對象,原對象在Proxy
里面的target
中;這里的reactive
是深層次的,只能定義對象類型的響應式數據;

ref
和reactive
的對比

這里要注意的是,重新分配reactive
的對象時,使用Object.assign
,但是如果是利用ref
定義的對象類數據,我們是可以直接進行替換的;
對響應式數據進行解構,toRef
和toRefs
:
let person = reactive({name: '張三',age: 18
})let {name, age} = person
// let name = person.name
// let age = person.agelet {name, age} = toRefs(person) //把reactive對象里面的每一組對象轉化為ref
// let name = toRef(person, 'name')
// let age = toRef(person, 'age')
4. 計算屬性
v-bind
是 單向綁定,數據流向頁面;v-model
是 雙向綁定,頁面也可以流向數據;
計算屬性 computed
是只要響應式變量出現了變化,就隨之變化;
使用例子如下:
<template><div class="app">姓名:<input type="text" v-model="name"> <br>年齡:<input type="text" v-model="age"> <br>information: {{ information }}</div>
</template><script lang="ts">export default {name: 'Person',}
</script><script setup lang="ts">import {ref, computed} from 'vue'let name = ref('zhangsan')let age = ref(18)let information = computed(()=>{return name.value + age.value})</script><style scoped>/* 樣式 */.app {background-color: #ddd;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}
</style>
computed
是用來區別于方法的,使用computed
得到的屬性是沒有緩存的,而且computed
得到的屬性是不可修改的;如果需要修改,則需要使用以下方法:
<template><div class="app">姓名:<input type="text" v-model="name"> <br>年齡:<input type="text" v-model="age"> <br>information: {{ information }} <br><button @click="changeInformation">修改information為lisi</button></div>
</template><script lang="ts">export default {name: 'Person',}
</script><script setup lang="ts">import {ref, computed} from 'vue'let name = ref('zhangsan')let age = ref(18)let information = computed({get(){return name.value + '-' + age.value},set(val){const [s1, s2] = val.split('-')name.value = s1age.value = parseInt(s2)}})function changeInformation(){information.value = 'lisi-18'}</script><style scoped>/* 樣式 */.app {background-color: #ddd;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}
</style>
day 2
5. watch 監視
情況1:監視ref
定義的基本類型數據
停止監視只需要調用watch
函數的返回值就可以;
<template><div><h5>情況1:監視【ref】定義的值是【基本類型】的數據</h5>sum : {{ sum }} <br><button @click="changeSum"> sum + 1</button> <br><hr></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {ref, watch} from 'vue'let sum = ref(1)function changeSum(){sum.value += 1}// 這里的sum是不需要添加.value的,返回值就是停止監視的函數const stopwatch = watch(sum, (newVal, oldVal)=>{console.log('sum變化了', newVal, oldVal)// 如果sum的最新值大于等于10則停止監視if(newVal >= 10 ){stopwatch()}})
</script><style scoped>
</style>
情況2:監視ref
定義的對象類型數據
這里要注意的是:若修改的是ref定義的對象中的屬性,newVal和oldVal都是新值,因為是同一個對象;若修改的是ref定義的整個對象,newVal是新值,oldVal是舊值,因為不是同一個對象;
<template><div><h5>情況2:監視【ref】定義的值是【對象類型】的數據</h5>姓名: {{ person.name }} <br>年齡: {{ person.age }} <br><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeFull">修改整個人</button></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {ref, watch} from 'vue'let person = ref({name: '張三',age: 18})function changeName (){person.value.name = '李四'}function changeAge (){person.value.age = 19}function changeFull (){person.value = {name: '王五', age: 20}}// 監視【ref】定義的【對象類型數據】,監視的是對象的地址值,若想要監視// 對象的內部屬性的變化,需要手動開啟深度監視deep// 若修改的是ref定義的對象中的屬性,newVal和oldVal都是新值,因為是同一個對象// 若修改的是ref定義的整個對象,newVal是新值,oldVal是舊值,因為不是同一個對象// watch的第一個參數是:被監視的數據// watch的第二個參數是:監視的回調// watch的第三個參數是:配置對象(deep, immediate ... )watch(person, (newVal, oldVal)=>{console.log('person變化了', newVal, oldVal)}, {deep: true})
</script><style scoped>button {margin: 10px;}
</style>
情況3:監視reactive
定義的對象類型數據
很簡單,只需要把ref
定義的對象改為reactive
定義的對象,然后在修改整個對象的時候使用Object.assign
替換就可以;
<template><div><h5>情況3:監視【reactive】定義的值是【對象類型】的數據</h5>姓名: {{ person.name }} <br>年齡: {{ person.age }} <br><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeFull">修改人</button></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {reactive, watch} from 'vue'let person = reactive({name: '張三',age: 18})function changeName (){person.name = '李四'}function changeAge (){person.age = 19}function changeFull (){// 并沒有修改地址值;Object.assign(person, {name: '王五', age: 20})}// 監視【reactive】定義的對象類型數據,默認是開啟深度監視的,而且深度是關不掉的watch(person, (newVal, oldVal)=>{console.log('person變化了', newVal, oldVal)})</script><style scoped>button {margin: 10px;}
</style>
情況4:監視ref
或者reactive
定義的對象類型中的某個屬性

<template><div><h5>情況4:監視【ref或reactive】定義的【對象類型】某個屬性</h5>姓名: {{ person.name }} <br>年齡: {{ person.age }} <br>車輛:{{ person.car.c1 }}, {{ person.car.c2 }} <br><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeC1">修改c1</button><button @click="changeC2">修改c2</button><button @click="changeCar">修改car</button></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {reactive, watch} from 'vue'let person = reactive({name: '張三',age: 18,car:{c1: 'asd',c2: 'das'}})function changeName (){person.name = '李四'}function changeAge (){person.age = 19}function changeC1(){person.car.c1 = 'qqq'}function changeC2(){person.car.c2 = 'www'}function changeCar(){person.car = {c1:'yyy', c2:'jjj'}}// 監視響應式對象中的某個屬性,且該變量是基本類型的,要寫成函數式/* watch(()=>person.name, (newVal, oldVal)=>{console.log('person.name變化了', newVal, oldVal)}) */// 監視響應式對象中的某個屬性,且該屬性是對象類型的,可以直接寫,也能寫函數,推薦寫函數watch(()=>person.car, (newVal, oldVal)=>{console.log('person.car變化了', newVal, oldVal)}, {deep:true})</script><style scoped>button {margin: 10px;}
</style>
情況5:監視多個數據
<template><div><h5>情況4:監視【ref】定義的值是【對象類型】的數據</h5>姓名: {{ person.name }} <br>年齡: {{ person.age }} <br>車輛:{{ person.car.c1 }}, {{ person.car.c2 }} <br><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeC1">修改c1</button><button @click="changeC2">修改c2</button><button @click="changeCar">修改car</button></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {reactive, watch} from 'vue'let person = reactive({name: '張三',age: 18,car:{c1: 'asd',c2: 'das'}})function changeName (){person.name = '李四'}function changeAge (){person.age = 19}function changeC1(){person.car.c1 = 'qqq'}function changeC2(){person.car.c2 = 'www'}function changeCar(){person.car = {c1:'yyy', c2:'jjj'}}// 此時newVal和oldVal是數組與前面的對應watch([()=>person.name, ()=>person.age], (newVal, oldVal)=>{console.log('變化了', newVal, oldVal)})</script><style scoped>button {margin: 10px;}
</style>
6. watchEffect
相較于watch,watchEffect不需要指定監視對象,而是響應式的追蹤對象;

<template><div><h5>情況4:監視【ref】定義的值是【對象類型】的數據</h5>姓名: {{ person.name }} <br>年齡: {{ person.age }} <br>車輛:{{ person.car.c1 }}, {{ person.car.c2 }} <br><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeC1">修改c1</button><button @click="changeC2">修改c2</button><button @click="changeCar">修改car</button></div>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {reactive, watch, watchEffect} from 'vue'let person = reactive({name: '張三',age: 18,car:{c1: 'asd',c2: 'das'}})function changeName (){person.name = '李四'}function changeAge (){person.age += 1}function changeC1(){person.car.c1 = 'qqq'}function changeC2(){person.car.c2 = 'www'}function changeCar(){person.car = {c1:'yyy', c2:'jjj'}}// 此時newVal和oldVal是數組與前面的對應/* watch([()=>person.name, ()=>person.age], (newVal, oldVal)=>{let [newname, newage] = newValif( newage > 23 ){console.log('發送請求')}}) */// 如果采用watchEffect,全自動的watch;watchEffect(()=>{if( person.age > 23 ){console.log('發送請求')}})</script><style scoped>button {margin: 10px;}
</style>
7. 標簽的ref
屬性
利用ref
于document.getElementById('')
的區別在于,前者是局部的,不會受到整體的干擾;

<template><h2> 北京 </h2><h2 ref="title"> 師范 </h2><h2> 大學 </h2><button @click="output"> 點擊一下輸出樣式 </button>
</template><script lang="ts">export default {name: 'Person'}
</script><script setup lang="ts">import {ref, defineExpose} from 'vue'// 這里變量名和template中的ref中的變量名對應上了let title = ref()function output(){console.log(title.value)}// 在這里可以使調用該模塊的模塊得到該模塊的內容defineExpose({title})
</script><style scoped>/* 這里的scoped是局部樣式,防止和子文件樣式出現重復而全部修改無腦加上就好 */
</style>