如何在纯Javascript中实现取消功能?

7
我有一个页面,其中以表格形式显示数据。每个表格都有一列包含复选框,如果该复选框被选中,则用户可以通过 Javascript 修改特定行。这是通过其 td 封装了 input 或 select 实现的,并使它们可编辑。用户修改行并保存更改,目前为止没有问题。我的问题是如何实现取消操作?用户可以选择多行,即勾选框并进行修改,但用户也可以按取消按钮。在取消时,应显示原始值(并且行再次变为不可编辑)。但是,如何在 Javascript 中实现取消操作?我们是否在某些全局数据结构中存储数据?这在 Javascript 中将会是什么?

2
你想要“取消”(回滚)还是“停止”? - Sebas
啊,那么对我来说似乎很简单。我脑海中首先想到的是添加一个不可见的列,完全复制允许修改的列,并在取消时使用它将其值复制粘贴到可见列中。但实际上,这必须是干净的,所以我必须说这取决于您的表最初是如何被填充的。 - Sebas
2
我曾经这样做过。使用 data-original 属性生成输入,例如 <input type='text' value='hello' data-original='hello' />。如果用户随时点击还原,我会将 data-original 加载到 value 中。 - acdcjunior
@acdcjunior:data-original是什么? - Cratylus
@Cratylus 从数据库预加载的数据将是“默认”值。刷新页面将重新加载这些值。这只是一个想法。 - showdev
显示剩余14条评论
4个回答

1

好的,在您提供的信息添加后,我建议您设置以下机制:

function getDatas() {
var oXhr;

    //get datas from database:
    oXhr = new XMLHttpRequest();    
    oXhr.onreadystatechange = function() {
    if (oXhr.readyState == 4 && (oXhr.status == 200)) {
        g_oData = (new DOMParser()).parseFromString(oXhr.responseText, "text/xml");
        }
    }

    oXhr.open("POST", "yourphpscriptthatreturnsthexmldatas.php", true);
    oXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
    oXhr.send();
}

function populateGrid() {
    //use g_oData to populate your grid, but at first totally clean the body
    var mygrid = document.getElementById("mygridid");
    //mygrid.innerHtml = "<table><tr><td>...</td></tr></table>";

    //use the xml library to parse g_oData and fill up the table:
    var xmlRows = g_oData.getElementsByTagName("TAG");
    var xmlRow;
    iLen = xmlRows.length;
    for (var i=0;i<iLen;i++) {
    xmlRow = xmlRows[i];
    //use xmlRow->textContent to build each cell of your table
    }
}

function revertChange() {
    //on cancel, revert the changes by populating the grid. 
    //it will use the global xml/json object loaded directly from database, to refill everything.
    populateGrid();
}

我自己经常这样做来刷新页面中的一些数据。基本上你正在做的就是这个,只不过你没有向数据库请求任何内容,而是重新填充了字段。

  1. g_oData是什么类型的对象?
  2. mygrid是什么?类似于document.getElementById('table')吗?抱歉,我在前端方面工作得不多。
- Cratylus
g_oData是什么类型的对象? - Cratylus
如果您选择 XML,则将是一个 XmlDomDocument。如果您选择 JSON,则是一个 JSON 对象。无论您喜欢哪种方式,最重要的是它是全局的,并且保留在页面的私有内存中。 - Sebas
请你写一个声明的例子,可以吗? - Cratylus
@Cratylus 看看我的例子。此外,XML解析取决于您从PHP返回的内容。但我想象一下,您可以使用MySQL查询来返回类似于“<ROWS><ROW><COL></COL></ROW></ROWS>”的XML文本,甚至是已经设计好的HTML表格?这取决于您的喜好。 - Sebas
显示剩余2条评论

1
你可以使用 HTML5 data- 属性 来实现还原功能。这样,每个 <input> 在使用 revert 按钮时都会保留其原始值。
以下是实现方式:
<table>
  <tr>
     <td><input type='text' value='change me' data-original='change me' /></td>
     <td><input type='text' value='change me2' data-original='change me2' /></td>
     <td><input type='button' value='revert' onclick='revert(this)'/></td>
  </tr>
<table>

并且还有将代码恢复的方法:

function revert(btn) {
    var parentTr = btn.parentNode.parentNode;
    var inputs = parentTr.getElementsByTagName('input');
    for(var i = 0; i < inputs.length; i++) {
        if (inputs[i].type == 'text') {
            inputs[i].value = inputs[i].getAttribute('data-original');
        }
    }
}

data-original属性可以由以下两种方式生成:


作为一个副解决方案,您可以将原始值存储在map对象中在此处查看(3)演示 (请注意,我添加了每个id,以便将其用作map的键)。

请记住,这两种解决方案(2或3)都不需要更改服务器端代码(假设您的输入具有ID)。并且(2)感觉更清晰。

关于“defaultValue”属性:
只有当要还原的值从不改变且涉及的字段是文本“input”时,“defaultValue”属性才可能是一种解决方案。
首先,“默认值”的更改相当麻烦,可能会破坏页面上的其他内容(人们希望浏览器使“defaultValue”属性只读,但似乎并非如此)。其次,您将仅限于文本类型的“input”。
尽管如此,如果没有任何问题,上面的代码可以快速适应使用它们而不是“data-”属性。

1
它的工作原理如下:您可以将任何额外属性添加到HTML元素中。这是有效的,浏览器可以理解。唯一的缺点是这会使HTML代码无效(但是,它仍然可以工作)。警告是,如果这些属性具有"data-"前缀且验证器是HTML5,那么HTML仍将有效(如果没有该前缀,则HTML5无效)。 - acdcjunior
1
@Cratylus:不行。但是,无论您将DOCTYPE设置为什么,仍然可以使用JavaScript与数据属性进行交互。如果您通过HTML验证器运行代码,它会抱怨无效的标记。因此,如果您不关心标记验证,可以使用此解决方案。 - Alan
1
你为什么需要一个数据属性?你从来没有听说过 defaultValue 属性吗? - Bergi
2
@Bergi: 这只适用于“input”文本吗? - Cratylus
1
@Bergi 你说得对,在示例代码的上下文中(其中值是内联设置的),它没有意义。但是数据属性有帮助的情况(我不确定这是否是OP的情况)是在通过AJAX进行字段更新时。在这种情况下,使用 defaultValue 无法编辑字段,保存它,然后重新编辑并恢复正确的值。所以你要做的就是每次保存值时设置 data-original,然后使用它。 - Ben Regenspan
显示剩余11条评论

1
这里有一个相当简单的方法:
不要用表单元素替换单元格内容。在显示表单元素时,将值(文本)保存在元素中并将其隐藏。然后,如果要取消操作,只需再次显示,并隐藏或删除表单元素即可。仅在用户想要保存值时更新
这是一个例子。所有的显示和隐藏都是通过CSS完成的。
<tr>
    <td>
        <span>value</span>
        <input type='text' value='' />
    </td>
    <td>
       <button class="save">Save</button>
       <button class="revert">Revert</button>
    </td>
</tr>

JS:

var rows = document.querySelectorAll('table tr');

for(var i = 0, l = rows.length; i < l; i++) {
    rows[i].addEventListener('click', function(event) {
        // all value display elements in the row
        var spans = this.querySelectorAll('span');
        // all form elements in the row
        var inputs = this.querySelectorAll('input');

        // handle click on save button
        if (event.target.className === 'save') {
            [].forEach.call(inputs, function(input, i) {
                spans[i].innerHTML = input.value;
            });
            this.className = '';
        }
        // handle click on revert button
        else if (event.target.className === 'revert') {
             // not much to do
             this.className = '';
        }
        else {
            // update form element values
            [].forEach.call(inputs, function(input, i) {
                input.value = spans[i].innerHTML;
            });
             this.className = 'edit';
        }
    });
}

演示


+1. 我想我理解你所描述的内容了,但是我不理解这段代码。 - Cratylus
这只是一个例子,以便我能够展示一些实际可行的东西 ;) - Felix Kling
能否简单地在纯JS中提供一个小部分作为提示,以便理解正在发生的事情? - Cratylus
没问题,请给我一些时间。虽然这将与HTML结构非常紧密相关。 - Felix Kling
结果证明,实际上并不太依赖它。但是为了方便起见,我使用了一些现代函数(querySelectorAllforEach)。我也更新了演示文稿。 - Felix Kling

1
你只需访问输入框的原始 value 属性即可获取 defaultValue。示例实现如下:
$("table").on("dblclick", "td", function(e) {
    var val = $(this).html();
    $(this).empty().append($("<form/>").append(
        $("<input/>", {type:"text"}).attr("value", val),
        //                           ^^^^
        // set the *attribute*, as if it was present in the parsed HTML
        $("<button/>", {type:"reset"}).text("Reset"),
        $("<button/>", {type:"button", class:"cancel"}).text("Cancel"),
        $("<button/>", {type:"submit"}).text("Submit")
    ));
}).on("submit", "form", function(e) {
    var val = $(this).find("input:text").val();
    //                                   ^^^^^
    // which is equivalent to .prop("value")

    /* then do something with val, e.g. send it to server via ajax */
    $(this).parent().html(val);
    e.preventDefault();
}).on("click", "button.cancel", function(e) {
    var $form = $(this).parent(),
        $input = $form.find("input:text"),
        oldval = $input.attr("value");
    //                  ^^^^^^^^^^^^^
    // or .prop("defaultValue"), but not .val()!
    if (oldval == $input.val() || confirm("Do you really want to discard your changes?"))
        $(this).parent().html(oldval);
    e.preventDefault();
});

(jsfiddle.net上的演示)

一个更简单的解决方案可能是使用dblclick处理程序作为闭包创建表单,并将原始html存储在本地变量中。


你在代码中哪里使用了 defaultValue?这对于其他类型的元素是否有效?比如 selectcheckbox - Cratylus
获取 value 属性等同于获取 defaultValue 属性。对于复选框,有 defaultChecked(或者只是 checked 属性);对于下拉列表,选项具有 defaultSelected 属性和它们的 selected 属性。 - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接