vue3_defineExpose的用法

Syinho發表於2024-03-29

目錄
  • 常規示例
    • 子元件: /components/testCom1.vue
    • 父元件: App.vue
  • 監聽defineExpose返回的資料的變化實現子元件向父元件傳遞資料
  • 父元件中修改子元件defineExpose丟擲的資料, 實現父元件向子元件回傳資料

官網說明

  • defineExpose用於子元件向其父元件傳值.

常規示例

子元件: /components/testCom1.vue

<template>
  <div id="a_container"></div>
</template>

<script setup>
import { ref, reactive, defineExpose } from 'vue'
const a = ref(Math.round(Math.random() * 100))
const b = reactive({
  num: Math.round(Math.random() * 100),
})
const c = 77
defineExpose({ a, b, c })
</script>

<style scoped lang="scss"></style>
  • 在子元件中宣告瞭一個a變數儲存隨機生成資料, 透過

父元件: App.vue

<template>
  <div id="app">
    <test-com1 ref="testCom1Ref"></test-com1>
  </div>
</template>

<script setup>
import testCom1 from './components/testCom1.vue'
import { ref, onMounted } from 'vue'
const testCom1Ref = ref(null)
onMounted(() => {
  console.log(testCom1Ref.value)
  const { a, b, c } = testCom1Ref.value
  console.log(a) // 隨機數
  console.log(b) // {num : 隨機數}
  console.log(c) // 77
})
</script>

<style></style>

監聽defineExpose返回的資料的變化實現子元件向父元件傳遞資料

  • 如下: 子元件丟擲資料, 並在指定時間後更新資料; 父元件在onMounted中透過watch監聽資料, 只能監聽到reactive定義的資料的變化; 因此可以透過defineExpose來返回子元件中的reactive定義的proxy物件, 然後在父元件中透過watch來監聽該資料的變化, 實現子元件向父元件傳遞資料
// components/testCom1.vue
<template>
  <div id="a_container"></div>
</template>

<script setup>
import { ref, reactive, defineExpose } from 'vue'
const a = ref(10) // 獲取一個隨機數
const b = reactive({ 
  num: 20 // 獲取一個隨機數
})
let c = 30 

setTimeout(() => {
  a.value = 100
  b.num = 200
  c = 300
}, 2000)
defineExpose({ a, b, c })
</script>

<style scoped lang="scss"></style>
// App.vue
<template>
  <div id="app">
    <test-com1 ref="testCom1Ref"></test-com1>
  </div>
</template>

<script setup>
import testCom1 from './components/testCom1.vue'
import { ref, onMounted, watch, onBeforeMount } from 'vue'
const testCom1Ref = ref(null)
onMounted(() => {
  const { a, b, c, d } = testCom1Ref.value
  console.log(typeof a) // number
  console.log(typeof b) // object
  console.log(typeof c) // number
  console.log(typeof d) // object
  console.log(a) // 10
  console.log(b.num) // 20
  console.log(c) // 30
  console.log(d.num) // 40

  watch(b, () => {
    console.log('b更新')
    console.log(b) //{num:200}
  })
  watch(
    () => d,
    () => {
      // 不執行, 因為watch只對監聽proxy物件有反應
      console.log('d更新')
      console.log(d)
    }
  )
  setTimeout(() => {
    console.log(a) // 10
    console.log(b.num) // 200
    console.log(c) //30
    console.log(d.num) // 400
  }, 3000)
})
</script>

<style></style>

父元件中修改子元件defineExpose丟擲的資料, 實現父元件向子元件回傳資料

  • 子元件中透過reactive定義的資料, 透過defineExpose丟擲後可以在父元件中獲取得到;
  • 父元件中修改defineExpose丟擲的, 在子元件中透過reactive定義的資料, 可以觸發子元件的資料響應
// components/testCom1.vue
<template>
  <div id="a_container">
    <p key="hasdhj">{{ a }}</p>
    <!-- b由20變化為200, 變化為2000 -->
    <p key="asasda">{{ b.num }}</p>
    <p key="zxcwwd">{{ c }}</p>
    <p key="xcqweq">{{ d.num }}</p>
  </div>
</template>

<script setup>
import { ref, reactive, defineExpose } from 'vue'
const a = ref(10) // 獲取一個隨機數
const b = reactive({
  num: 20 // 獲取一個隨機數
})
let c = 30
const d = { num: 40 }

setTimeout(() => {
  a.value = 100
  b.num = 200
  c = 300 // 因為a,b響應式資料被更新, 所以c也會因為頁面更新而更新, 但它本身不具有響應式
  d.num = 400 // 因為a,b響應式資料被更新, 所以d也會因為頁面更新而更新, 但它本身不具有響應式
}, 2000)
defineExpose({ a, b, c, d })
</script>

<style scoped lang="scss"></style>
// App.vue
<template>
  <div id="app">
    <test-com1 ref="testCom1Ref"></test-com1>
  </div>
</template>

<script setup>
import testCom1 from './components/testCom1.vue'
import { ref, onMounted, watch, onBeforeMount } from 'vue'
const testCom1Ref = ref(null)
onMounted(() => {
  const { a, b, c, d } = testCom1Ref.value
  console.log(typeof a) // number
  console.log(typeof b) // object
  console.log(typeof c) // number
  console.log(typeof d) // object
  console.log(a) // 10
  console.log(b.num) // 20
  console.log(c) // 30
  console.log(d.num) // 40

  watch(b, () => {
    // 每次更新都會執行
    console.log('b更新')
    console.log(b) 
  })
  watch(
    () => d,
    () => {
      // 不執行, 因為watch只對監聽proxy物件有反應
      console.log('d更新')
      console.log(d)
    }
  )
  setTimeout(() => {
    console.log(a) // 10
    console.log(b.num) // 200
    console.log(c) //30
  }, 3000)

  // setTimeout(() => {
  //   b.num = 2000
  //   d.num = 4000 // 不具有響應式, 但因為響應式資料b變化, 頁面重新渲染, d資料也會被重新渲染, 造成該資料有響應式的假象
  // }, 5000);

  setTimeout(() => {
    b.num = 2000
  }, 5000)
  setTimeout(() => {
    d.num = 4000 // 不具有響應式, 且子元件資料變化但頁面並不更新
  }, 5000)
})
</script>

<style></style>