開發(fā)知識點(diǎn)

toRaw 與 markRaw

目的是不想使用響應(yīng)式對象

  1. toRaw,將一個響應(yīng)式對象轉(zhuǎn)為普通對象,對這個普通對象的操作不會引起頁面更新,提高性能。
  2. markRaw,標(biāo)記一個對象,使其永遠(yuǎn)不會再成為響應(yīng)式對象
    • 有些值不應(yīng)被設(shè)置為響應(yīng)式的,例如復(fù)雜的第三方類庫等
    • 當(dāng)渲染具有靜態(tài)數(shù)據(jù)源的大列表時,跳過響應(yīng)式轉(zhuǎn)換可以提高性能

示例一

動態(tài)組件<component> is 在接收一個組件時,明確要求不能是一個響應(yīng)式對象

import { ref, markRaw } from 'vue'
import Foo from './foo/index.vue'

const list = ref([
    {
        // ...
        component: markRaw(Foo)
    }
])
<template>
    <div v-for="(item, index) in list" :key="index">
        <component :is="item.component"></component>
    <div>
</template>

示例二

Vue3 封裝 echarts 時,監(jiān)聽窗口大小變化時,調(diào)用 echarts resize() 函數(shù)更新圖表,會發(fā)現(xiàn)報錯:
TypeError: Cannot read properties of undefined (reading 'type')
原因是,vue3默認(rèn)把 echarts 實(shí)例轉(zhuǎn)為響應(yīng)式proxy代理,致使 resize() 無法獲取 coordSys.type
解決方案

import { ref, markRaw, onMounted } from 'vue'
import * as echarts from 'echarts'
import { EChartsOption, EChartsType } from 'echarts'

const chartRef = ref<EChartsType>()
onMounted(() => {
    chartRef.value = markRaw(echarts.init(document.getElementById("chart")))
})

shallowRef

reactive 底層其實(shí)就是通過 ref 創(chuàng)建的;
默認(rèn)情況下,無論是 ref 還是 reactive 都是深度監(jiān)聽;而 shallowRef / shallReactive 都是非深度監(jiān)聽,只會包裝第一層的數(shù)據(jù),如果想更改多層的數(shù)據(jù),必須先更改第一層的數(shù)據(jù),然后在去更改其他層的數(shù)據(jù),這樣視圖上的數(shù)據(jù)才會發(fā)生變化。
所以,當(dāng)我們試圖將一個component組件 變成響應(yīng)式時,vue3會發(fā)出警告:should be avoided by marking the component with markRaw or using shallowRef instead of ref -- 用 markRaw / shallowRef 標(biāo)記組件

defineProps、defineEmits、defineExpose

defineProps

聲明組件 props 傳值

<script setup lang="ts">
  // 采用 ts專有聲明,無默認(rèn)值
  defineProps<{
      msg: string,
      num?: number
  }>()

  // 采用ts專有聲明,有默認(rèn)值
  interface Props {
      msg?: string
      labels?: string[]
  }
  const props = withDefaults(defineProps<Props>(), {
      msg: 'hello',
      labels: () => ['one', 'two']
  })

  // 非ts專有聲明
  defineProps({
      msg: String,
      num: {
          type:Number,
          default: ''
      }
  })
</script>

defineEmits

子組件聲明暴露的事件

<script setup lang="ts">
    /*ts專有*/
   const emit= defineEmits<{
      (e: 'click', num: number): void
   }>()

  /*非ts專有*/
  const emit= defineEmits(['click'])
  
  const clickThis = () => {
      emit('click', 2)
  }
</script>

defineExpose

子組件暴露出去、讓父組件訪問的屬性

// helloword.vue
import { ref, defineExpose } from 'vue'

const count = ref(123)
defineExpose({
   count
})

// Something.vue
<template>
  <helloword ref="hello"></helloword>
  <button @click="helloClick">touch me</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import helloword from './components/HelloWorld.vue'

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

相關(guān)閱讀更多精彩內(nèi)容

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