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

Vue3嵌套vue-draggable时子组件无法获取父级属性解决方案问询

问题根因

你拿不到父级属性有两个核心原因:

  • vue-draggable的item插槽只会向外暴露内置的几个上下文参数:当前循环项element、项索引index,你给<draggable>标签绑定的自定义属性(比如你写的mainType)不会自动注入到插槽作用域,自然解构不出来。
  • 你内外两层#item插槽都用element当解构变量名,内层的同名变量直接遮蔽了外层作用域中代表品牌对象的element,本来不需要传值就能直接访问到父级属性,被重名变量盖住了。
实现方案

方案1:直接利用模板作用域(最简单,适配你当前的两层嵌套场景)

内层draggable本身就写在外层品牌列表的插槽内部,外层插槽解构出的品牌对象在整个内层作用域都可以直接访问,只需要把内外层的解构变量重命名避免冲突就行,不需要额外做属性传递。
核心修正代码如下:

<!-- 外层品牌列表:把解构出的品牌项重命名为brandItem,避免和内层重名 -->
<draggable :list="brand" :disabled="!enabled" item-key="name" class="list-group" ghost-class="ghost"
  v-bind="dragOptions" handle=".handle" :group="{ name: 'brand' }" @start="dragging = true" @end="dragging = false">

  <template #item="{ element: brandItem, index: brandIndex }">
    <div class="list-group-item" :class="{'not-draggable' : !enabled}">
      <div class="row handle drag-object">
        ID: {{ brandItem.id }} , Name: {{ brandItem.name }}

        <button class="btn btn-primary" type="button" data-bs-toggle="collapse" :data-bs-target="'#target'+brandItem.id"
          aria-expanded="false" aria-controls="collapseExample">
          Details
        </button>

        <div class="row">
          <div class="collapse" :id="'#target'+brandItem.id" :class="{'show' : showAll}">
            <div class="card card-body size-classes">
              <!-- 不需要给内层draggable传自定义mainType -->
              <draggable :list="brandItem.content" :disabled="!enabled2"
                item-key="size-class" class="list-group" ghost-class="ghost" v-bind="dragOptions" handle=".handle"
                :group="{ name: 'size-class'+brandItem.name}" 
                @start="dragging2 = true" 
                <!-- 拖拽事件直接把当前品牌对象当参数传入 -->
                @end="handleSizeSort(brandItem, $event)">

                <!-- 内层尺码项重命名为sizeItem,避免和外层brandItem重名 -->
                <template #item="{ element: sizeItem, index: sizeIndex }">
                  <div class="list-group-item size-classes-bar" :class="{'not-draggable' : !enabled2}">
                    <div class="row handle drag-object">
                      <!-- 直接访问外层的brandItem就能拿到父级品牌属性 -->
                      所属品牌: {{ brandItem.name }} ,尺码ID: {{ sizeItem.id }} , 尺码名: {{ sizeItem.name }}

                      <button class="btn btn-primary" type="button" data-bs-toggle="collapse"
                        :data-bs-target="'#target2'+sizeItem.id" aria-expanded="false" aria-controls="collapseExample">
                        Details
                      </button>
                    </div>

                    <div class="collapse" :id="'#target2'+sizeItem.id" :class="{'show' : showAll2}">
                      <div class="card card-body size-classes-details">
                        <h1>Something ..</h1>
                      </div>
                    </div>

                  </div>
                </template>
              </draggable>
            </div>
          </div>
        </div>
      </div>
    </div>
  </template>
</draggable>

对应的拖拽排序处理函数示例:

const handleSizeSort = (currentBrand, dragEvent) => {
  dragging2.value = false
  // 这里直接就能拿到当前操作的品牌id、name
  console.log('当前修改的品牌:', currentBrand.id, currentBrand.name)
  // currentBrand.content就是排序后的尺码列表,直接做后续逻辑即可
}

方案2:抽离内层组件(适合复杂业务、嵌套层级≥3的场景)

如果后续拖拽逻辑会变复杂,可以把内层尺码拖拽区域抽成独立组件,通过props显式传入当前品牌对象,逻辑解耦更易维护:

  1. 新建SizeDraggable.vue组件:
<template>
  <draggable 
    :list="currentBrand.content" 
    :disabled="!enabled2"
    item-key="size-class" 
    class="list-group" 
    ghost-class="ghost" 
    v-bind="dragOptions" 
    handle=".handle"
    :group="{ name: 'size-class'+currentBrand.name}" 
    @start="dragging2 = true" 
    @end="handleDragEnd">
    <template #item="{ element: sizeItem, index: sizeIndex }">
      <div class="list-group-item size-classes-bar" :class="{'not-draggable' : !enabled2}">
        <div class="row handle drag-object">
          所属品牌: {{ currentBrand.name }} ,尺码ID: {{ sizeItem.id }} , 尺码名: {{ sizeItem.name }}
          <!-- 省略其他原有结构 -->
        </div>
      </div>
    </template>
  </draggable>
</template>
<script setup>
const props = defineProps({
  currentBrand: {
    type: Object,
    required: true
  }
})
const handleDragEnd = () => {
  dragging2.value = false
  // 直接通过props.currentBrand访问父级品牌属性
  console.log('当前操作品牌:', props.currentBrand.name)
}
</script>
  1. 外层直接引入组件传值即可:
<template #item="{ element: brandItem }">
  <!-- 省略其他原有结构 -->
  <SizeDraggable :current-brand="brandItem" />
</template>

内容的提问来源于stack exchange,提问作者Wong Yat Cheong Jacky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:24:23