在视图上自动更新 ViewComponent
Auto update ViewComponent on view
我目前的观点是:
但是每当我将商品添加到购物车时,它都不会自动更新数量。仅在我刷新页面时。
如何让它自动更新?它在 _Layout 视图上带有一个视图组件。
CartViewComponent
public class CartViewComponent : ViewComponent
{
private readonly ApplicationDbContext _context;
private readonly SignInManager<UserModel> _signInManager;
private readonly UserManager<UserModel> _userManager;
public CartViewComponent(
ApplicationDbContext context,
SignInManager<UserModel> signInManager,
UserManager<UserModel> userManager)
{
_context = context;
_signInManager = signInManager;
_userManager = userManager;
}
public int CheckIfOrderExists()
{
var userId = Request.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
OrderMain orderMain = _context.OrderMains.Where(o => o.user_id == userId).FirstOrDefault();
if (orderMain != null)
{
return orderMain.id;
}
else
{
return 0;
}
}
public int CountItemsInShoppingCart(int order_id)
{
var result = (from orderlines in _context.OrderLines
join items in _context.Items on orderlines.item_id equals items.id
join ordermains in _context.OrderMains on orderlines.order_id equals ordermains.id
where orderlines.order_id == order_id
select orderlines).Count();
return result;
}
public IViewComponentResult Invoke()
{
int order_id = CheckIfOrderExists();
int count = CountItemsInShoppingCart(order_id);
ViewBag.count = count;
return View(ViewBag.count);
}
}
Default.cshtml
<span class="badge">@ViewBag.count</span>
_Layout.cshtml
...
<li>
<a asp-area="" asp-controller="ShoppingCart" asp-action="Index">
<span style="color:black;" class="glyphicon glyphicon-shopping-cart"></span>
@await Component.InvokeAsync("Cart")
</a>
</li>
...
这里有服务器端和客户端组件。首先,视图组件只是服务器端的东西。一旦它被呈现并且服务器 returns 对客户端的响应,它是一个视图组件这一事实就完全无关紧要了。客户端只是 DOM.
中的节点集合
客户端,如果您只想使用来自服务器的新信息更新页面的某些部分,您需要发出 AJAX 请求。 JavaScript 对象 XMLHttpRequest
就是您所说的 "thin client"。它只是简单地发出请求并接收响应,但它不会自己执行任何渲染、向 DOM 添加内容等操作。这取决于您作为开发人员来确定如何处理来自服务器的响应以及如何处理它。
在这方面,您有两种选择。首先,您可以让服务器 return 部分带有一些 HTML。您不能直接请求或 return 您的视图组件,因此您需要一个 returns PartialView
的操作,以及调用您的视图组件的相应局部视图:
public IActionResult GetCart() =>
PartialView("_Cart");
然后,在_Cart.cshtml
:
@await Component.InvokeAsync("Cart");
在您的 AJAX 请求的回调中,您将 select 页面上现有的 "Cart" 父元素,并将其替换为这个新的 HTML return来自服务器。
第二个选项是简单地有一个端点,return当前购物车项目计数为 JSON。例如:
{
"items": 3
}
然后,在您的 AJAX 回调中,您只需用这个数字替换徽章的文本即可。
我实际上是使用 jQuery get 函数而不是视图组件来完成的。在 get 函数中,我从我的 ShoppingCartController 中检索 public int TotalCount()
。
在 _Layout 部分视图上,我创建了 jQuery 脚本,一个用于呈现当前值,一个用于每 2 秒更新一次值:
<script src="~/lib/jquery/dist/jquery.min.js">
</script>
<!-- rendering the current value -->
<script>
$.get('/ShoppingCart/TotalCount', function (data) {
$('#countCart').html(data);
});
</script>
<!-- reloading the value every 2 seconds -->
<script>
setInterval(function () {
$('#countCart').load('/ShoppingCart/TotalCount');
}, 2000)
</script>
徽章也在 _Layout 局部视图上:
<span class="badge" id="countCart"></span>
我目前的观点是:
但是每当我将商品添加到购物车时,它都不会自动更新数量。仅在我刷新页面时。
如何让它自动更新?它在 _Layout 视图上带有一个视图组件。
CartViewComponent
public class CartViewComponent : ViewComponent
{
private readonly ApplicationDbContext _context;
private readonly SignInManager<UserModel> _signInManager;
private readonly UserManager<UserModel> _userManager;
public CartViewComponent(
ApplicationDbContext context,
SignInManager<UserModel> signInManager,
UserManager<UserModel> userManager)
{
_context = context;
_signInManager = signInManager;
_userManager = userManager;
}
public int CheckIfOrderExists()
{
var userId = Request.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
OrderMain orderMain = _context.OrderMains.Where(o => o.user_id == userId).FirstOrDefault();
if (orderMain != null)
{
return orderMain.id;
}
else
{
return 0;
}
}
public int CountItemsInShoppingCart(int order_id)
{
var result = (from orderlines in _context.OrderLines
join items in _context.Items on orderlines.item_id equals items.id
join ordermains in _context.OrderMains on orderlines.order_id equals ordermains.id
where orderlines.order_id == order_id
select orderlines).Count();
return result;
}
public IViewComponentResult Invoke()
{
int order_id = CheckIfOrderExists();
int count = CountItemsInShoppingCart(order_id);
ViewBag.count = count;
return View(ViewBag.count);
}
}
Default.cshtml
<span class="badge">@ViewBag.count</span>
_Layout.cshtml
...
<li>
<a asp-area="" asp-controller="ShoppingCart" asp-action="Index">
<span style="color:black;" class="glyphicon glyphicon-shopping-cart"></span>
@await Component.InvokeAsync("Cart")
</a>
</li>
...
这里有服务器端和客户端组件。首先,视图组件只是服务器端的东西。一旦它被呈现并且服务器 returns 对客户端的响应,它是一个视图组件这一事实就完全无关紧要了。客户端只是 DOM.
中的节点集合客户端,如果您只想使用来自服务器的新信息更新页面的某些部分,您需要发出 AJAX 请求。 JavaScript 对象 XMLHttpRequest
就是您所说的 "thin client"。它只是简单地发出请求并接收响应,但它不会自己执行任何渲染、向 DOM 添加内容等操作。这取决于您作为开发人员来确定如何处理来自服务器的响应以及如何处理它。
在这方面,您有两种选择。首先,您可以让服务器 return 部分带有一些 HTML。您不能直接请求或 return 您的视图组件,因此您需要一个 returns PartialView
的操作,以及调用您的视图组件的相应局部视图:
public IActionResult GetCart() =>
PartialView("_Cart");
然后,在_Cart.cshtml
:
@await Component.InvokeAsync("Cart");
在您的 AJAX 请求的回调中,您将 select 页面上现有的 "Cart" 父元素,并将其替换为这个新的 HTML return来自服务器。
第二个选项是简单地有一个端点,return当前购物车项目计数为 JSON。例如:
{
"items": 3
}
然后,在您的 AJAX 回调中,您只需用这个数字替换徽章的文本即可。
我实际上是使用 jQuery get 函数而不是视图组件来完成的。在 get 函数中,我从我的 ShoppingCartController 中检索 public int TotalCount()
。
在 _Layout 部分视图上,我创建了 jQuery 脚本,一个用于呈现当前值,一个用于每 2 秒更新一次值:
<script src="~/lib/jquery/dist/jquery.min.js">
</script>
<!-- rendering the current value -->
<script>
$.get('/ShoppingCart/TotalCount', function (data) {
$('#countCart').html(data);
});
</script>
<!-- reloading the value every 2 seconds -->
<script>
setInterval(function () {
$('#countCart').load('/ShoppingCart/TotalCount');
}, 2000)
</script>
徽章也在 _Layout 局部视图上:
<span class="badge" id="countCart"></span>