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

Meteor集成Dragula问题:无法渲染数据库数据生成的可拖拽div容器

解决Meteor + Dragula动态列表拖拽问题

看起来你现在的核心问题有几个:一是在helper里操作DOM的时机不对(helper执行时列表的DOM元素还没渲染出来),二是把字符串(列表名称)当成DOM元素传给了Dragula,三是模板没有正确渲染出数据库里的列表和任务。咱们一步步来修正:

问题根源拆解

  1. 你在lists模板的mount helper里初始化Dragula,但helper的核心作用是提供数据给模板渲染,这时候列表的DOM元素还未生成,document.getElementById根本找不到目标元素;而且你把listName(字符串)直接push到drake.containers,Dragula需要的是DOM元素对象,不是字符串。
  2. lists模板里没有循环渲染数据库的列表,只是调用了{{mount}},导致页面上根本没生成对应列表的div容器,自然没有可拖拽的元素。
  3. 代码里有个语法错误:element.[i].nome应该改成element[i].nome(多了一个不必要的点)。

修正后的完整实现

1. 修正模板结构(main.html)

首先让lists模板循环渲染出每个列表容器,以及对应容器里的任务卡片:

<head>
  <title>Dragula test</title>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
</head>
<body>
  <h1>Welcome to Meteor!</h1>
  <h1>Draglist</h1>
  {{> dragList}}
  <br>
  <h1>Lists</h1>
  {{> lists}}
  <br>
</body>

<template name="dragList">
  <h5 class="card-title">Container 1</h5>
  <div id="left1">
    <p class="card-text">This is a draggable p</p>
    <button class="btn btn-primary">First draggable button</button>
    <button class="btn btn-primary">Second draggable button</button>
  </div>
  <h5 class="card-title">Container 2</h5>
  <div id="right1">
    <p class="card-text">This is another draggable p</p>
    <button class="btn btn-primary">Third draggable button</button>
    <button class="btn btn-primary">Fourth draggable button</button>
  </div>
</template>

<template name="lists">
  <div class="lists-container" style="display: flex; gap: 20px; padding: 10px;">
    <!-- 循环渲染每个列表容器 -->
    {{#each list in list}}
      <div class="list-container" id="{{list.nome}}" style="width: 250px; background: #ebecf0; padding: 10px; border-radius: 4px;">
        <h3 style="margin-top: 0;">{{list.nome}}</h3>
        <!-- 循环渲染当前列表下的任务(假设Tarefas有listNome字段关联列表) -->
        {{#each task in getTasksForList list.nome}}
          <div class="task-card" data-task-id="{{task._id}}" style="background: white; padding: 8px; margin: 8px 0; border-radius: 4px; cursor: move; box-shadow: 0 1px 0 rgba(9,30,66,.25);">
            {{task.descricao}} <!-- 假设任务有descricao字段存储内容 -->
          </div>
        {{/each}}
      </div>
    {{/each}}
  </div>
</template>

2. 修正JavaScript逻辑(main.js)

把Dragula的初始化移到lists模板的onRendered钩子(模板渲染完成后执行,此时DOM已存在),同时让helper只负责提供数据:

import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import dragula from 'dragula';
import '../node_modules/dragula/dist/dragula.css';
import './main.html';

Listas = new Mongo.Collection('listas');
Tarefas = new Mongo.Collection('tarefas');

console.log("Before enter drag");

Template.dragList.onRendered(function(){
 console.log("entrou no onRendered");
 dragula([document.querySelector('#left1'), document.querySelector('#right1')]);
});

Template.lists.helpers({
  // 返回所有列表数据
  'list': function(){
    return Listas.find({});
  },
  // 根据列表名称返回对应的任务(确保Tarefas有listNome字段关联列表)
  'getTasksForList': function(listNome){
    return Tarefas.find({ listNome: listNome });
  },
});

Template.lists.onRendered(function(){
  console.log("初始化动态拖拽容器");
  // 获取所有列表容器的DOM元素
  const containers = Array.from(this.findAll('.list-container'));
  // 初始化Dragula,支持容器内部和容器之间拖拽
  const drake = dragula(containers, {
    copy: false, // false是移动任务,true是复制任务
    revertOnSpill: true, // 拖拽到容器外会放回原位置
    removeOnSpill: false // 拖拽到容器外不会删除任务
  });

  // 监听拖拽结束事件,同步更新数据库中任务的归属列表
  drake.on('drop', function(el, target, source, sibling){
    // 获取任务的新归属列表名称
    const newListNome = target.id;
    // 获取任务ID(从任务卡片的data属性中获取)
    const taskId = el.getAttribute('data-task-id');
    // 更新数据库里任务的归属列表
    Tarefas.update(taskId, { $set: { listNome: newListNome } });
  });

  console.log("dragula实例:", drake);
});

关键修正点说明

  • 模板优先渲染:通过{{#each}}把数据库的列表和任务渲染成真实DOM元素,每个列表容器有唯一id,任务卡片明确归属到对应列表。
  • DOM操作时机正确:把Dragula初始化放在onRendered钩子,此时模板已经渲染完成,能准确获取到所有列表容器的DOM元素。
  • 传递正确的容器类型:传给Dragula的是DOM元素数组,而非字符串,确保Dragula能识别可拖拽的容器和元素。
  • 数据与视图同步:通过drake.on('drop')监听拖拽结束事件,将任务的新归属列表更新到数据库,实现拖拽操作后数据的持久化。

额外提示

  • 建议用列表的_id而非nome作为容器id和关联字段,避免列表名称重复导致的冲突。
  • 可以根据需求调整Dragula的配置项,比如开启copy实现复制拖拽,或者自定义拖拽时的样式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:57:36