整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          vue3-響應式基礎之ref

          明響應式狀態

          ref()

          在組合式 API 中,推薦使用 ref() 函數來聲明響應式狀態: ref() 接收參數,并將其包裹在一個帶有 .value 屬性的 ref 對象中返回:

          import { ref } from 'vue'
          const count = ref(0)
          
          console.log(count) // { value: 0 }
          console.log(count.value) // 0
          
          count.value++
          console.log(count.value) // 1
          

          形式1 setup() 函數

          1. 要在組件模板中訪問 ref,請從組件的 setup() 函數中聲明并返回它們:
          <script lang="ts" >
          import { ref } from 'vue'
          
          export default {
              setup() {
                  const count = ref(0)
          
                  function increment() {
                      // 在 JavaScript 中需要 .value
                      count.value++
                  }
          
                  // 不要忘記同時暴露 increment 函數
                  return {
                      count,
                      increment
                  }
              }
          }
          </script>
          
          <template>
              <div class="container">
                  <div>{{ count }}</div>
                  <button @click="count++">
                      {{ count }}
                  </button>
              </div>
          </template>
          
          <style  scoped>
          .container {}
          </style>
          
          1. 注意,在模板中使用 ref 時,我們不需要附加 .value。為了方便起見,當在模板中使用時,ref 會自動解包 (有一些注意事項)。

          在模板渲染上下文中,只有頂級的 ref 屬性才會被解包。

          在下面的例子中,count 和 object 是頂級屬性,但 object.id 不是:

          const count = ref(0)
          const object = { id: ref(1) }
          
          //模版正常渲染執行
          {{ count + 1 }} 
          
          //模版不會正常渲染非頂級不會被解包仍然是一個ref
          {{ object.id + 1 }}  對象
          
          
          //我們可以將 id 解構為一個頂級屬性
          const { id } = object
          {{ id + 1 }}   //模版正常渲染并執行
          
          //模版自動解包
          {{ object.id }}
          該特性僅僅是文本插值的一個便利特性,等價于 {{ object.id.value }}
          
          

          形式2 <script setup>

          • 在 setup() 函數中手動暴露大量的狀態和方法非常繁瑣。
          • 幸運的是,我們可以通過使用單文件組件 (SFC) 來避免這種情況。我們可以使用 <script setup> 來大幅度地簡化代碼:
          <script setup lang="ts">
          import { ref } from 'vue'
          
          const count = ref(0)
          
          function increment() {
              count.value++
          }
          </script>
          
          <template>
              <button @click="increment">
                  {{ count }}
              </button>
          </template>
          

          深層響應性

          • Ref 可以持有任何類型的值,包括深層嵌套的對象、數組或者 JavaScript 內置的數據結構,比如 Map。
          • Ref 會使它的值具有深層響應性。這意味著即使改變嵌套對象或數組時,變化也會被檢測到:
          <script setup lang="ts">
          import { ref } from 'vue'
          
          const count = ref(0)
          const obj = ref({
              nested: { count: 0 },
              arr: ['foo', 'bar']
          })
          
          function mutateDeeply() {
              // 以下都會按照期望工作
              obj.value.nested.count++
              obj.value.arr.push('baz')
          }
          
          
          function increment() {
              count.value++
          }
          </script>
          
          <template>
              {{ obj.arr }}
              <button @click="mutateDeeply">
                  {{ obj.nested.count + 1 }}
              </button>
          </template>
          

          shallow ref

          可以通過 shallow ref 來放棄深層響應性

          1. 減少大型不可變數據的響應性開銷
          2. 與外部狀態系統集成

          DOM 更新時機

          • 當你修改了響應式狀態時,DOM 會被自動更新。但是需要注意的是,DOM 更新不是同步的。
          • Vue 會在“next tick”更新周期中緩沖所有狀態的修改,以確保不管你進行了多少次狀態修改,每個組件都只會被更新一次。

          要等待 DOM 更新完成后再執行額外的代碼,可以使用 nextTick() 全局 API:

          先來一個用于測試的Demo頁:

          <!DOCTYPE html>
          <html>
           
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <title>ref active toRef toRefs</title>
              <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.1.1/vue.global.js"></script>
          </head>
           
          <body>
              <div id="app">
                  <span> ref: </span>
                  <input type="text" v-model="refValue" @input="inputRefHander" />
                  {{ refValue }}
                  <hr>
                  <span> reactive: (顯示age的值)</span>
                  <input type="text" v-model="reactiveValue.age" @input="inputReactiveHander"  />
                  {{ reactiveValue.age }}
                  <hr>
                  <span> toRef: (使age有響應)</span>
                  <input type="text" v-model="toRefValue" @input="inputToRefValueHander" />
                  {{ toRefValue}}
                  <hr>
                  <span> toRefs: </span>
                  <input type="text" v-model="toRefsValue.name.value" @input="inputToRefsValueHander" />
                  {{ toRefsValue.name.value}}
              </div>
          </body>
           
          </html>
          <script>
          const { createApp, reactive, toRefs, ref, toRef } = Vue;
          const app = createApp({
              setup() {
                  let name = 'chj';
                  const obj = { name: 'chj', gender: 'male', age: 18 }
           
                  const refValue = ref(name);               // => reactive({value:'chj'})
                  const reactiveValue = reactive(obj)       // => reactive({ name: 'chj', gender: 'male', age: 18 })
                  const toRefValue = toRef(obj, 'age')      // => reactive({value:18})
                  const toRefsValue = toRefs(obj)           
           
                  function inputRefHander() {
                      console.log(`ref:::refValue:`);
                      console.log(refValue);
                      console.log(`原始數據`);
                      console.log(name);
                  }
           
                  function inputReactiveHander() {
                      console.log(`reactive:::reactiveValue`);
                      console.log(reactiveValue);
                      console.log(`原始數據`);
                      console.log(obj);
                  }
           
                  function inputToRefValueHander() {
                      console.log(`toRef:::toRefValue: `);
                      console.log(toRefValue);
                      console.log(`原始數據:`);
                      console.log(obj);
                  }
           
                  function inputToRefsValueHander() {
                      console.log(`toRefs:::toRefsValue: `);
                      console.log(toRefsValue);
                      console.log(`原始數據:`);
                      console.log(obj);
                  }
                  return { refValue, inputRefHander, reactiveValue, inputReactiveHander, toRefValue, inputToRefValueHander, toRefsValue, inputToRefsValueHander }
              }
          })
          app.mount("#app")
          </script>

          隨意輸入內容,發現ref“包裹的”數據變化如下:

          對于ref:
          原始數據沒有變化,而ref“包裹的數據”變成了一個新的對象,而且模板有變化。


          對于reactive:
          reactive處理的數據無論是原始數據,“包裹后的數據”,還是模板,都有變化。


          對于toRef:

          toRef處理的數據會有變化,而原始數據也有變化,但是模板沒有變化


          對于toRefs:wtoRefs處理的數據響應變化,原始數據也響應變化,但是模板并沒有變化

          總結

          ef、isRef、toRef、toRefs、toRaw 看著一堆類似的東西,一個頭兩個大,今天整理一篇文章詳細介紹它們的功能及區別。

          1、ref

          ref 屬性除了能夠獲取元素外,也可以使用 ref 函數,創建一個響應式數據,當數據值發生改變時,視圖自動更新。

          <script lang="ts" setup>
          import { ref } from 'vue'
          let str: string = ref('我是張三')
          const chang = () => {
            str.value = '我是鉆石王老五'
            console.log(str.value)
          }
          </script>
          <template>
            <div>
              {{ str }}
              <button type="button" @click="chang">修改值</button>
            </div>
          </template>

          2、isRef

          檢查變量是否為一個被 ref 包裝過的對象,如果是返回 true ,否則返回 false。

          import { ref, isRef, reactive } from 'vue'
          
          let str: string = ref('我是張三')
          let num: number = 1
          let per = reactive({ name: '代碼女神', work: '程序媛' })
          
          console.log('strRes', isRef(str)) //true
          console.log('numRes', isRef(num)) //false
          console.log('perRes', isRef(per)) //false

          3、toRef

          創建一個 ref 對象,其 value 值指向另一個對象中的某個屬性。

          toRef(obj, key) 將對象中的某個值轉化為響應式數據,分為兩種情況:

          • toRef 定義原始非響應式數據,修改值時,原始數據和 copy 數據都會變的,但是視圖不更新。
          <script>
            import { ref, isRef, toRef, reactive } from 'vue'
          let obj = {
            name: '姓名',
            age: 18,
          }
          let name: string = toRef(obj, 'name')
          const chang = () => {
            obj.name = '鉆石王老五'
            name.value = '李四'
            console.log(obj.name) // 李四
            console.log('name', name) // 李四
          }
          //chang() //DOM掛載前調用
          </script>
          <template>
            <div>
              {{ obj.name }} ------- {{ name }}
              <button type="button" @click="chang">修改值</button>
            </div>
          </template>

          注意:如果是在 DOM 掛載之前調用 chang 方法,改變數值,此時數據和視圖都會發生改變。

          • toRef 定義原始數據響應式數據,修改值時,原始數據,和 copy 數據都會改變,視圖也會更新。
          <script>
            import { ref, isRef, toRef, reactive } from 'vue'
          let obj = reactive({
            name: '姓名',
            age: 18,
          })
          let name: string = toRef(obj, 'name')
          const chang = () => {
            obj.name = '鉆石王老五'
            name.value = '李四'
          }
          </script>
          <template>
            <div>
              {{ obj.name }} ------- {{ name }}
              <button type="button" @click="chang">修改值</button>
            </div>
          </template>

          最終值為 “李四”。

          4、toRefs

          toRefs 用來解構 ref、reactive 包裹的響應式數據。接收一個對象作為參數,遍歷對象上的所有屬性,將對象上的所有屬性變成響應式數據。

          let obj = reactive({
            name: '姓名',
            age: 18,
          })
          let { name, age } = toRefs(obj)
          const chang = () => {
            name.value = '鉆石王老五'
            age.value++
          }
          </script>
          <template>
            <div>
              {{ name }} ------- {{ age }}
              <button type="button" @click="chang">修改值</button>
            </div>
          </template>

          toRefs 解構數據時,如果某些參數作為可選參數,可選參數不存在時就會報錯,如:

          let obj = reactive({
            name: '姓名',
            age: 18,
          })
          let { name, age, work } = toRefs(obj)
          const chang = () => {
            name.value = '鉆石王老五'
            age.value++
            console.log('work', work.value)
            work.value = '程序媛'
          }

          此時可以使用 toRef 解決此問題,使用 toRef 解構對象某個屬性時,先檢查對象上是否存在該屬性,如果存在就繼承對象上的屬性值,如果不存在就會創建一個。

          修改上邊的代碼為:

          let obj = reactive({
            name: '姓名',
            age: 18,
          })
          let { name, age } = toRefs(obj)
          let work = toRef(obj, 'work')
          const chang = () => {
            name.value = '鉆石王老五'
            age.value++
            console.log('work', work.value)
            work.value = '程序媛'
          }

          5、toRaw

          將響應式對象轉為原始對象。做一些不想被監聽的事情,從 ref 或 reactive 得到原始數據。

          修改原響應式數據時,toRaw 轉換得到的數據會被修改,視圖也會更新,如:

          <script lang="ts" setup>
          import { ref, isRef, toRef, toRefs, reactive, toRaw } from 'vue'
          let obj = reactive({
            name: '姓名',
            age: 18,
          })
          let newObj = toRaw(obj)
          const chang = () => {
            obj.name = '鉆石王老五'
            obj.age++
          }
          </script>
          <template>
            <div>
              {{ obj.name }} ------- {{ obj.age }}
              <button type="button" @click="chang">修改值</button>
              <br />
              {{ newObj }}
            </div>
          </template>

          如果修改 toRaw 得到的原始數據,原數據也會被修改,但是視圖不更新。如:


          主站蜘蛛池模板: 国产精品久久亚洲一区二区| 无人码一区二区三区视频| 无码精品人妻一区二区三区漫画| 国产短视频精品一区二区三区| 国产成人精品无码一区二区老年人| 好湿好大硬得深一点动态图91精品福利一区二区 | 日本一区二区三区不卡视频中文字幕| 黑人大战亚洲人精品一区| 成人精品一区二区激情| 国产激情з∠视频一区二区| 男人的天堂精品国产一区| 国产91精品一区二区麻豆网站| 91一区二区三区| 精品天海翼一区二区| 69久久精品无码一区二区| 国99精品无码一区二区三区 | 激情内射亚洲一区二区三区爱妻| 福利一区在线视频| 日韩在线视频一区| 午夜一区二区在线观看| 波多野结衣一区二区| 亚洲AV无码一区二区三区在线| 伊人久久精品无码av一区| 久久影院亚洲一区| 国产精品无码一区二区在线观一 | 一区二区3区免费视频| 日本精品啪啪一区二区三区| 精品一区二区ww| 无码丰满熟妇一区二区| 亚洲乱码av中文一区二区| 无码中文字幕一区二区三区| 亚洲日韩中文字幕无码一区| 99无码人妻一区二区三区免费| 国产精品高清一区二区人妖 | 国产91一区二区在线播放不卡| 日本一区二区三区在线视频观看免费| 日韩伦理一区二区| 秋霞电影网一区二区三区| 精品国产一区二区22 | 国产福利电影一区二区三区久久久久成人精品综合 | 国内精品一区二区三区最新|