我正在尝试实现看板应用程序(待办事项应用程序)在Flask和HTML。我可以添加任务,它们显示在各自的列(To-Do,In Progress,Done),我可以改变任务的状态,这会将它们移动到相应的列中。现在,我正在尝试使任务可拖动,并根据它们被放入的相应列来改变它们的状态,那时我不得不开始使用JavaScript来实现HTML的拖放API的事件处理程序。
在应用程序的Jinja模板中,我为拖放API定义了事件侦听器:
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function dragEnter(ev) {
ev.preventDefault();
$(this).addClass('zoomed');
}
function drag(ev) {
ev.dataTransfer.setData("task_id", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var task_id = ev.dataTransfer.getData("task_id");
var targe_state = ev.target.id;
{{ dropped(project_id=project.id, task_id=task_id, target_state=target_state) }}
}
</script>
字符串
实际的逻辑发生在对dropped
的调用中,dropped
是传递给Jinja模板的Python函数:
def dropped(project_id, task_id, target_state):
project_id = int(project_id)
task_id = int(task_id)
if Project.query.get(project_id) is None:
return render_template("404.html"), 404
try:
session = sessions_by_project[project_id]
except KeyError:
return render_template("404.html"), 404
task = session.query(Task).get(int(task_id))
if task is None:
return render_template("404.html"), 404
task.change_status(str2status(target_state))
session.commit()
print(f"Dropped called with target ID: {task_id}, state: {target_state}")
return redirect(url_for("main.kanban", project_id=project_id))
@main.route("/<int:project_id>/kanban", methods=["GET", "POST"])
def kanban(project_id):
# ...more code ommited...
return render_template(
"kanban.html", tasks_by_status=tasks_by_status, project=project, dropped=dropped
)
型
Jinja模板中设置事件处理程序的部分是(还有两个基本相同的“In Progress”和“Done”有序列表,所以我省略了它们):
<ol class="kanban To-do" id="todo" ondrop="drop(event)" ondragover="allowDrop(event)" ondragenter="dragEnter(event)">
<h2> To-Do </h2>
{% for (depth, pending) in tasks_by_status[1]%}
<li class="dd-item indent{{depth}}" id="{{pending.id}}" draggable="true" ondragstart="drag(event)">
<h3 class="title dd-handle"><button name="task" value={{pending.id}}>{{pending.title}}</button></h3>
<div class="text" contenteditable="true">{{pending.description}}</div>
</li>
{% endfor%}
</ol>
型
所以从我在测试和尝试过程中看到的:
- 我可以拖动标有
draggable=true
的列表项 - 当我将可拖动项移动到有序列表元素上时,什么也没有发生,尽管应该调用
drageEnter
并使元素看起来稍微大一点 - 同样,当我在有序列表元素上放置一些东西时,
- 当我使用硬编码的值来调用
dropped(1,1,"pending")
时,我可以看到函数在页面加载时打印到控制台,而不是在触发drop事件时打印。 - 经过更多的调查,似乎 dropzone 事件处理程序(ondragenter,ondragnet,ondragleave,ondrop)在应该触发事件时没有被调用,而
ondragstart
和ondragend
事件处理程序确实工作=>难道有序列表不能用作 * dropzone *?
我也试着不把dropped
函数传递给模板,而是把它添加到flask上下文处理器,这也没有帮助。希望有人知道发生了什么,我在哪里犯了错误-我希望这不是太傻。非常感谢,谢谢!
1条答案
按热度按时间jexiocij1#
就像Qori说的,每当页面加载时,传递给jinja模板的函数就会被调用,结果会被放入模板中以生成显示的HTML页面。因此,为了在后端站点上使用正确的参数调用函数,我需要通过fetch API发送数据.:
字符串
然后处理它:
型
为了查看数据库的更改,必须重新加载页面,这发生在通过
then
传递给fetch API的回调中。此外,为了在正确的元素上执行回调,在我的例子中是有序列表元素,而不是任何子元素,我需要通过以下方式将元素传递给回调:
型
另一个问题是,当鼠标悬停在子元素上时,
ondragleave
和ondragenter
也会被调用。我遵循了here的建议,并为ondragenter
和ondragleave
回调函数植入了一个计数器:型
现在一切都按照预期工作了:我可以将
list items
拖到其中一个ordered lists
上,并获得所需的突出显示效果,当悬停子元素时不会 Flink 。此外,正确的ID(task_id
,target_state
)通过fetch API发送到后端,对数据库进行更改,页面重新加载,我可以看到更改。