最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

面試官常問的題之說一下Vue中setup的props和context

 更新時(shí)間:2026年04月03日 09:23:12   作者:喜歡吃辣椒炒肉拌面  
setup是一個(gè)組件選項(xiàng),在組件被創(chuàng)建之前,props被解析之后執(zhí)行,這篇文章主要介紹了Vue中setup的props和context的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、props:和 Vue2 核心邏輯完全一致,僅訪問方式微調(diào)

props 作為 Vue 「父?jìng)髯印沟暮诵耐ㄐ欧绞?/p>

Vue3 中 單向數(shù)據(jù)流、類型校驗(yàn)、默認(rèn)值 / 必傳項(xiàng) 等核心規(guī)則和 Vue2 完全一樣,唯一區(qū)別是「訪問方式」:

1. 共性(Vue2/Vue3 通用)

  • 單向數(shù)據(jù)流:子組件不能直接修改 props,必須通過 emit 通知父組件修改;
  • 支持類型校驗(yàn)( String / Number / Array / Object 等)、默認(rèn)值、自定義校驗(yàn)規(guī)則;
  • 父組件傳的屬性如果沒被 props 聲明,會(huì)落到 attrs 中(下文會(huì)提)。

2. 用法對(duì)比(Vue2 選項(xiàng)式 vs Vue3 組合式)

<!-- Vue2 選項(xiàng)式 API -->
<script>
export default {
  props: {
    name: { type: String, default: '默認(rèn)名' },
    age: { type: Number, required: true }
  },
  mounted() {
    console.log(this.name); // ?? 通過 this 訪問
  }
}
</script>
<!-- Vue3 組合式 API(setup) -->
<script>
export default {
  // ?? props 定義規(guī)則和 Vue2 完全一樣
  props: {
    name: { type: String, default: '默認(rèn)名' },
    age: { type: Number, required: true }
  },
  // ?? props 作為 setup 第一個(gè)參數(shù)傳入,無需 this
  setup(props) {
    console.log(props.name); // 直接訪問
    // 注意:props 是響應(yīng)式的,解構(gòu)會(huì)丟失響應(yīng)式,需用 toRefs
    const { name } = Vue.toRefs(props);
    console.log(name.value); // ref 需 .value 訪問
  }
}
</script>

二、context:Vue3 把 Vue2 的「this 上的通信屬性」聚合到上下文

context 是 setup 的第二個(gè)參數(shù)(非響應(yīng)式,可直接解構(gòu)),核心作用是替代 Vue2 中 this 上的「非 props 相關(guān)通信能力」,你提到的幾個(gè)屬性對(duì)應(yīng)關(guān)系精準(zhǔn),補(bǔ)充用法細(xì)節(jié):

context 屬性Vue2 對(duì)應(yīng)寫法核心用法示例
context.emitthis.$emit子傳父觸發(fā)事件:context.emit('change', { id: 1 })(父組件用 @change 接收)
context.slotsthis.$slots訪問父組件傳入的插槽:context.slots.header()(Vue3 插槽是函數(shù),需加 () 調(diào)用)
context.attrsthis.$attrs接收父組件未被 props 聲明的屬性:父?jìng)?nbsp;class="box" 且 props 未聲明 → context.attrs.class
context.expose()無(Vue2 無此能力)主動(dòng)暴露子組件內(nèi)部屬性給父組件:context.expose({ fn: () => console.log('暴露的方法') })

核心示例(context 解構(gòu)使用,更簡(jiǎn)潔)

<script>
export default {
  setup(props, { emit, slots, attrs, expose }) {
    // 1. 子傳父:觸發(fā)自定義事件
    const handleClick = () => emit('submit', '子組件數(shù)據(jù)');
    // 2. 訪問具名插槽
    console.log(slots.footer()); // 獲取父組件傳入的 footer 插槽內(nèi)容
    // 3. 訪問未聲明的屬性
    console.log(attrs['data-id']); // 父?jìng)?data-id="123" 且未被 props 聲明
    // 4. 暴露內(nèi)部方法給父組件(父通過 ref 僅能訪問暴露的內(nèi)容)
    const internalFn = () => '內(nèi)部邏輯';
    expose({ internalFn }); // 父組件 ref.value.internalFn() 可調(diào)用
    return { handleClick };
  }
}
</script>

1. 子組件(Child.vue):核心邏輯詳解

<template>
  <!-- 點(diǎn)擊按鈕觸發(fā)子傳父事件 -->
  <button @click="handleClick">點(diǎn)擊觸發(fā)submit事件</button>
  <!-- 渲染父組件傳入的footer具名插槽 -->
  <div class="slot-container">
    <slot name="footer"></slot>
  </div>
  <!-- 把a(bǔ)ttrs中的data-id透?jìng)鹘o內(nèi)部div(演示attrs用法) -->
  <div :data-id="attrs['data-id']">透?jìng)鞲附M件未聲明的data-id屬性</div>
</template>
<script>
// 導(dǎo)入vue的核心方法(按需導(dǎo)入,Vue3組合式API規(guī)范)
import { toRefs } from 'vue';
export default {
  // 第一步:聲明props(僅聲明name,未聲明data-id,所以data-id會(huì)落到attrs中)
  props: {
    name: {
      type: String,
      default: '默認(rèn)名稱'
    }
  },
  // setup第二個(gè)參數(shù)解構(gòu)出:emit(子傳父)、slots(插槽)、attrs(透?jìng)鲗傩裕?、expose(暴露內(nèi)容)
  setup(props, { emit, slots, attrs, expose }) {
    // ?? 1. 子傳父:觸發(fā)自定義事件(核心用法)
    const handleClick = () => {
      // 第一個(gè)參數(shù):事件名(父組件用@submit接收);第二個(gè)參數(shù):傳遞給父組件的數(shù)據(jù)
      emit('submit', {
        msg: '子組件傳遞的數(shù)據(jù)',
        name: props.name // 結(jié)合props使用,把props數(shù)據(jù)也傳給父組件
      });
    };
    // ?? 2. 訪問具名插槽(控制臺(tái)打印插槽內(nèi)容,驗(yàn)證是否傳入)
    console.log('===== 訪問footer插槽 =====');
    // Vue3中slots的每個(gè)插槽都是函數(shù),調(diào)用后返回VNode數(shù)組(插槽的DOM結(jié)構(gòu))
    if (slots.footer) { // 先判斷父組件是否傳入了footer插槽,避免報(bào)錯(cuò)
      const footerSlotContent = slots.footer();
      console.log('footer插槽的VNode內(nèi)容:', footerSlotContent);
    } else {
      console.log('父組件未傳入footer插槽');
    }
    // ?? 3. 訪問父組件未被props聲明的屬性(attrs)
    console.log('===== 訪問attrs =====');
    console.log('父組件傳入的data-id:', attrs['data-id']); // 父?jìng)鞯膁ata-id未被props聲明,所以在attrs中
    console.log('父組件傳入的class(若有):', attrs.class); // class/style會(huì)自動(dòng)透?jìng)?,也?huì)在attrs中
    // 注意:attrs是非響應(yīng)式的,若需要響應(yīng)式,可結(jié)合toRefs(但一般attrs無需響應(yīng)式)
    // ?? 4. 暴露子組件內(nèi)部方法/屬性給父組件(父組件通過ref訪問)
    // 定義子組件內(nèi)部方法(未return也能通過expose暴露)
    const internalFn = () => {
      return `內(nèi)部方法執(zhí)行成功!props.name的值是:${props.name}`;
    };
    // 定義內(nèi)部屬性(僅暴露給父組件,模板中無法直接使用,除非return)
    const internalData = '子組件內(nèi)部私有數(shù)據(jù)';
    // 主動(dòng)暴露指定內(nèi)容(只有這里聲明的,父組件才能通過ref訪問)
    expose({
      internalFn, // 暴露內(nèi)部方法
      internalData, // 暴露內(nèi)部屬性
      // 也可以暴露props(方便父組件直接獲取props值)
      getPropsName: () => props.name
    });
    // ?? 5. 補(bǔ)充:props的響應(yīng)式使用(可選)
    // 解構(gòu)props并保留響應(yīng)式(若需要單獨(dú)使用props中的屬性)
    const { name } = toRefs(props);
    console.log('===== props使用 =====');
    console.log('props.name的值(響應(yīng)式):', name.value);
    // 把需要在模板中使用的方法return出去(handleClick在模板中綁定點(diǎn)擊事件,必須return)
    return {
      handleClick,
      attrs // 把a(bǔ)ttrsreturn出去,方便模板中使用(如上面模板中的:data-id="attrs['data-id']")
    };
  }
};
</script>

2. 父組件(Parent.vue):調(diào)用子組件并配合使用

<template>
  <div class="parent-container">
    <h3>父組件</h3>
    <!-- 第二步:使用子組件,完成以下操作:
         1. 傳props:name="測(cè)試名稱"
         2. 傳未聲明的屬性:data-id="10086"(會(huì)落到子組件attrs中)
         3. 綁定子組件的自定義事件:@submit="handleChildSubmit"
         4. 傳入具名插槽:<template #footer>...</template>
         5. 給子組件加ref:childRef(用于訪問子組件暴露的內(nèi)容)
    -->
    <Child
      ref="childRef"
      name="測(cè)試名稱"
      data-id="10086"
      class="child-component"
      @submit="handleChildSubmit"
    >
      <!-- 傳入footer具名插槽(子組件會(huì)訪問這個(gè)插槽) -->
      <template #footer>
        <p>這是父組件傳給子組件的footer插槽內(nèi)容</p>
      </template>
    </Child>
    <!-- 顯示子組件傳遞的數(shù)據(jù) -->
    <div class="child-data" v-if="childSubmitData">
      <h4>子組件傳遞的數(shù)據(jù):</h4>
      <p>msg:{{ childSubmitData.msg }}</p>
      <p>name:{{ childSubmitData.name }}</p>
    </div>
    <!-- 點(diǎn)擊按鈕訪問子組件暴露的方法/屬性 -->
    <button @click="accessChildExpose">訪問子組件暴露的內(nèi)容</button>
  </div>
</template>
<script>
// 導(dǎo)入子組件
import Child from './Child.vue';
// 導(dǎo)入vue的ref(用于創(chuàng)建子組件的引用)和onMounted(生命周期)
import { ref, onMounted } from 'vue';
export default {
  // 注冊(cè)子組件
  components: {
    Child
  },
  setup() {
    // ?? 1. 創(chuàng)建子組件的ref引用(用于訪問子組件暴露的內(nèi)容)
    const childRef = ref(null);
    // ?? 2. 接收子組件的自定義事件數(shù)據(jù)
    const childSubmitData = ref(null);
    const handleChildSubmit = (data) => {
      console.log('父組件接收到子組件的submit事件數(shù)據(jù):', data);
      childSubmitData.value = data; // 把數(shù)據(jù)存到響應(yīng)式變量中,模板中顯示
    };
    // ?? 3. 訪問子組件通過expose暴露的內(nèi)容
    const accessChildExpose = () => {
      // 確保子組件已掛載(避免初始時(shí)childRef.value為null)
      if (childRef.value) {
        // 調(diào)用子組件暴露的internalFn方法
        const fnResult = childRef.value.internalFn();
        console.log('調(diào)用子組件暴露的internalFn結(jié)果:', fnResult);
        // 獲取子組件暴露的internalData屬性
        const internalData = childRef.value.internalData;
        console.log('獲取子組件暴露的internalData:', internalData);
        // 調(diào)用子組件暴露的getPropsName方法(獲取子組件的props.name)
        const propsName = childRef.value.getPropsName();
        console.log('子組件的props.name:', propsName);
        // 注意:子組件未暴露的內(nèi)容,父組件無法訪問(比如子組件的handleClick)
        console.log('訪問子組件未暴露的handleClick:', childRef.value.handleClick); // undefined
      }
    };
    // ?? 4. 生命周期:組件掛載后,也可以主動(dòng)訪問子組件暴露的內(nèi)容
    onMounted(() => {
      console.log('===== 組件掛載后訪問子組件暴露內(nèi)容 =====');
      if (childRef.value) {
        console.log('掛載后獲取internalData:', childRef.value.internalData);
      }
    });
    // return需要在模板中使用的變量/方法
    return {
      childRef,
      childSubmitData,
      handleChildSubmit,
      accessChildExpose
    };
  }
};
</script>

三、關(guān)鍵總結(jié)

  1. props規(guī)則完全繼承 Vue2,僅在 Vue3 setup 中需通過第一個(gè)參數(shù)訪問,注意響應(yīng)式解構(gòu)(用 toRefs);
  2. context替代 Vue2 中 this 上的通信屬性,把 $emit/$slots/$attrs 聚合到 上下文( context ) ,新增 expose() 增強(qiáng)組件封裝性(Vue2 父組件通過 ref 能訪問子組件所有內(nèi)容,Vue3 需主動(dòng)暴露才可見);
  3. 簡(jiǎn)化記憶:setup(props, context) → 第一個(gè)參數(shù)管「父?jìng)髯拥?props」,第二個(gè)參數(shù)管「子傳父、插槽、透?jìng)鲗傩?、暴露?nèi)容」。

這種設(shè)計(jì)既保留了 Vue2 的使用習(xí)慣,又讓組合式 API 脫離了 this 的束縛,邏輯更聚合,是 Vue3 兼顧「易用性」和「靈活性」的核心設(shè)計(jì)。

到此這篇關(guān)于Vue中setup的props和context的文章就介紹到這了,更多相關(guān)Vue setup的props和context內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

临猗县| 泗阳县| 闽侯县| 石景山区| 宾川县| 合肥市| 电白县| 楚雄市| 凤山市| 宣化县| 广宗县| 安国市| 贵德县| 小金县| 六枝特区| 邛崃市| 玉林市| 中牟县| 永新县| 聊城市| 固镇县| 黑龙江省| 巴彦淖尔市| 巴东县| 沈丘县| 如皋市| 中宁县| 洛扎县| 那曲县| 舒城县| 邢台市| 犍为县| 当涂县| 静宁县| 肇庆市| 集贤县| 陕西省| 通河县| 米易县| 紫云| 泗水县|