MVC 3,重用部分视图和jquery,不会与DOM冲突

Nim*_*ima 11 jquery dom encapsulation reusability asp.net-mvc-3

由于我还是MVC 3和jquery的新手,我想知道如何解决以下问题的最佳实践解决方案:

我有一个视图,我使用jquery ajax来获取并显示带有产品A的一些产品细节的局部视图.加载的局部视图由一堆html和jquery代码组成,它与局部视图中定义的id相关联.

因此,我想重复使用相同的局部视图来显示同一视图上其他产品的详细信息(例如,在弹出对话框中显示产品B的详细信息).每当显示弹出窗口时,新获取的部分视图将与产品A的部分视图冲突,因为在html中使用相同的id.

案例的概念性概述

有没有办法在局部视图中封装html和javascript,并重复使用几页而不用担心与ID和东西有任何冲突?

我希望我的问题有道理.谢谢,

/尼玛

更新

这是一些伪代码,概述了我的问题:

视图

<script type="text/javascript">
$(document).ready(function () {

    $('.productItems').click(function () {
        var input = { productId: $(this).attr('data-productID') };
        var url = url = '<%: Url.Content("~/ProductDetails/ShowProductDetails") %>';


        // Show the modal box with product details
        $('#dialogBox').dialog({
            title: $(this).attr('data-productTitle')
        });


        // Fetch content in the background
        $.get(url, input, function (result, response) {
            $('#dialogBox').html(result);
            });
    });
});
</script>


<div id="detailsArea">
    <% Html.RenderPartial("ProductDetails", Model.Product); %>
</div>

<div id="productLinks">
  <span class="productItems" data-productID="123">Product B</a>
</div>

<div id="dialogBox" style="display: none;"></div>
Run Code Online (Sandbox Code Playgroud)

控制器 - >动作(ShowProductDetails)

public ActionResult ShowProductDetails(int productId)
{
  // Get product from db. and return the partial view

  return PartialView("ProductDetails", p);
}
Run Code Online (Sandbox Code Playgroud)

部分视图(ProductDetails)

<script type="text/javascript">

   function SetProductTabContent(selectedTab) {
        $("#productDescriptionContent > div").css('display', 'none');

        switch (selectedTab) {

            case '#tab-1':
                $('#productDescriptionText').css('display', 'block');
                break;

            case '#tab-2':
                $('#productSpecificationText').css('display', 'block');
                break;   
        }


$(document).ready(function () {
    // Get all the menu items
    var menuItems = $("#productMenu a");

    // Select the first tab as default
    menuItems.first().addClass("menuItemActive");

    // Handle the look of the tabs, when user selects one. 
    menuItems.click(function () {

        var item = $(this);

        // Get content for the selected tab
        SetProductTabContent(item.attr('href'));

        menuItems.removeClass("menuItemActive");
        item.addClass("menuItemActive");
        return false;
    });
});
</script>


<div id="productMenu" style="">
    <a href="#tab-1">
        <div class="menuItemHeader">Menu1</div>
    </a>
    <a href="#tab-2">
        <div class="menuItemHeader">Menu2 </div>
    </a>
</div>


<div id="productDescriptionContent">

        <div id="productDescriptionText" style="display: none;">
            <%: Model.Product.Description %>
        </div>
        <div id="productSpecificationText" style="display: none;">
            <%: Model.Product.Description2%>
        </div>
</div>
Run Code Online (Sandbox Code Playgroud)

问题 当局部视图在DOM中加载两次时,div会发生冲突.

Mrc*_*ief 7

是.正如您所指出的,不要在JavaScript中使用id和id选择器.而是使用类选择器:

例如,在您的视图中标记:

<div class="container">Partial View content</div>
Run Code Online (Sandbox Code Playgroud)

JS:

var $div = $('div.container');
// do something
Run Code Online (Sandbox Code Playgroud)

要消除选择具有相同类名的其他标记的可能性,请为部分视图中的元素指定编程名称,该元素仅用作选择器句柄而不是CSS类.

虽然基于ID的查找是性能最佳的,但在这种情况下,通过基于[tag + class]的查找来避免id冲突更有意义.基于[tag + class]的查找在性能方面非常接近id选择器.

此外,您可以通过限制查找范围来获得进一步的改进:

<div class="container">Partial View content <span class="child">Child content </span></div>

var $span = $(span.child')  // scope of lookup here is entire document
Run Code Online (Sandbox Code Playgroud)

但是,如果您知道它child位于容器div内,则可以通过以下方式限制范围:

var $div = $('div.container').children('span.child'); // or just '.child'
Run Code Online (Sandbox Code Playgroud)

另一个提示是进行一次查找并重用它:

// less performant
function doSomething() {

    // do something here
    $('div.container').css('color', 'red');

    // do other things
    $('div.container').find('.child');

   // do more things
    $('div.container').click(function() {...});
}


// better
function doSomething() {
    var $div = $('div.container');

    // do something here
    $div.css('color', 'red');

    // do other things
    $div.find('.child');

   // do more things
    $div.click(function() {...});

   // or chaining them when appropriate
   $('div.container').css('color', 'red').click(function() { ... });


}
Run Code Online (Sandbox Code Playgroud)

更新:重构OP的帖子来演示这个概念:

<script type="text/javascript">

       function SetProductTabContent(selectedTab, ctx) {
            var $container = $("div.pv_productDescriptionContent", ctx);

            // this will find only the immediate child (as you had shown with '>' selector)
            $container.children('div').css('display', 'none');  

            switch (selectedTab) {

                case '#tab-1':
                    $('div.pv_productDescriptionText', $container).css('display', 'block');
                    // or $container.children('div.pv_productDescriptionText').css('display', 'block');
                    break;

                case '#tab-2':
                    $('div.pv_productSpecificationText', $container).css('display', 'block');
                    // or $container.children('div.pv_productSpecificationText').css('display', 'block');
                    break;   
            }


    function SetUpMenuItems(ctx) {
        // Get all the menu items within the passed in context (parent element)
        var menuItems = $("div.pv_productMenu a", ctx);

        // Select the first tab as default
        menuItems.first().addClass("menuItemActive");

        // Handle the look of the tabs, when user selects one. 
        menuItems.click(function () {

            var item = $(this);

            // Get content for the selected tab
            SetProductTabContent(item.attr('href'), ctx);

            menuItems.removeClass("menuItemActive");
            item.addClass("menuItemActive");
            return false;
        });
    }
    </script>


<div style="" class="pv_productMenu">
    <a href="#tab-1">
        <div class="menuItemHeader">
            Menu1</div>
    </a><a href="#tab-2">
        <div class="menuItemHeader">
            Menu2
        </div>
    </a>
</div>
<div class="pv_productDescriptionContent">
    <div class="pv_productDescriptionText" style="display: none;">
        <%: Model.Product.Description %>
    </div>
    <div class="pv_productSpecificationText" style="display: none;">
        <%: Model.Product.Description2%>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

注意:我删除了document.ready包装器,因为加载局部视图时不会触发.相反,我重构了你的View的JS来调用setup函数并传入范围(这将避免选择具有相同类的其他div):

// Fetch content in the background
$.get(url, input, function (result, response) {
       $('#dialogBox').html(result);
       SetUpMenuItems($('#dialogBox'));   
});
Run Code Online (Sandbox Code Playgroud)

显然,你可以在你认为适合你的应用程序时进一步修改它,我所展示的是一个想法,而不是最终的解决方案.

  • 如果#dialog再次加载,它们将覆盖现有标记,因此不会重复.
  • 如果在一些其他容器再次加载局部视图,可以传递作为上下文,这将防止你访问children#dialog
  • 我想出了pv_程序化类句柄的这个任意前缀.这样,您可以告诉查看类名称,如果它是用于CSS还是用于脚本.