2011-08-06 33 views
11

Như tôi vẫn còn mới để MVC 3 và jquery, tôi muốn biết một giải pháp thực hành tốt nhất để như thế nào sau đây có thể được giải quyết:MVC 3, tái sử dụng của quang cảnh một phần và jquery, không mâu thuẫn DOM

tôi có một cái nhìn, nơi tôi sử dụng jquery ajax để lấy và hiển thị một phần xem với một số chi tiết sản phẩm cho sản phẩm A. Khung nhìn từng phần được nạp bao gồm một chuỗi mã html và jquery, được gắn với id được định nghĩa trong khung nhìn một phần.

Do đó, tôi muốn sử dụng lại chế độ xem một phần để hiển thị chi tiết từ các sản phẩm khác trên cùng một Chế độ xem (ví dụ: hiển thị chi tiết sản phẩm B trong hộp thoại bật lên). Bất cứ khi nào cửa sổ bật lên được hiển thị, chế độ xem một phần mới được tìm nạp sẽ xung đột với chế độ xem từng phần cho sản phẩm A, vì cùng một id được sử dụng trong html.

Conceptual overview of the case

Có cách nào để đóng gói html và javascript trong giao diện phần, và tái sử dụng nó nhiều trang mà không cần lo lắng về bất kỳ cuộc xung đột với ID và các công cụ?

Tôi hy vọng câu hỏi của tôi có ý nghĩa. Cảm ơn,

/Nima

CẬP NHẬT

Dưới đây là một số mã giả, phác thảo vấn đề của tôi:

XEM

<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> 

Controller -> Hành động (ShowProductDetails)

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

    return PartialView("ProductDetails", p); 
} 

Partial View (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> 

CẤP Khi xem một phần được nạp hai lần trong DOM, các divs xung đột.

+0

gì về cách hiển thị nội dung của DialogBox trong iframe không? – Nima

Trả lời

7

Có. Như bạn đã chỉ ra, không sử dụng id và id selectors trong JavaScript của bạn. Thay vì sử dụng bộ chọn lớp:

Ví dụ, trong xem của bạn đánh dấu:

<div class="container">Partial View content</div> 

JS:

var $div = $('div.container'); 
// do something 

Để loại bỏ khả năng lựa chọn các thẻ khác với tên lớp cùng, gán một tên có lập trình các phần tử trong chế độ xem từng phần chỉ được sử dụng làm công cụ chọn và không phải là lớp CSS.

Trong khi tra cứu dựa trên ID là hiệu suất tốt nhất khôn ngoan, trong trường hợp này, việc tìm kiếm dựa trên [thẻ +] trở nên có ý nghĩa hơn để tránh xung đột id. Tra cứu dựa trên [tag + class] xuất hiện khá gần với bộ chọn id về hiệu suất.

Ngoài ra, bạn có thể đạt được sự cải thiện hơn nữa bằng cách giới hạn phạm vi tìm kiếm:

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

var $span = $(span.child') // scope of lookup here is entire document 

Tuy nhiên, nếu bạn biết rằng child là bên trong div container, bạn có thể giới hạn phạm vi bằng cách nói:

var $div = $('div.container').children('span.child'); // or just '.child' 

Một mẹo khác là thực hiện tra cứu một lần và sử dụng lại nó:

// 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() { ... }); 


} 

Cập nhật: bài Refactoring OP để giới thiệu các khái niệm:

<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> 

Lưu ý: Tôi đã gỡ bỏ document.ready wrapper vì đó sẽ không cháy khi bạn tải quan điểm một phần. Thay vào đó, tôi refactored JS của Xem của bạn để gọi hàm thiết lập và cũng vượt qua trong phạm vi (mà sẽ tránh chọn divs khác với cùng một lớp):

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

Rõ ràng, bạn có thể sửa đổi này hơn nữa khi bạn cho là phù hợp trong của bạn ứng dụng, những gì tôi đã thể hiện là một ý tưởng chứ không phải là giải pháp cuối cùng.

  • lần nữa, chúng sẽ ghi đè lên đánh dấu hiện có, do đó sẽ không bị trùng lặp.
  • Nếu bạn tải quan điểm từng phần một lần nữa trong một số thùng chứa khác, bạn có thể vượt qua điều đó như bối cảnh và điều đó sẽ ngăn cản bạn truy cập vào children của #dialog
  • tôi đến với tiền tố tùy ý này pv_ cho xử lý lớp theo chương trình. Bằng cách đó, bạn có thể nói xem tên lớp nếu nó là cho CSS hoặc để sử dụng trong kịch bản của bạn.
+1

vấn đề với bộ chọn lớp là, nếu tôi ví dụ thực hiện một số hành động đối với sản phẩm B (trong cửa sổ bật lên), điều tương tự sẽ xảy ra trên Sản phẩm A. Hai loại đó không nên phụ thuộc vào nhau. – Nima

+0

Thử sử dụng kiểu dữ liệu * * HTML5 và chọn kiểu dựa trên thuộc tính mới của bạn. Lik data-product = "1" – turtlepick

+0

Đó là nơi tìm kiếm phạm vi giúp. Bạn có thể tra cứu trong một phạm vi nhất định. Hơn nữa, bạn có thể đặt tên cho bộ chọn của mình sao cho chúng sẽ là duy nhất: 'class =" partial_view_main_container "'. Đây không phải là một lớp css mà bạn sẽ sử dụng để tạo kiểu, nhưng chỉ để tìm kiếm nội dung của phần xem của bạn. – Mrchief

0

Cách đơn giản nhất để làm điều đó là, làm cho id của sản phẩm như một phần của thẻ html id

một cái gì đó như thế

<input type="text" id="txt_<%=Model.ID%>"> 

nếu bạn sử dụng Razor

<input type="text" id="[email protected]"> 
+0

Đây là một cách tiếp cận lộn xộn trong thời gian dài. Vài ví dụ: 1) Onus là bạn để tạo ra id duy nhất mọi lúc (vì vậy giữa các yêu cầu, bạn cần phải giữ một tab của nó bằng cách nào đó). 2) Bạn cần phải tiêm này bằng cách nào đó trong yuor javascript (trừ khi bạn đang viết kịch bản nội tuyến) cũng có. 3) javscript của bạn không thể được kiểm tra đơn vị vì nó phụ thuộc vào các id được tự động hóa. – Mrchief

+0

Vâng, nó thực sự có ý nghĩa để bao gồm id trong html. Nhưng tôi tất cả các điểm được thực hiện bởi @Mrchief cũng có ý nghĩa. Nhưng đây thực sự là cách để làm điều đó? – Nima

+0

@Nima nó chỉ là cách đơn giản nhất để ngăn chặn xung đột giữa các div khi xem một phần được nạp hai lần, nhưng có nhiều cách khác để thực hiện samething –

0

tôi m ngạc nhiên điều này đã không đi lên thường xuyên hơn. Tôi đoán hầu hết các nhà phát triển không tạo điều khiển riêng của họ với partials. Đây là một cái gì đó mà tôi đến với đó là hoạt động khá tốt và không phải là khó thực hiện trong MVC4.

Trước tiên, tôi đã thử chuyển một mô hình động sang một phần và không hoạt động. (mặt buồn) Sau đó, tôi đã đi tuyến đường được xem từng phần. Tôi tạo ra một bộ sưu tập các đối tượng được gọi là các bước (vì xây dựng một điều khiển thuật sĩ).

public class WizardStep 
{ 
    public string Id { get; set; } 
    public string Class { get; set; } 
} 

public class WizardSteps 
{ 

    public WizardSteps() 
    { 
     Steps = new List<WizardStep>(); 
     Steps.Add(new WizardStep() {Id = "Step1"}); 
     Steps.Add(new WizardStep() { Id = "Step2" }); 
     Steps.Add(new WizardStep() { Id = "Step3" }); 
     Steps.Add(new WizardStep() { Id = "Step4" }); 
     Steps.Add(new WizardStep() { Id = "Step5" }); 

    } 
    public List<WizardStep> Steps { get; set; } 

} 

đang Razor trông như thế này:

@Html.Partial("_WizardButtonPanel", @Model.WizardSteps.Steps.First()) 

hoặc

@Html.Partial("_WizardButtonPanel", @Model.WizardSteps.Steps.Skip(1).First()) 

hoặc

@Html.Partial("_WizardButtonPanel", @Model.WizardSteps.Steps.Skip(2).First()) 

và nhiều hơn nữa

@Html.Partial("_WizardButtonPanel",@Model.WizardSteps.Steps.Skip(3).First()) 

Quan điểm phần trông giống như sau:

@model SomeProject.Models.WizardStep 
<div id="[email protected]" > 
<a id="[email protected]" >Somelinke</a> 
</div> 

Chúc mừng mã hóa ...

+0

BTW tìm kiếm bằng cách sử dụng bộ chọn lớp sẽ gây ra sự cố trong điều khiển loại trình hướng dẫn. – Tim

Các vấn đề liên quan