Vue Composition Api 渲染功能同步发射不起作用

Posted

技术标签:

【中文标题】Vue Composition Api 渲染功能同步发射不起作用【英文标题】:Vue Composition Api render function sync emit doesn't work 【发布时间】:2021-04-06 00:35:39 【问题描述】:

我想重构 this 教程中关于渲染函数的代码以使用 Composition API。除了 onClick 函数中的context.emit("update:activeTabId", tab.props.tabId); 行之外,一切都运行良好。控制台记录 tab.props.tabId 显示 onClick 函数可以正常工作并正确读取 tabId,但 update:activeTabId 不会更新 activeTabId 值。是否有另一种方法可以在 Composition API 中使用同步修饰符发出事件,还是我做错了什么?

这是我的代码:

---- App.vue ----

<template>
<!-- eslint-disable-next-line -->
  <tab-container v-model:activeTabId="activeTabId">
    <tab tabId="1">Tab #1</tab>
    <tab tabId="2">Tab #2</tab>
    <tab tabId="3">Tab #3</tab>

    <tab-content tabId="1">Content #1</tab-content>
    <tab-content tabId="2">Content #2</tab-content>
    <tab-content tabId="3">Content #3</tab-content>
  </tab-container>
</template>

<script>
import ref from 'vue'
import Tab, TabContent, TabContainer from './components/tabs.js';

export default 
  components: 
    Tab, 
    TabContent,
    TabContainer
  ,
  setup() 
    const activeTabId = ref('1');

    return 
      activeTabId,
    ;
  ,
;
</script>

--- tabs.js ---

import  h  from "vue";

export const TabContainer = 
  props: 
    activeTabId: 
      type: String,
      required: true,
    ,
  ,
  emits: ['update:activeTabId'],
  setup(props, context) 
    const $slots = context.slots.default();
    const tabs = $slots
      .filter((x) => x.type === Tab)
      .map((tab) =>
        h(tab, 
          class: 
            tab: true,
            active: props.activeTabId === tab.props.tabId,
          ,
          onClick: () => 
            console.log(tab.props.tabId)
            context.emit("update:activeTabId", tab.props.tabId);
          ,
        )
      );

    const content = $slots.find(
      (slot) =>
        slot.props.tabId === props.activeTabId && slot.type === TabContent
    );

    return () => [
      h(() => h("div",  class: "tabs" , tabs)), 
      h(() => h("div", content))
    ];
  ,
;

const tabItem = (content) => (
  ...content,
  props: 
    tabId: 
      type: String,
      required: true,
    ,
  ,
  setup(_, context) 
    return () => h("div", context.slots.default())
  
);

export const Tab = tabItem( name: "Tab" );
export const TabContent = tabItem( name: "TabContent" );

【问题讨论】:

我进行了快速测试,您的代码似乎可以正常工作,父模型正在为我正确更新:codesandbox.io/s/flamboyant-***-46r62?file=/src/App.vue 感谢@LeBen 的回复。是的,activeTabId 的值正在 App.vue 中更新,但不知何故新值没有传递给TabContainer。似乎TabContainer 只呈现一次并且从不更新。在标签上单击 Content 值应该会改变。 【参考方案1】:

经过一些研究,我发现 activeTabId 正在更新,但 TabContainer 不知何故不认为它是反应值,所以它没有改变。我已经用 watchEffect 包装了所有 TabContainer 逻辑,观察 activeTabid 的变化,它现在可以正常工作了!

https://codesandbox.io/s/solitary-currying-50ick?file=/src/App.vue

【讨论】:

以上是关于Vue Composition Api 渲染功能同步发射不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Vue 3 Composition API、Props 和 v-if 渲染,尽管值为 false

Storybook vue composition api,_router of undefined

Vue 3 中的模板渲染与渲染函数 h()

Vue3.x Composition API 详解

围绕Vue 3 Composition API构建一个应用程序,包含一些最佳实践!

Vue 3 Composition API - 类似标签的组件中的“子”数据