通过纯 JS 将 HTML 表单从一个位置移动到另一个位置(并返回)



我是一个服务器端开发人员(主要是Pythong/Django),但现在正在学习纯Javascript。这些概念对我来说相对较新,所以需要帮助。

想象一个 Web 应用程序,用户可以在其中发布内容(文本或图像)。所有帖子都以长列表的形式显示在单个页面上。在每个帖子下方,都有一个reply按钮。按下它会动态创建(通过 JS)一个用于回复所述帖子的表单字段。

还有一个额外的要求。

再次按下相同的reply按钮应该会消失之前创建的表单。实质上,reply按钮打开和关闭表单。

此外,如果页面中的任何其他帖子也有表单,那也应该消失。

我已经能够完成上述所有操作,但是一旦表单"打开"(在同一位置),我需要帮助关闭表单。这是我的问题。


目前,在页面加载时,我将代码表单的代码停放在 HTML 页面的顶部,放在带有display:nonediv内。

每当在帖子下方按下reply按钮时,我都会将此表单移动到同一帖子下。如果此后按下完全不同的reply按钮,窗体将再次移动到该新位置。

就像我说的,我似乎不能做的一件事是在重复按下相同的回复按钮时打开和关闭表单。

理想情况下,我不想改变我正在使用的策略(它对我来说效果很好),但会出于效率原因改变它(对我来说是一大优势)。其次,我正在寻找纯JS解决方案。JQuery 在我的雷达上,但我想先了解 JS,因此有这个要求。


我的JS代码目前是:

var formTemplate = document.querySelector('#form-template form');
function createInput(payload, id) {
// populating input fields with correct values
var input = document.createElement('input');
input.setAttribute('id',id);
input.setAttribute('type','hidden');
input.setAttribute('value',payload);    
return(input);
}
function toggleReply(e) {
if (!formTemplate) return;
// prevent form submission
e.preventDefault();
// moving 'ghost form' into position
e.target.parentNode.insertAdjacentElement('afterend', formTemplate);
// getting pertinent values from "reply" button
var payload = e.target.parentNode.querySelector('#payload').value;
payload = payload.split(':');
var tt = payload[5];
var bid = payload[0];
var idx = payload[3];
// assigning populated input fields to form 
formTemplate.appendChild(createInput(tt, 'tt'));
formTemplate.appendChild(createInput(bid, 'bid'));
formTemplate.appendChild(createInput(idx, 'idx'));
}
};
Array.from(document.querySelectorAll('button.rep'))
.forEach(btn => btn.onclick = toggleReply)

停放在 HTML 文档开头的表单如下所示:

<div id="form-template" style="display: none;">
<form action="{% url 'reply_to_post' %}" id="rep-form" method="POST" style="display:inline" enctype="multipart/form-data">
{% csrf_token %}
<div style="width:75%;display:inline-block;">
{{ personal_group_form.reply }}
</div>
<div style="width:22%;display:inline-block;float:right;text-align:center;">
{{ personal_group_form.image }}
<label for="browse_image_btn" style="cursor: pointer;"><img src="{{ STATIC_URL }}img/cam1.svg" width="70" height="70" /></label>
</div>
<button style="border:none;height:30px;" name="tid" value="{{ tid }}" type="submit">OK</button>
</form>
</div>

忽略{%{{类型语法。那是姜戈。

最后,每个内容帖子下的回复按钮布局如下:

<form action="{% url 'post_buttons' %}" method="POST" style="display:inline">
{% csrf_token %}
<input id="payload" type="hidden" name="pl" value="{{ blob_id }}:{{ username }}:{{ score }}:{{ idx }}:{{ t }}:{{ tt }}:{{ tid }}:{{ img_width }}:{{ their_nick }}:{{ own_nick }}:{{ is_res }}:{{ av_url }}">
<button type="submit" class="rep" name="dec" value="1">reply</button>
<button type="submit" name="dec" value="2">save</button>
<button type="submit" name="dec" value="3">hide</button>
</form>

最后,我尝试调整我之前发布的 JS 代码,如下所示,但它没有给我正确的结果:

var formTemplate = document.querySelector('#form-template form');
function createInput(name, payload, id) {
// populating input fields with correct values
var input = document.createElement('input');
input.setAttribute('id',id);
input.setAttribute('type','hidden');
input.setAttribute('name',name);    
input.setAttribute('value',payload);    
return(input);
}
function toggleReply(e) {
// error-handling the case where there is no ghost form
if (!formTemplate) return;
// prevent form submission
e.preventDefault();
// first check if reply form was already added under reply button
var to_remove = e.target.parentNode.nextSibling.querySelector("#rep-form");
if (to_remove != null) {
// move form back to being a ghost (it was already added under the reply button)
document.querySelector('#form-template').insertAdjacentElement('afterbegin',formTemplate);
} else {
// moving ghost form into position
e.target.parentNode.insertAdjacentElement('afterend', formTemplate);
// getting value from "reply" button
var payload = e.target.parentNode.querySelector('#payload').value;
payload = payload.split(':');
var tt = payload[5];
var bid = payload[0];
var idx = payload[3];
// assigning populated input fields to formTemplate 
formTemplate.appendChild(createInput('', tt, 'tt'));
formTemplate.appendChild(createInput('', bid, 'bid'));
formTemplate.appendChild(createInput('', idx, 'idx'));
}
};
Array.from(document.querySelectorAll('button.rep'))
.forEach(btn => btn.onclick = toggleReply)

我得到TypeError: e.target.parentNode.nextSibling.querySelector is not a function.更改为e.target.parentNode.nextSibling.getElementById()也不起作用。事实上,即使只是打印e.target.parentNode.nextSibling的值也会产生错误的结果。请指教。

移动这个表单会使事情变得复杂。为什么不给每个帖子自己的形式,然后用display切换它们?

var form = e.target.parentNode.querySelector('form');
form.style.display = form.style.display === 'none' ? 'block' : 'none';

通过纯JS操作DOM元素并非易事。我最终手动处理了无数的边缘情况,代码是:

var formTemplate = document.querySelector('#form-template');
function createInput(name, payload) {
// populating input fields with correct values
var input = document.createElement('input');
input.setAttribute('type','hidden');
input.setAttribute('id',name);
input.setAttribute('name',name);    
input.setAttribute('value',payload);    
return(input);
}
function removeInputFields() {
// remove unneeded input fields
child1 = document.getElementById('tt');
child2 = document.getElementById('bid');
child3 = document.getElementById('idx');
if (child1 != null) { formTemplate.removeChild(child1); }
if (child2 != null) { formTemplate.removeChild(child2); }
if (child3 != null) { formTemplate.removeChild(child3); }
}
function appendInputFields(payload) {
// getting value from "reply" button
payload = payload.split(':');
var tt = payload[5];
var bid = payload[0];
var idx = payload[3];
// assigning populated input fields to formTemplate 
formTemplate.appendChild(createInput('tt', tt));
formTemplate.appendChild(createInput('bid', bid));
formTemplate.appendChild(createInput('idx', idx));
}
function toggleReply(e) {
// error-handling the case where there is no ghost form
if (!formTemplate) return;
// prevent form submission
e.preventDefault();
// first check if reply form was already added under reply button
var to_remove = this.parentNode.nextElementSibling;
console.log(to_remove);
if (to_remove == null) {
// make the form visible
formTemplate.style.display = 'inline';
// remove unneeded input fields
removeInputFields();
// moving ghost form into position
e.target.parentNode.insertAdjacentElement('afterend', formTemplate);
// creating and appending desired input fields in formTemplate
appendInputFields(e.target.parentNode.querySelector('#payload').value);
}
if (to_remove != null && to_remove.id == 'form-template') {
console.log(formTemplate.style.display);
// toggle form visibility
if ( formTemplate.style.display == 'inline' ) { 
formTemplate.style.display = 'none';
// remove unneeded input fields
removeInputFields();
}
else {
formTemplate.style.display = 'inline';
// remove unneeded input fields
removeInputFields();
// moving ghost form into position
e.target.parentNode.insertAdjacentElement('afterend', formTemplate);
// creating and appending desired input fields in formTemplate
appendInputFields(e.target.parentNode.querySelector('#payload').value);
}

} else {
// make the form visible
formTemplate.style.display = 'inline';
// remove unneeded input fields
removeInputFields();
// moving ghost form into position
e.target.parentNode.insertAdjacentElement('afterend', formTemplate);
// creating and appending desired input fields in formTemplate
appendInputFields(e.target.parentNode.querySelector('#payload').value);
}
};
Array.from(document.querySelectorAll('button.rep'))
.forEach(btn => btn.onclick = toggleReply)

它又丑又长,但可以完成工作。希望这里有优化的空间。

相关内容