简体   繁体   English

如何在 JavaScript 中实现“添加新项目”功能?

[英]How to implement "add new item" functionality in JavaScript?

The title isn't very descriptive but I couldn't find a better one.标题不是很描述,但我找不到更好的。 Feel free to edit it.随意编辑它。

Basically what I'm looking for is the best way to do the following:基本上我正在寻找的是执行以下操作的最佳方法:

添加新项目

When the user clicks "Add New Item", a new row is added with an indentical text box and drop down as above.当用户单击“添加新项目”时,将添加一个带有相同文本框和下拉列表的新行,如上所示。 The options I can think of are the following:我能想到的选项如下:

  • Hardcode the HTML in the JavaScript code.在 JavaScript 代码中硬编码 HTML。 This is obviously a hideously ugly solution.这显然是一个非常丑陋的解决方案。
  • Assemble the HTML from DOM nodes (or jQuery objects).从 DOM 节点(或 jQuery 对象)组装 HTML。 This is very ugly too.这也太丑了。
  • Use a client-side template system.使用客户端模板系统。 I used one of those once and it was pretty weird (it used <script language="html"> tags to define the templates).我曾经使用过其中一个,它非常奇怪(它使用<script language="html">标签来定义模板)。
  • Make an ad-hoc client-side "template" and hide it somehow with CSS.制作一个特别的客户端“模板”并用 CSS 以某种方式隐藏它。
  • Make an AJAX request to fetch the HTML.发出 AJAX 请求以获取 HTML。 This is slow and uses server resources unnecessarily.这很慢并且会不必要地使用服务器资源。

What do you suggest?你有什么建议? I'm not completely satisfied with any of the above solutions.我对上述任何解决方案都不完全满意。

If you're already using a framework like jquery or sencha on your page, you might as well make use of it.如果您已经在您的页面上使用了 jquery 或 sencha 等框架,那么您不妨使用它。

Otherwise, i'd keep it as simple as possible.否则,我会尽可能简单。 This does't look like a very important core functionality, so don't create something that requires extra https requests or even entire libraries to be loaded.这看起来不是一个非常重要的核心功能,所以不要创建需要额外 https 请求甚至整个库才能加载的东西。 Cloning or generating the html might not look elegant, but it'll be:克隆或生成 html 可能看起来不优雅,但它会是:

  • fast to implement快速实施
  • easy to read, and therefore easy to debug易于阅读,因此易于调试
  • waste few resources, and extremely fast浪费很少的资源,而且速度极快
  • stable稳定的
  • doesn't need server side code or extra http requests不需要服务器端代码或额外的 http 请求
  • it'll be easy to change the implementation later on if needed如果需要,稍后可以轻松更改实现

Don't create something that's overkill for somerhing as trivial as this.不要为像这样微不足道的事情创造一些矫枉过正的东西。

Assuming the super-simple approach and that your format is in a table:假设超级简单的方法并且您的格式在表格中:

<table>
    <tr>
        <td><input type="text" name="item_name" placeholder="item name" /></td>
        <td><select name="item_type"><option value="" selected="selected">Type</option></select></td>
    </tr>
    <tr>
        <td><input type="text" name="item_name" placeholder="item name" /></td>
        <td><select name="item_type"><option value="" selected="selected">Type</option></select></td>
    </tr>
    <tr>
        <td colspan="2" id="add">+ Add new item</td>
    </tr>
</table>

You can use the following:您可以使用以下内容:

$('#add').on('click',function(e){
    var $this = $(this);
    var $newRow = $this.closest('table').find('tr:first').clone();
    $newRow.find(':input').val('');
    $newRow.insertBefore($this.parent());
});

Broken down:分解:

  1. We give the last item an ID to make it easier to bind a click event to.我们给最后一个项目一个 ID,以便更容易绑定点击事件。
  2. Use jQuery and bind the click event to that ID which:使用 jQuery 并将点击事件绑定到该 ID,其中:
    • Grabs the current table we're clicking within ( $this.closest('table') ) $this.closest('table')我们正在点击的当前表格( $this.closest('table')
    • Locates the first row within that table and duplicates it ( .clone() )定位该表中的第一行并复制它( .clone()
    • Remove any populated values that may be present ( .find(':input').val('') )删除任何可能存在的填充值( .find(':input').val('')
    • Append this new cloned row to the table just above the "add new item" row ( $newRow.insertBefore(...) )将此新克隆的行附加到“添加新项目”行上方的表中( $newRow.insertBefore(...)

You can also take the template approach, but that's really up to you and how much control you'd like over the output.您也可以采用模板方法,但这实际上取决于您以及您希望对输出进行多少控制。

While I realise you already have an accepted answer, I thought I'd offer a plain JavaScript means of achieving the same:虽然我意识到你已经有了一个公认的答案,但我想我会提供一种简单的 JavaScript 方法来实现相同的目标:

function closest(el, tag) {
    if (!el || !tag) {
        return false;
    }
    else {
        var curTag = el.tagName.toLowerCase();
        return curTag == tag.toLowerCase() && curTag !== 'body' ? el : closest(el.parentNode, tag);
    }
}

function addRow(el) {
    if (!el) {
        return false;
    }
    else {
        var tr = closest(el, 'tr').previousElementSibling,
            newRow = tr.cloneNode(true);
        tr.parentNode.insertBefore(newRow, tr.nextSibling);
    }
}

document.getElementById('add').onclick = function() {
    addRow(this);
}​

JS Fiddle demo . JS小提琴演示

Revised the above a little, to add a simple shim to cope with those browsers that don't implement previousElementSibling :稍微修改上面的内容,添加一个简单的垫片来应对那些没有实现previousElementSibling浏览器:

function closest(el, tag) {
    if (!el || !tag) {
        return false;
    }
    else {
        var curTag = el.tagName.toLowerCase();
        return curTag == tag.toLowerCase() && curTag !== 'body' ? el : closest(el.parentNode, tag);
    }
}

function prevElementSiblingShim(el) {
    if (!el) {
        return false;
    }
    else {
        var prevSibling = el.previousSibling;
        return prevSibling.nodeType == 1 ? prevSibling : prevElementSiblingShim(prevSibling);
    }
}

function addRow(el) {
    if (!el) {
        return false;
    }
    else {
        var par = closest(el, 'tr'),
            tr = par.previousElementSibling || prevElementSiblingShim(par),
            newRow = tr.cloneNode(true);
        tr.parentNode.insertBefore(newRow, tr.nextSibling);
    }
}

document.getElementById('add').onclick = function() {
    addRow(this);
}​

References:参考:

Inserting HTML from a string into the DOM is the most efficient way.将字符串中的 HTML 插入 DOM 是最有效的方法。 Unless you're inserting hundreds at once, it doesn't really matter.除非您一次插入数百个,否则这并不重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM