【问题标题】:What would be the best way to go about writing this in JS/jQuery? (Multiple individual objects with multiple fields)用 JS/jQuery 编写这个的最好方法是什么? (具有多个字段的多个单个对象)
【发布时间】:2013-08-26 10:10:33
【问题描述】:

警告:这是一篇很长的文章,因为有很多与问题相关的信息,所以请做好准备,如果您愿意,感谢您抽出宝贵时间阅读!

我正在为客户编写一个非常大的 WebApp,并为此使用 jQuery 构建了许多交互式应用程序,但我开发的一个让我想知道:有没有标准的方法来做这个,或者只是一个更好的方法

这是我来找你们的地方,以了解是否有某种方法可以做到这一点,因为我一直在寻找构建最佳应用程序。

我必须完成的任务

我正在构建的应用要求用户能够创建产品发票。该发票可以通过搜索框添加任意数量的产品。每个产品都从数据库中提取并存储在该搜索框中,并且每个产品都可以添加多次。

用户添加产品的方式是在搜索框中输入产品名称,然后按添加产品按钮。这会将已处理的模板添加到产品列表中。很简单吧?

问题

我遇到的一个大问题是,不仅发票能够包含产品列表,而且这些产品中的每一个都包含不同的可定制细节。这意味着每个产品都有许多自己的字段,用户可以编辑这些字段,从而修改了许多内容。例如,一种产品具有数量,需要乘以该产品的成本价才能返回总价。另一种产品有一个长度,需要乘以宽度,再乘以该产品的成本价返回总价。

您可以想象,有许多不同类型的产品具有许多不同的字段需要进行许多不同的计算,其中,在创建结束时,需要解析为 PHP 页面,同时保持完全可修改性,用户可以在同一发票页面上添加/删除/编辑产品而无需跳转.

对我来说,这简直是一场噩梦,因为我需要有一种方法来保持这种清洁,并且让一堆不同的输入/jQuery 对象不会以某种方式相互碰撞。我还必须将加载的产品与新创建的产品区分开来,因为有些产品会从数据库中获取信息

我构建的解决方案

因此,当产品添加到列表前时,该产品包含许多字段、许多详细信息和一个删除按钮。我做的第一件事是为每种不同类型的产品制作带有可替换标记的模板。这很简单,而且工作得非常好,当一个产品被添加到列表之前,对于与该产品相关的每个元素,我添加了一个 rel 属性(我称之为“钩子”) ) 以便我可以添加仅使用该特定钩子修改元素的处理程序

对于我使用输入数组的输入,格式为<input name="Products[%HOOK%][%PRODUCTDATAKEY%]" value="%PRODUCTDATAVALUE%" />。我出现的主要问题是我必须将已加载的已保存在数据库中的产品与刚刚添加的新添加产品区分开来。我这样做的方法是在所有输入名称数组之前添加 [Loaded],以便我的 PHP 脚本能够单独处理 [Loaded] 数组。

我有什么顾虑?

我最担心的是,从标记到代码,一切最终看起来有多混乱。 钩子到处乱飞,输入名称极长几千行代码以及各种按键和操作让人头疼要替换的令牌。它工作得很好,当我作为开发人员看待它时感觉很糟糕。以这个“添加的产品”为例:

<div class="item product special-order" rel="7" style="">
    <input type="hidden" name="products[7][id]" value="17">
    <input type="hidden" name="products[7][item_id]" value="">
    <input type="hidden" name="products[7][type]" value="Special Order Flooring">
    <input type="hidden" name="retail_price" class="invoice-base-cost" value="18.49">
    <h4>Carpet Brand<a name="action" rel="7" class="btn btn-mini btn-danger remove-product initialized" style=""><i class="icon-remove"></i> Remove</a>
 </h4>
    <div class="item-details">
        <div class="detail-column">
            <div class="detail">
                <span class="detail-label detail-label-medium"> Type:</span>Carpet
            </div>
            <div class="detail">
                <span class="detail-label detail-label-medium">Range:</span> Carpet Brand
            </div>
            <div class="detail">
            <span class="detail-label detail-label-medium">
                Colour:</span><input required="" class="detail-input-large left-align" value="" type="text" name="products[7][colour]">
            </div>
            <div class="detail">
            <span class="detail-label detail-label-medium">
            Length:</span><input type="text" name="products[7][length]" rel="7" class="length-field initialized" placeholder="Enter the length..." value="1.000"><span class="detail-unit">m</span>
            </div>
        </div>

        <div class="detail-column">
            <div class="detail">
                <span class="detail-label detail-label-large">Manufacturer:</span>
                <select class="detail-input-large" required="" name="products[7][manufacturer_id]">
                    <option value="14">Manufacturer 1</option>
                    <option value="16">Manufacturer 2</option>
                </select>
            </div>
            <div class="detail">
                <span class="detail-label detail-label-large">Width supplied:</span><input type="text" name="products[7][width]" class="width-field" value="5.000"><span class="detail-unit">m</span>
            </div>
            <div class="detail">
                <span class="detail-label detail-label-large">Retail price per/m:</span> £18.49
            </div>
            <div class="detail">
                <span class="detail-label detail-label-large">Room:</span><input class="detail-input-large left-align" type="text" name="products[7][room]" value="" required="required">
            </div>
        </div>
        <div class="item-cost">
            <h5>Item cost</h5>
            £<span class="invoice-cost" rel="7">92.45</span>
        </div>
    </div>
</div>

这不是矫枉过正吗?难道我没有将这些映射到 JSON 对象 以使其更清洁吗?或者这是正确的方法吗?

该产品上也有大约 5 个不同的事件绑定,这很混乱,因为 如果更改了长度字段,则必须根据宽度和底价宽度相同,而这一切都是通过寻找具有相同rel(hook)的字段来完成的...在我看来,这简直是一团糟。就应该如何处理这个问题获得专家意见会很棒。

【问题讨论】:

  • 如果你只是想优化工作代码,你可能想试试Code Review

标签: php javascript jquery optimization refactoring


【解决方案1】:

我支持前两个答案:使用旨在处理此问题的框架。

然而,在去那里之前,这是模块化代码的第一步:根据您的描述,您似乎有一个 .special-order 项目的列表,每个项目都有自己的生命。

尝试在您的标记和代码中体现这一点:

1- 标记:使用有意义的类名来识别将发挥积极作用的项目(您似乎已经拥有:.special-order.length-field.remove-button ...)。确保有一个单独的节点来包装整个 html“捆绑包”(在您的情况下:.special-order 似乎扮演了这个角色)。

2- 事件挂钩:使用这些类名来绑定您的挂钩:

$('.remove-button').click(function(){  ...  });
$('.length-field').change(function(){ ... });

3- 如果您的项目列表是动态的(例如,您可以通过 javascript 添加/删除项目而无需重新加载整个页面),请使用event delegation 绑定您的事件:

$('.special-order-list').on('click', '.remove-button', function(){ ... });
$('.special-order-list').on('change', '.length-field', function(){ ... });

4- 在您的处理程序中,遵循标记中表示的模块化。如果两个节点是同一 .special-order 节点的子节点,则它们是相关的。这样您就可以表示节点之间的关系,这不依赖于“rel”字段的显式值:

 $('.special-order-list').on('change', '.length-field', function(){
     var $masterNode = $(this).closest('.special-order');
     var basePrice = $masterNode.find('.base-price').val();
     var length = $(this).val();
     $masterNode.find('.total-price').val( basePrice * length );
 });

5- 显然,在适当的地方使用函数:

 function recomputePrice($masterNode){
     var basePrice = $masterNode.find('.base-price').val();
     var length = $masterNode.find('.length-field').val();
     $masterNode.find('.total-price').val( basePrice * length );
 });

 $('.special-order-list').on('change', '.length-field, .base-price', function(){
     var $masterNode = $(this).closest('.special-order');
     recomputePrice( $masterNode );
 });

将您的页面组织成模块和子模块(有些人称它们为组件或小部件......)被认为是页面布局的“最佳实践”。在 SmaCSS 中提到了它,它是几个 css/js 框架的基础,例如 Bootstrap 或许多其他框架。

【讨论】:

  • 这给了我关于如何使用相关节点作为查找子属性的一种方式的观点,结合事件委托(我以前不太了解)给了我一个很好的想法工具箱跟...共事。非常适合这个问题的很好的答案!
  • 很高兴我能帮上忙。下面是对事件委托的简单直接的解释:stackoverflow.com/questions/8110934/…
  • 您应该将此答案标记为您的解决方案,因为它似乎对您帮助最大。
【解决方案2】:

正如 spez86 所建议的那样;您应该使用框架来生成 HTML,并将事件绑定到每个 HTML 部分中的元素。我建议你看看backbonejshandlebarsjs。当您结合使用这 2 个时,您需要付出最小的努力来实现您的目标。
您可以参考以下URL 以了解更多关于它们的用法。
我会建议您首先在 UI 上工作,即创建为您不同类型的产品提供单独的模板,然后在您的添加产品按钮上单击尝试将主干视图附加到您的产品列表容器。
一旦您能够成功地将 HTML 添加到页面上,您就可以继续将事件绑定到产品模板中存在的子元素。这可以在 Backbone.View 类的 events 函数中完成。此处注册的事件处理程序将仅附加到此视图中存在的元素,而不附加到页面 DOM 中具有相同 CSS 类的任何其他元素。因此,您将摆脱 [rel] 机制以及长输入名称。希望这会对您有所帮助。

【讨论】:

    【解决方案3】:

    老实说,鉴于您所谈论的数据量和可以修改的方式的数量,您应该寻找一个更强大的框架,并且旨在使数据绑定更容易。那里有很多,但我个人最喜欢的是 AngularJS。

    http://angularjs.org/

    开始研究这一点,因为它可能会为您节省大量时间来开发应用程序,然后当然可以在以后对其进行维护。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-13
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-28
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      相关资源
      最近更新 更多