Day17 - 进入轻前端 Vue 前的范例

这篇主要整合以下几点来实作

  • Tag Helper
  • 动态 新增/删除 订单项目
  • 後端加上计算功能

方便之後与轻前端 Vue 的版本做个比较 !


Case01

延续前一次的范例

  • 後端变更

    • ViewModel

      public class ViewModel
      {
          // ...
      
          [Display(Name = "小计")]
          public decimal? SubTotalAmount { get; set; }
      
          [Display(Name = "税金")]
          public decimal? Tax { get; set; }
      
          [Display(Name = "总计")]
          public decimal? TotalAmount { get; set; }
      }
      
      public class OrderItem
      {
          // ...
      
          /// <summary>
          /// 单价
          /// </summary>
          [Display(Name = "单价")]
          public decimal? UnitPrice { get; set; }
      
          // ...
      
          /// <summary>
          /// 金额
          /// </summary>
          [Display(Name = "金额")]
          public decimal? Amount { get; set; }
      }
      
    • Contoller 新增计算功能 Action

      [HttpPost, Route("api/[controller]/[action]")]
      [ValidateAntiForgeryToken]
      public IActionResult Calculate([FromForm]ViewModel vm)
      {
          if (vm?.Items?.Length > 0 == false)
          {
              return Ok(vm);
          }
      
          vm.SubTotalAmount = 0;
          foreach (var item in vm.Items)
          {
              item.Amount = item.UnitPrice * item.Quantity;
      
              vm.SubTotalAmount += item.Amount.GetValueOrDefault();;
          }
      
          vm.Tax         = vm.SubTotalAmount * 0.05m;
          vm.TotalAmount = vm.SubTotalAmount * 1.05m;
      
          return Ok(vm);
      }
      
  • 前端变更

    • Case01.cshtml

      
      ...
      
        <th>
            <label asp-for="Items.FirstOrDefault().UnitPrice"></label>
        </th>
      
      ...
      
        <th>
            <label asp-for="Items.FirstOrDefault().Amount"></label>
        </th>
      
      ...
      
        <p>
            <label asp-for="SubTotalAmount"></label>
            <label>@(Model?.SubTotalAmount)</label>
            <input type="hidden"
                   readonly
                   asp-for="SubTotalAmount" />
        </p>
        <p>
            <label asp-for="Tax"></label>
            <label>@(Model?.Tax)</label>
            <input type="hidden"
                   readonly
                   asp-for="Tax" />
        </p>
        <p>
            <label asp-for="TotalAmount"></label>
            <label>@(Model?.TotalAmount)</label>
            <input type="hidden"
                   readonly
                   asp-for="TotalAmount" />
        </p>
      ...
      
    • OrderItem.cshtml

      ...
      
          <td>
              <input type="number"
                  name="Items[@(itemIndex)].UnitPrice"
                  step=1
                  min=0
                  onblur="Calculate()"
                  asp-for="UnitPrice" />
          </td>
      
      ...
      
          <td>
              <label>@(Model?.Amount)</label>
              <input type="hidden"
                  readonly
                  name="Items[@(itemIndex)].Amount"
                  asp-for="Amount" />
          </td>
      
      ...
      
    • js 部份

      
      // ...
      
      window.CalculateUrl = '@Url.Action("Calculate")';
      
      // ...
      
      window.Calculate = function () {
      
          fetch(CalculateUrl, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'RequestVerificationToken': AntiForgeryToken,
              },
              body: $('form').serialize(),
              })
          .then(response => response.json())
          .then(data => {
              RenewAmounts(data);
          })
      }
      
      window.RenewAmounts = function (viewModel) {
      
          $('#Items > tr > td > input[name$="Amount"]').each( (index,dom) => {
              const amount = viewModel?.Items[index]?.Amount;
      
              $(dom)?.val(amount)
                      ?.prev()?.text(amount);
          });
      
          $('#SubTotalAmount')?.val(viewModel?.SubTotalAmount)
                              ?.prev()?.text(viewModel?.SubTotalAmount);
      
          $('#Tax')?.val(viewModel?.Tax)
                      ?.prev()?.text(viewModel?.Tax);
      
          $('#TotalAmount')?.val(viewModel?.TotalAmount)
                              ?.prev()?.text(viewModel?.TotalAmount);
      }
      
      // ...
      

画面如下:

Image


目前页面上比较关键的实作如下:

  1. 前端动态 新增/删除 订单项目
  2. 透过 partal view 减少维护 html 成本
  3. 在 单价 / 数量 onblur 时,就会抛到後端进行计算
  4. 後端计算完毕後,再把计算结果放回画面上

之後等轻前端的部份介绍完毕後,再回头过来跟这个范例的语法进行比较 !

这篇先到这里,下一篇开始进入 轻前端 Vue 这个部份 !


<<:  【Day2】如何安装odoo社区版?

>>:  Day 05 : 资料处理 Pandas (1)

【Day6】[资料结构]-堆叠Stack-实作

堆叠(Stack)建立的方法 push: 新增元素 pop: 从顶端移除元素 peek: 查看顶端(...

CSS微动画 - Transform不一定是位移的最佳选择

Q: 效能跟效果之间怎麽取舍? A: 如果效果不复杂,用一些渲染成本比较高的写法也无妨 新属性搭配...

Day05 - Android Jetpack: Navigation

这篇会稍微从前几篇的内容抽离出来,因为中秋节连假家人来找,只能先做点简单的事情... Android...

[Day 09] 建立机器学习模型 — Andrew Ng 大神说要这样做

AI system = Code (Algorithm/Model) + Data TL;DR 建...

Day 29 -资料库应用小程序 菜单显示(内涵程序码)

废话不多说直接开始 我们点选菜单按钮会连结到这个表单 全域变数 string MyConnectio...