FineUI 官方论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

本论坛已关闭(禁止注册、发帖和回复)
请移步 三石和他的朋友们

FineUI首页 WebForms - MVC & Core - JavaScript 常见问题 - QQ群 - 十周年征文活动

FineUI(开源版) 下载源代码 - 下载空项目 - 获取ExtJS - 文档 在线示例 - 版本更新 - 捐赠作者 - 教程

升级到 ASP.NET Core 3.1,快、快、快! 全新ASP.NET Core,比WebForms还简单! 欢迎加入【三石和他的朋友们】(基础版下载)

搜索
查看: 2320|回复: 1
打印 上一主题 下一主题

FineUI + Knockout 实现数据绑定

[复制链接]
跳转到指定楼层
楼主
发表于 2020-3-29 16:12:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 棕榈 于 2020-3-29 16:19 编辑

FineUI + Knockout 实现数据绑定




knockout 是 MVVM模式的JS实现,文档 https://knockoutjs.com/documentation/introduction.html


由于 knockout 数据绑定是在DOM上的,而 FineUI 的控件都是通过JS创建的,并且控件都有自己的DOM结构,无法直接使用 knockout 进行数据绑定,这里可通过创建自定义数据绑定来实现。



我已对 FineUI 控件的常用方法及事件进行了数据绑定的封装,如下面就是控件的数据绑定定义:

  1. <f:TextBox Label="姓" AttributeDataTag="f:{text:surname}"></f:TextBox>
  2. <f:TextBox Label="名" AttributeDataTag="f:{text:name}"></f:TextBox>
  3. <f:Label Label="姓名" Text="<span data-bind='text:fullname'></span>" EncodeText="false"></f:Label>
复制代码

这是 ViewModel 代码:

  1. function ViewModel() {
  2.         var self = this;
  3.         self.surname = ko.observable('李');
  4.         self.name = ko.observable('某某');
  5.         self.fullname = ko.pureComputed(function () {
  6.                 return self.surname() + self.name();
  7.         });
  8. };
复制代码

f 为数据绑定的名称,可以通过 f:{text:name} ,将 name 绑定到 text 属性上,这里的 text 属性对应 FineUI 控件中 setText 方法,当然也可以写成 f:{setText:name},但这样不够简单直观,所以这里做了一些封装,首先会检测当前属性在 FineUI 控件中是否有对应的方法,如果有则直接采用,如果没有,加上set后再次检测是否含有,这样就可以直接使用 text 而不必使用 setText,相关的方法有很多,如:

  1. setDisabled
  2. setEditable
  3. setEmptyText
  4. setEnabled
  5. setFieldLabel
  6. setHeight
  7. setHidden
  8. setMaxLength
  9. setMinLength
  10. setReadonly
  11. setRedStar
  12. setRegex
  13. setRegexPattern
  14. setRequired
  15. setSize
  16. setText
  17. setTooltip
  18. setValue
  19. setVisible
  20. setWidth
复制代码

都可以直接将 set 去掉,直接使用后面的名称,如 tooltip 等,这里要注意,对于方法需要传递两个参数的,只能传递第一个参数,对于多个参数只能通过FineUI提供的api进行调用。

事件直接使用FineUI控件提供的事件名称,如 click , 可以直接写 f:{click:save},save为ViewModel中的方法,这里还要注意一下,由于FineUI控件中的方法名与事件名有相同的,如click,hide,show,这里都将示为事件名。


下面为示例中的代码:

  1. @page
  2. @model FineUICore.EmptyProject.RazorPages.Pages.HelloModel
  3. @{
  4.     ViewBag.Title = "Hello";
  5.     var F = @Html.F();
  6. }

  7. @section head {
  8.     <link href="~/bootstrap-4.4.1/css/bootstrap.css" rel="stylesheet" type="text/css" />
  9. }

  10. @section body {

  11.     <div class="input-group mb-3">
  12.         <div class="input-group-prepend">
  13.             <span class="input-group-text" id="basic-addon1">@@</span>
  14.         </div>
  15.         <input type="text" class="form-control" data-bind="value:textbox,valueUpdate:'input'" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1">
  16.     </div>

  17.     <div class="progress">
  18.         <div class="progress-bar" data-bind="style:{width:progress()+'%'},text:progress()+'%'" role="progressbar"></div>
  19.     </div>

  20.     <f:Panel Layout="Anchor" Title="bootstrap 文本框" Width="350" BodyPadding="20">
  21.         <Items>
  22.             <f:Panel ShowBorder="false" ShowHeader="false" ContentEl=".input-group"></f:Panel>
  23.             <f:TextBox AttributeDataTag="f:{text:textbox}"></f:TextBox>
  24.         </Items>
  25.     </f:Panel>

  26.     <br />

  27.     <f:Panel Layout="Anchor" Title="bootstrap 进行条" Width="350" BodyPadding="20">
  28.         <Items>
  29.             <f:Panel ShowBorder="false" ShowHeader="false" ContentEl=".progress" CssStyle="margin-bottom:10px"></f:Panel>
  30.             <f:NumberBox AttributeDataTag="f:{value:progress}"></f:NumberBox>
  31.         </Items>
  32.     </f:Panel>

  33.     <br />

  34.     <f:Panel Layout="Anchor" Title="姓名" Width="350" BodyPadding="20">
  35.         <Items>
  36.             <f:TextBox Label="姓" AttributeDataTag="f:{text:surname}"></f:TextBox>
  37.             <f:TextBox Label="名" AttributeDataTag="f:{text:name}"></f:TextBox>
  38.             <f:Label Label="姓名" Text="<span data-bind='text:fullname'></span>" EncodeText="false"></f:Label>
  39.         </Items>
  40.     </f:Panel>

  41.     <br />

  42.     <f:Panel Layout="HBox" Title="两数相乘" Width="350" BodyPadding="20">
  43.         <Items>
  44.             <f:NumberBox AttributeDataTag="f:{value:value1}" BoxFlex="1"></f:NumberBox>
  45.             <f:Label Text="*" Margin="0 10 0 10"></f:Label>
  46.             <f:NumberBox AttributeDataTag="f:{value:value2}" BoxFlex="1"></f:NumberBox>
  47.             <f:Label Text="=" Margin="0 10 0 10"></f:Label>
  48.             <f:NumberBox Readonly="true" AttributeDataTag="f:{value:value1()*value2()}" BoxFlex="1"></f:NumberBox>
  49.         </Items>
  50.     </f:Panel>

  51.     <br />

  52.     <f:Panel Layout="Anchor" Title="联系人地址" Width="350" BodyPadding="20">
  53.         <Items>
  54.             <f:CheckBox ID="cbxSameAsContactAddress" Text="启用联系人地址" AttributeDataTag="f:{value:enableAddress}"></f:CheckBox>
  55.             <f:TextBox ID="tbxBillingAddress" Label="详细地址" AttributeDataTag="f:{enabled:enableAddress}"></f:TextBox>
  56.             <f:Panel ID="Panel3" Layout="VBox" BoxConfigAlign="Stretch" ShowHeader="false" ShowBorder="false">
  57.                 <Items>
  58.                     <f:TextBox ID="tbxBillingProvince" Label="省" AttributeDataTag="f:{enabled:enableAddress}"></f:TextBox>
  59.                     <f:TextBox ID="tbxBillingCity" Label="市" AttributeDataTag="f:{enabled:enableAddress}"></f:TextBox>
  60.                     <f:TextBox ID="tbxBillingPostCode" Label="邮政编码" AttributeDataTag="f:{enabled:enableAddress}"></f:TextBox>
  61.                 </Items>
  62.             </f:Panel>
  63.         </Items>
  64.     </f:Panel>
  65. }

  66. @section script {
  67.     <script src="~/bootstrap-4.4.1/js/bootstrap.bundle.js"></script>
  68.     <script src="~/knockout-3.5.1/knockout.js"></script>
  69.     <script src="~/res/js/knockout-fineui.js"></script>

  70.     <script>
  71.         F.ready(function () {
  72.             $('[data-tag]').each(function () {
  73.                 $(this).attr('data-bind', $(this).data('tag'));
  74.             });

  75.             function ViewModel() {
  76.                 var self = this;
  77.                 self.surname = ko.observable('李');
  78.                 self.name = ko.observable('某某');
  79.                 self.fullname = ko.pureComputed(function () {
  80.                     return self.surname() + self.name();
  81.                 });

  82.                 value1 = ko.observable(20);
  83.                 value2 = ko.observable(5);

  84.                 textbox = ko.observable('bootstrap');
  85.                 progress = ko.observable(40);

  86.                 enableAddress = ko.observable(false);
  87.             };

  88.             ko.applyBindings(new ViewModel());
  89.         });
  90.     </script>
  91. }
复制代码


关于示例代码,这里简单说一下,由于 FineUI 中没有直接提供 data-bind 的属性,这里借用了 AttributeDataTag 属性,并在 FineUI 控件初始化完成后,将 data-tag 中的值复制到 data-bind 中,代码:

  1. $('[data-tag]').each(function () {
  2.         $(this).attr('data-bind', $(this).data('tag'));
  3. });
复制代码

希望三石兄提供一个 AttributeDataBind 属性,这样就可以直接使用,而不必借用 AttributeDataTag 属性。


示例项目文件及 knockout-fineui.js 请到知识星球下载。









本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
沙发
发表于 2020-3-29 21:34:03 | 只看该作者
赞,一个很好的尝试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|FineUI 官方论坛 ( 皖ICP备2021006167号-1 )

GMT+8, 2024-11-25 12:53 , Processed in 0.045812 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表