跟技術(shù)胖學vue3.0(typescript版)(二) setup() , ref() 和 reactive()

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ù)

把程序改正確很簡單

  1. 引入ref
  2. 給a賦值一個ref對象, 具體是ref(1)
  3. 現(xiàn)在a指向了一個ref對象, 所以聲明a不是let了, 是const
  4. 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 ??????

我們以上文中的四大美女服務員為例:

  1. 進化第一步: 改造為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>
  1. 進化第二步: 既然使用了typescript, 將data的數(shù)據(jù)類型指定好
    這里采用typescript的接口思想
  1. 進化第三步: 每次都用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 進行比較

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容