tips: vue2.0 和 vue3.0的區(qū)別
- 沒有data methods computed 那些內(nèi)容了 而是用setup()函數(shù)代替
-
<template>里的“根元素”不再只能是一個了
一. setup() 函數(shù)
現(xiàn)在, 我們沒有必要把數(shù)據(jù)寫在 data里 把方法寫在methods 里了
我們把數(shù)據(jù)和方法寫在setup里, 再通過return 暴露出去
<template>
<h2>請選擇服務員:</h2>
<div>
<button
v-for="(name, index) in girls"
v-bind:key="index"
@click="selectGirlFun(index)"
>
{{ index }}:{{ name }}
</button>
</div>
<h2>您選擇了:{{ selectedGirl }}!!</h2>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "App",
setup() {
const girls = ref(["貂蟬", "王昭君", "西施", "楊玉環(huán)"]);
const selectedGirl = ref("");
const selectGirlFun = (index: number) => {
selectedGirl.value = girls.value[index];
};
return {
girls,
selectedGirl,
selectGirlFun,
};
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
二. ref() 函數(shù)
我們看到, 上述例程中使用了 ref()函數(shù)
ref()這個函數(shù)使得我們的變量擁有了雙向綁定屬性,
這是和vue2.0中寫在data里就可以雙向綁定是不同的.
下面我們通過一個錯誤的例程和 修改后正確的例程來說明此函數(shù)
錯誤的例程

實驗結(jié)果也是錯的, a其實在增加, 但并沒有顯示在頁面上

正確但例程, 要用到vue3.0 的 ref函數(shù)
把程序改正確很簡單
- 引入ref
- 給a賦值一個ref對象, 具體是ref(1)
- 現(xiàn)在a指向了一個ref對象, 所以聲明a不是let了, 是const
- a的值要用 a.value來獲取
上面一直在說ref對象, 其實人家的真實類型是:RefImpl, 可以從下面的截圖看出它的結(jié)構(gòu)
<template>
<h2>{{ a }}</h2>
<button @click="add">+</button>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "App",
setup() {
const a= ref(1);
const add = () => {
a.value += 1;
console.log(a);
};
return {
a,
add
};
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>


這樣做有什么好處?
這樣做的好處是區(qū)分了需要界面顯示的變量和只參與script內(nèi)部運算的變量, 從而不做不必要的數(shù)據(jù)綁定, 提高性能.
三. reactive()
除了ref這種方式, 我們還有一種方式可以把數(shù)據(jù)設置成雙向綁定數(shù)據(jù), 那就是reactive()
這也是和ref一樣的把變量綁定到雙向數(shù)據(jù)綁定對象的方法, 這個函數(shù)接收一個對象作為參數(shù)
下面,我們嘗試將上面那個a++的例子改為reactive
<template>
<h2>{{ a.value }}</h2>
<button @click="add">+</button>
</template>
<script lang="ts">
import { reactive } from "vue"; //從vue模組引入reactive函數(shù)
export default ({
name: "App",
setup() {
const a= reactive({value:1}); //reactive接收對象作為參數(shù), 所以應該這樣寫
const add = () => {
a.value += 1; //所以這里也要修改 a的value屬性 上面也要顯示a的value屬性
console.log(a);
};
return {
a,
add
};
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

根據(jù)控制臺輸出, 我們可以看到 a 現(xiàn)在是一個Proxy掛鉤, 掛在一個target 對象上
所以網(wǎng)上說的ref是reactive的一個特例是不對的, 雖然兩者用法很相似
四. reactive進階用法----像vue2.0一樣用vue3.0 ??????
我們以上文中的四大美女服務員為例:
- 進化第一步: 改造為reactive() 綁定數(shù)據(jù)
<template>
<h2>請選擇服務員:</h2>
<div>
<button
v-for="(name, index) in data.girls"
v-bind:key="index"
@click="data.selectGirlFun(index)"
>
{{ index }}:{{ name }}
</button>
</div>
<h2>您選擇了:{{ data.selectedGirl }}!!</h2>
</template>
<script lang="ts">
import { reactive } from "vue";
export default {
name: "App",
setup() {
const data = reactive({
girls: ["貂蟬", "王昭君", "西施", "楊玉環(huán)"],
selectedGirl: "",
selectGirlFun: (index: number) => {
data.selectedGirl = data.girls[index];
},
});
return {
data,
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
- 進化第二步: 既然使用了typescript, 將data的數(shù)據(jù)類型指定好
這里采用typescript的接口思想

- 進化第三步: 每次都用data.xxx 太麻煩, 能不能用
...擴展運算符省略掉data.?
直接用擴展運算符是不行的 因為擴展運算符會取消data的響應式
要使用 toRefs函數(shù)
toRefs()接收一個reactive object,并把它變成一個ToRefs<T>的泛型類型,使其具有雙向數(shù)據(jù)綁定的特性
<template>
<h2>請選擇服務員:</h2>
<div>
<button
v-for="(name, index) in girls"
v-bind:key="index"
@click="selectGirlFun(index)"
>
{{ index }}:{{ name }}
</button>
</div>
<h2>您選擇了:{{ selectedGirl }}!!</h2>
</template>
<script lang="ts">
import { reactive, toRefs } from "vue"; //從vue中引入 toRefs
interface DataProp {
girls: string[];
selectedGirl: string;
selectGirlFun: (index: number) => void;
}
export default {
name: "App",
setup() {
const data: DataProp = reactive({
girls: ["貂蟬", "王昭君", "西施", "楊玉環(huán)"],
selectedGirl: "",
selectGirlFun: (index: number) => {
data.selectedGirl = data.girls[index];
},
});
const refdata = toRefs(data); //把data轉(zhuǎn)為ref類型對象
console.log(data);
console.log(refdata);
return {
...refdata, //用擴展運算符擴展這個變量
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
toRefs 從控制臺打印data 和 refdata 進行比較
