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

Vue3使用vue-draggable拖拽排序时出现空值读取错误

Vue3中vue-draggable拖动排序异常及TypeError问题解决

拖动组件调整顺序时无法正常切换,同时抛出以下错误:

  • Uncaught TypeError: Cannot read properties of null (reading "element")
  • Uncaught TypeError: Cannot read properties of null (reading "index")

相关代码如下:

模板部分:

<draggable v-model="modules" item-key="id" handle=".module-handle" animation="200">
    <template #item="{ element }">
        <component
             v-if="element && registry[element.type]"
             :is="registry[element.type]"
             v-bind="element.props"
             :uid="uid"
             :edit="profileEdit"
        />
    </template>
</draggable>

脚本部分:

const registry = {
   bio: defineAsyncComponent(() => import('./components/Biography.vue')),
   media: defineAsyncComponent(() => import('./components/Media.vue')),
   links: defineAsyncComponent(() => import('./components/Links.vue')),
   music: defineAsyncComponent(() => import('./components/Music.vue'))
}
const modules = ref([
   { id: 1, type: 'bio', props: {} },
   { id: 2, type: 'media', props: {} },
   { id: 3, type: 'links', props: {} },
   { id: 4, type: 'music', props: {} }
]);

问题原因

拖动过程中,vue-draggable会临时生成虚拟元素用于占位或过渡,此时element可能为null,或者registry[element.type]匹配失败,导致<component>被v-if销毁。DOM结构的突然破坏会让draggable组件无法读取到预期的元素和索引,从而抛出TypeError。

解决办法

方案1:用v-show替代v-if

v-show仅控制元素的显示/隐藏,不会销毁DOM,能保持draggable所需的DOM结构完整:

<draggable v-model="modules" item-key="id" handle=".module-handle" animation="200">
    <template #item="{ element }">
        <component
             v-show="element && registry[element.type]"
             :is="registry[element.type]"
             v-bind="element.props"
             :uid="uid"
             :edit="profileEdit"
        />
    </template>
</draggable>

方案2:将条件判断移至组件内部

确保<component>始终被渲染,把显示逻辑放到每个异步组件内部:

<draggable v-model="modules" item-key="id" handle=".module-handle" animation="200">
    <template #item="{ element }">
        <component
             :is="registry[element.type] || 'div'"
             v-bind="element.props"
             :uid="uid"
             :edit="profileEdit"
             :element="element"
        />
    </template>
</draggable>

以Biography.vue为例,内部添加显示控制:

<template>
  <div v-show="element?.type === 'bio'">
    <!-- 组件原有内容 -->
  </div>
</template>

<script setup>
const props = defineProps(['element'])
</script>

额外检查

确认item-key="id"对应的每个modules项的id值唯一且稳定,避免拖动过程中key值变化导致的DOM异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:21:20