首页 > 解决方案 > 如何使用 JavaScript 为表中的行创建重新排序功能

问题描述

我目前正在重构一个使用 Python 小部件和 JavaScript 的项目。它目前使用的表格具有重新排序功能,可以进行一些重大改进。使用“reorderRowDown”按钮时,它可以正常工作,当前行向下移动,上一行和下一行相应调整。

但是,在“reorderRowUp”按钮上,当前行只是在当前行和上一行之间来回交替。(我希望我能很好地解释这一点,我很抱歉)将当前行向上移动非常笨拙。

我想实现类似于“reorderRowDown”的功能,当单击“reorderRowUp”时,当前行向上移动,上一行和下一行相应地调整。总之,我想知道如何以正确的方式对表中的行进行重新排序。任何帮助将不胜感激。

(这里是下面发布的 GIF,以更好地展示我所引用的场景)

reorderRowDown 示例:

https://media.giphy.com/media/8WHiGw57pPTK9Zdibk/giphy.gif

reorderRowUp 示例:

https://media.giphy.com/media/Wp7x9GtYDX29cFLT6I/giphy.gif

这是我的代码(如果您需要更多,请告诉我)

PathContext.js

'use strict';

module.exports = () => {
  window.reorderRowUp = function(ruleSetIdPriority) {
    let ruleSetId;

    ruleSetId = ruleSetIdPriority.split('-priority')[0];

    const row = document.getElementById(ruleSetId);
    const table = row.parentNode;
    const prevRow = row.previousElementSibling;

    table.insertBefore(row, prevRow);
  };

  window.reorderRowDown = function(ruleSetIdPriority) {
    let ruleSetId;

    ruleSetId = ruleSetIdPriority.split('-priority')[0];

    const row = document.getElementById(ruleSetId);
    const table = row.parentNode;
    const nextRow = row.nextElementSibling;

    table.insertBefore(nextRow, row);
  };
};

reorder_row_widget.html

<button class="reorder-btn" type="button" onclick=reorderRowUp("{{widget.name}}")>Up</button>
<button class="reorder-btn" type="button" onclick=reorderRowDown("{{widget.name}}")>Down</button>
<input id="{{ widget.name }}" type="hidden" name="{{ widget.name }}" value="{{ widget.value }}"></input>

这是我浏览器控制台中实际表格行的 html

<table>
    <tbody>
       <tr class="form-row row1 has_original dynamic-rule_set" id="rule_set-0">
            <td class="original">
            <p>
            Rule object (84)
            </p>
                <input type="hidden" name="rule_set-0-id" value="84" id="id_rule_set-0-id">
                <input type="hidden" name="rule_set-0-path_context" value="6" id="id_rule_set-0-path_context">
            </td>
            <td class="field-priority">   
                <button class="reorder-btn" type="button" onclick="reorderRowUp(&quot;rule_set-0-priority&quot;)">Up</button>
                <button class="reorder-btn" type="button" onclick="reorderRowDown(&quot;rule_set-0-priority&quot;)">Down</button>
                <input id="rule_set-0-priority" type="hidden" name="rule_set-0-priority" value="-301">
            </td>
            <td class="field-pattern"> 
                <input type="text" name="rule_set-0-pattern" value="^/$" id="id_rule_set-0-pattern"> 
            </td> 
            <td class="field-value">     
                <input class="tgl" id="rule_set-0-value" name="rule_set-0-value" type="checkbox" checked="">
                <label class="tgl-btn" for="rule_set-0-value"></label>
            </td> 
            <td class="field-experience">
                <select name="rule_set-0-experience" id="id_rule_set-0-experience">
                    <option value="">---------</option>
                    <option value="modal" selected="">Modal</option>
                    <option value="sticky_cta">Sticky CTA</option>
                </select>
            </td>
            <td class="delete"><input type="checkbox" name="rule_set-0-DELETE" id="id_rule_set-0-DELETE"></td>  
       </tr>     
    </tbody>
  </table>

admin.py(如果需要,python 代码)

class ReorderRowWidget(forms.Widget):
    template_name = 'admin/reorder_row_widget.html'

    def get_context(self, name, value, attrs=None):
        return {'widget': {
            'name': name,
            'value': value,
        }}

    def render(self, name, value, attrs=None, renderer=None):
        context = self.get_context(name, value, attrs)
        template = loader.get_template(self.template_name).render(context)
        return mark_safe(template)

标签: javascriptpython

解决方案


这是我用来解决我的问题并创建更好的 UI 的实现。我重构了 PathContext.js 文件。

  function replaceReorderFunction() {
    const reorderRowUp = window.reorderRowUp || function() {};
    const reorderRowDown = window.reorderRowDown || function() {};
    // when page gets rendered, django creates a hidden row with a special ruleSetId with id __prefix__
    // once 'add new row' is clicked, a real ruleSetId is given to the row
    // need to replace the reorder function of that row so that it uses the proper ruleSetId so the row can be reordered properly
    // should only need to happen once, on the first reordering after the row is added
    // therefore I assume that the row in question is always at the bottom of the table
    const tableWrapper = document.getElementById('rule_set-group');
    const tbody = tableWrapper.querySelector('tbody');
    const rowToUpdate = tbody.lastElementChild.previousElementSibling.previousElementSibling;
    const priorityField = rowToUpdate.getElementsByClassName('field-priority')[0];
    const buttons = priorityField.getElementsByTagName('button');
    buttons[0].onclick = () => {reorderRowUp(rowToUpdate.id);};
    buttons[1].onclick = () => {reorderRowDown(rowToUpdate.id);};
    return rowToUpdate.id;
  }

  window.reorderRowUp = function(ruleSetIdPriority) {
    let ruleSetId;
    // it's a new row, ruleSetId is not correct
    if (ruleSetIdPriority.match(/__prefix__/)) {
      // get the proper ruleSetId and replace existing onclick functions
      ruleSetId = replaceReorderFunction();
    } else {
      ruleSetId = ruleSetIdPriority.split('-priority')[0];
    }
    const row = document.getElementById(ruleSetId);
    const table = row.parentNode;
    const prevRow = row.previousElementSibling;
    if (!prevRow) {
      return;
    }
    table.insertBefore(row, prevRow);
    // swap priority values
    const prevPriorityValue = getPriorityValueFromRow(prevRow);
    const curPriorityValue = getPriorityValueFromRow(row);
    setPriorityValueOfRow(row, prevPriorityValue);
    setPriorityValueOfRow(prevRow, curPriorityValue);
  };

  window.reorderRowDown = function(ruleSetIdPriority) {
    let ruleSetId;
    // it's a new row, ruleSetId is not correct
    if (ruleSetIdPriority.match(/__prefix__/)) {
      ruleSetId = replaceReorderFunction();
    } else {
      ruleSetId = ruleSetIdPriority.split('-priority')[0];
    }
    const row = document.getElementById(ruleSetId);
    const table = row.parentNode;
    const nextRow = row.nextElementSibling;
    if (!nextRow || nextRow.className === 'add-row' || nextRow.id.includes('empty')) {
      return;
    }
    table.insertBefore(nextRow, row);
    // swap priority values
    const nextPriorityValue = getPriorityValueFromRow(nextRow);
    const curPriorityValue = getPriorityValueFromRow(row);
    setPriorityValueOfRow(row, nextPriorityValue);
    setPriorityValueOfRow(nextRow, curPriorityValue);
  };

推荐阅读