MVC 3,重用部分视图和jquery,不与DOM冲突
由于我对 MVC 3 和 jquery 还很陌生,我想知道如何解决以下问题的最佳实践解决方案:
我有一个视图,我使用 jquery ajax 来获取和显示带有一些产品详细信息的部分视图产品 A。加载的部分视图由一堆 html 和 jquery 代码组成,这些代码与部分视图中定义的 id 相关联。
因此,我想重用相同的部分视图来显示同一视图上其他产品的详细信息(例如,在弹出对话框中显示产品 B 的详细信息)。每当显示弹出窗口时,新获取的部分视图将与产品 A 的部分视图冲突,因为 html 中使用了相同的 id。
有没有一种方法可以将 html 和 javascript 封装在局部视图中,并在多个页面中重复使用它,而无需担心ID之类的东西有冲突吗?
我希望我的问题有意义。谢谢,
/Nima
更新
这是一些伪代码,概述了我的问题:
VIEW
<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 ->操作(显示产品详细信息)
public ActionResult ShowProductDetails(int productId)
{
// Get product from db. and return the partial view
return PartialView("ProductDetails", p);
}
部分视图(产品详细信息)
<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>
问题 当分部视图在 DOM 中加载两次时,div 会发生冲突。
As i am still new to MVC 3 and jquery, i would like to know a best practice solution to how the following can be solved:
I have a view, where I use jquery ajax to fetch and display a partial view with some product details for product A. The loaded partial view consist of a bunch of html and jquery code, which is tied to the defined id's within the partial view.
Thus, i would like to reuse the same partial view to show details from other products on the same View (e.g. show product B details in a pop-up dialog). Whenever the pop-up is shown, the newly fetched partial view will conflict with the partial view for product A, as the same id's are used in the html.
Is there a way to encapsulate the html and javascript in the partial view, and reuse it several pages without worry about any conflicts with ID's and stuff?
I hope my question makes sense. Thanks,
/Nima
UPDATED
Here is some pseudo code, outlining my issue:
VIEW
<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 -> Action (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>
ISSUE
When the partial view gets loaded twice in the DOM, the divs conflicts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的。正如您所指出的,不要在 JavaScript 中使用 ids 和 id 选择器。而是使用类选择器:
例如,在视图的标记中:
JS:
为了消除选择具有相同类名的其他标记的可能性,请为部分视图中的元素分配一个编程名称,其中仅用作选择器句柄,而不用作 CSS 类。
虽然基于 ID 的查找性能最佳,但在这种情况下,通过基于 [tag+class] 的查找来避免 id 冲突更有意义。基于 [tag+class] 的查找在性能方面非常接近 id 选择器。
另外,您可以通过限制查找范围来获得进一步的改进:
但是,如果您知道
child
位于容器 div 内,则可以通过以下方式限制范围:另一个技巧是查找一次并重复使用它:
更新:重构OP的帖子来演示这个概念:
注意:我删除了
document.ready
包装器,因为当您加载时它不会触发局部视图。相反,我重构了 View 的 JS 来调用 setup 函数并传入范围(这将避免选择具有相同类的其他 div):显然,您可以根据您认为适合您的应用程序的情况进一步修改它,我已经展示了只是一个想法,而不是最终的解决方案。
#dialog
,它们将覆盖现有标记,因此不会出现重复。#dialog
的children
pv_
。这样,您就可以通过查看类名来判断它是用于 CSS 还是用于脚本中。Yes. As you pointed out, do not use ids and id selectors in your JavaScript. Instead use class selectors:
E.g., in your view's markup:
JS:
To eliminate possibility of selecting other tags with same class name, assign a programmatic name the elements in partial view which is used only as a selector handle and not as a CSS class.
While ID based lookup is the best performance wise, in this case, it makes more sense to go by the [tag+class] based lookup to avoid id conflicts. [tag+class] based lookup comes pretty close to id selectors in terms of performance.
Also, you can gain further improvement by limiting the lookup scope:
However, if you know that
child
is inside container div, you can limit the scope by saying:Another tip is to do the lookup once and reuse it:
Update: Refactoring OP's post to demo the concept:
Note: I removed
document.ready
wrapper since that will not fire when you load the partial view. Instead, I refactored your View's JS to call the setup function and also pass in the scope (which will avoid selecting other divs with same class):Obviously, you can modify this further as you deem fit in your app, what I've shown is an idea and not the final solution.
#dialog
again, they will overwrite existing markup, hence there won't be duplicate.children
of#dialog
pv_
for programmatic class handles. That way, you can tell looking at the class name if it is for CSS or for use in your script.最简单的方法是,将产品 id 作为 html 标签 id 的一部分,
类似于id
如果您使用 Razor,则
Simplest way to do that is, make ids of products as part of html tags ids
something like that
if you use
Razor
我很惊讶这种情况并没有更频繁地出现。我想大多数开发人员都不会使用部分内容创建自己的控件。这是我带来的东西,它运行得很好,并且在 MVC4 中实现起来并不困难。
首先,我尝试将动态模型传递给局部模型,但这不起作用。 (悲伤的表情)
然后我走了打字的部分视图路线。我创建了一个称为步骤的对象集合(因为构建了一个向导控件)。
Razor 代码如下所示:
or
or
and more
部分视图如下所示:
快乐编码...
I'm surprised this hasn't come up more often. I guess most developers aren't creating their own controls with partials. Here is something that I came with that is works pretty well and not that hard to implement in MVC4.
First I tried passing a dynamic model to the partial and that doesn't work. (sad face)
Then I went the typed partial view route. I created a collection of objects called steps (because build a wizard control).
Razor code looks like this:
or
or
and more
The partial view looks something like this:
Happy coding...