You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue 3插槽作为参数使用且不渲染,如何解决其props非响应式问题?

Vue自定义DataTable插槽Props无响应式问题

在PrimeVue、ElementPlus等主流UI框架中,DataTable组件支持通过插槽传递列配置(比如<DataTableColumn>),我尝试实现类似功能,但遇到了插槽Props不具备响应式的问题:当插槽组件的Props(比如search-options绑定的响应式数据)更新时,父组件的列配置无法同步更新。

当前父组件代码

<script setup>
import {onMounted, useSlots, watch, h, computed} from 'vue';
import { useDataTableStore } from '@/components/DataTable/DataTableStore';

const dataTableStore = useDataTableStore();
const slots = useSlots();

const props = defineProps({
    data: {
        type: Array,
        required: true,
    },
});

onMounted(() => {
    dataTableStore.orderAll = props.orderAll;
    dataTableStore.searchAll = props.searchAll;

    slots.default().forEach(s => {
        dataTableStore.columns.push({
            title: s.props.title,
            prop: s.props.prop ?? s.props.title,
            order: s.props.order ?? false,
            search: s.props.search ?? false,
            searchType: s.props['search-type'] ?? 'text',
            searchOptions: s.props['search-options'] ?? []
        });
    });
});
</script>

组件使用示例

<DataTable
    :data="packagesStore.packages"
    :columns="columns"
    :search-all="true"
    :order-all="true"
    @on-filter="onFilter"
>
    <DataTableColumn
        title="Nr."
        prop="number"
        :search="false"
    />
    <DataTableColumn
        title="Wood"
        prop="wood.id"
        search-type="select"
        :search-options="classificatorsStore.quality"
    />
</DataTable>

解决方案

问题根源在于onMounted只会执行一次,无法追踪插槽Props的后续变化。需要改用响应式监听机制来同步列配置:

修改后的父组件代码

<script setup>
import { watchEffect, useSlots, defineProps } from 'vue';
import { useDataTableStore } from '@/components/DataTable/DataTableStore';

const dataTableStore = useDataTableStore();
const slots = useSlots();

const props = defineProps({
    data: {
        type: Array,
        required: true,
    },
    orderAll: Boolean,
    searchAll: Boolean
});

// 自动追踪插槽和Props变化,同步列配置
watchEffect(() => {
    // 更新全局开关配置
    dataTableStore.orderAll = props.orderAll;
    dataTableStore.searchAll = props.searchAll;

    // 清空旧列配置,重新生成最新列数据
    dataTableStore.columns = [];
    const columnSlots = slots.default?.() || [];
    
    columnSlots.forEach(slotNode => {
        if (!slotNode.props) return;
        
        dataTableStore.columns.push({
            title: slotNode.props.title,
            prop: slotNode.props.prop ?? slotNode.props.title,
            order: slotNode.props.order ?? false,
            search: slotNode.props.search ?? false,
            searchType: slotNode.props['search-type'] ?? 'text',
            searchOptions: slotNode.props['search-options'] ?? []
        });
    });
});
</script>

关键修改点说明

  1. 用watchEffect替代onMounted:watchEffect会自动追踪所有依赖(包括插槽内容、Props),当任何依赖变化时自动重新执行回调,保证列配置始终和最新的插槽Props同步。
  2. 重新生成列配置而非追加:每次更新时先清空旧列数据,避免新旧数据混杂,确保配置完全同步。
  3. 容错处理:用slots.default?.()处理插槽为空的情况,避免调用forEach时报错。

另外需要确保DataTableStore中的columns是响应式数据(比如用Vuex的state或Pinia的ref/reactive定义),这样列配置更新后才能触发UI渲染。

内容的提问来源于stack exchange,提问作者Kin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 08:50:15