zoukankan      html  css  js  c++  java
  • angularjs + seajs构建Web Form前端(三) -- 兼容easyui

    回顾

      在上一章中使用了angular实现了ajax form和树形结构,经过以上两章对于angular的大致使用,对于angular也有了初步的认识,接下来的内容只会对angular的一些用法做简单的说明,如果有不清楚的可以自己查看angular API或者留言给我。

      刚开始接触angular的时候,我以为会抛弃诸如jQueryUI、easyui这样的ui组件,但是随着我学习后才发现,其实是我被自己的想法给误导、局限了。mvvm通过数据与ui的绑定,实现双向的同步,使用其他ui的组件我们一样可以通过数据的变化来实现ui组件的状态变化,通过ui组件的一些变化来变更绑定的数据也是行的通的。

    问题

      1、input类型控件

      2、列表类型控件

      3、C#扩展

    input类型控件

      由于easyui大部分的控件都可以基于input,如validatebox、datebox、numberbox等,试着使用ngModel直接在这些控件上进行绑定,代码如下:

    //html
    <div id="main" ng-controller="MainController">
        名字:<input type="text" ng-model="editData.name" />
        <br />
        年龄:<input name="age" class="easyui-numberbox" ng-model="editData.age" />
        <br />
        <a href="#" class="easyui-linkbutton" ng-click="save()">保存</a>
    </div>
    
    //js
    angular.module('test', []).controller('MainController', function ($scope) {
        var age = $('[numberboxname=age]');
    
        $scope.editData = {};
    
        $scope.save = function () {
            console.log($scope.editData);
            $scope.editData = {};
        };
    });
    

      当点击保存的时候,发现代码是运行正常的,可以在控制台内看到名字和年龄的值,但是这里有一个BUG,那就是当保存数据以后,要再次输入年龄的时候,年龄还是显示上次输入的值,因此需要在重置editData的时候将numberbox的值设置为默认值,代码就不写了。

    列表类型控件

      像numberbox、validatebox、datebox等input类型控件,都可以通过ngModel加上一些代码来实现数据的双向绑定,相对来说还是很简单的,但是像combo、combobox、combotree等就没办法直接使用ngModel进行绑定了,因为这些控件会生成额外的html代码,这是NG无法控制到的,因为这些控件的一些自身的事件机制并不能在ng内发挥作用,相反还会影响ng的正常运行,因此只能根据自身的业务来对它们进行一些扩展,这里以combobox为例子,实现思路大致如下:

      1、自定义指令生成下拉单html

      2、手动初始化combobox并将绑定字段的值设置到combobox上

      3、当combobox选择值的时候将值更新到绑定的字段上

      根据以上思路,实现代码如下:

    //其他的省略
    .directive('esCombobox', function () {
        return {
            replace: true,
            restrict: 'E',
            template: '<select></select>',
            scope: {
                data: '=',
                value: '@'
            },
            link: function (scope, element, attrs) {
                var props = scope.value.split('.');
                var current = getBinder();
    
                element.combobox({
                    data: scope.data,
                    onSelect: function (r) {
                        var binder = getBinder();
                        binder.obj[binder.field] = r.value;
                    }
                }).combobox('setValue', current.obj[current.field]);
    
                function getBinder() {
                    return props.length == 1 ? {
                        obj: scope.$parent,
                        field: props[0]
                    } : {
                        obj: scope.$parent[props[0]],
                        field: props[1]
                    };
                };
            }
        };
    });
    

      以上方法之所以要将getBinder独立出来,是因为每次操作的绑定对象都是不同的(editData在保存之后会被重新赋值,引用的对象不同了)。

    C#扩展

      有时候当我们使用服务端脚本来生成html的时候,我们可能会使用如下代码来进行绑定:

    <input type="text" ng-model="editData.name"  ng-init="editData.name='<%=Model.Name %>'"/>

      以上html代码可以发现,editData.name是绑定的字段,而ngInit内初始化赋值可以直接从Model中获取,我们可以创建一个NgModelAttribute的特性,然后该特性内提供一个属性用来存储绑定的字段,大致代码如下:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class NgModelAttribute : Attribute, ITagBuilderWrapper
    {
        private string m_BindName;
        public string BindName { get { return m_BindName; } }
    
        public NgModelAttribute(string bindName)
        {
            m_BindName = bindName;
        }
    }
    

      然后使用服务端脚本生成Html的时候,获取表达式指定的属性包含的NgModelAttribute特性以及Model的值来生成以上的html,大致代码如下:

    public static string Control(string tag, Expression<Func<TModel, object>> exp, TModel model)
    {
        var builder = new TagBuilder(tag);
        string propertyName = PropertyHelper.ResolveName(exp);
        var property = model.GetType().GetProperty(propertyName);
        var attrs = property.GetCustomAttributes(typeof(NgModelAttribute), false);
        if (attrs.Length > 0)
        {
            var ngModel = attrs[0] as NgModelAttribute;
            builder.AddAttribute("ng-model", ngModel.BindName);
            if (model != null)
            {
                var propertyValue = property.GetValue(model, null);
                string initValue;
                if (property.PropertyType == typeof(string) || property.PropertyType == typeof(Guid))
                {
                    initValue = string.Format("'{0}'", propertyValue.ToString());
                }
                else if (property.PropertyType == typeof(DateTime))
                {
                    try
                    {
                        var date = Convert.ToDateTime(propertyValue);
                        initValue = string.Format(
                            "new Date(1970, 0, 1, 0, 0, {0})",
                            Convert.ToInt32((date - new DateTime(1970, 1, 1)).TotalSeconds));
                    }
                    catch
                    {
                        initValue = "new Date()";
                    }
                }
                else
                {
                    initValue = propertyValue.ToString();
                }
                builder.AddAttribute("ng-init", string.Format("{0}={1}", ngModel.BindName, initValue));
            }
        }
        return builder.ToString();
    }
    

      以上代码仅作为参考,其中大部分的代码主要是用于判断绑定ngInit的值,因为不同值绑定的方式不同。那么接下来只要将最初的代码改为如下:

    //html
    <%=HtmlHelper.Control<Person>("input", p => p.Name, Person)
    
    //ViewModel
    public class Person
    {
        [NgModel("editData.name")]
        public string Name { get; set; }
    }
    

      生成的结果跟原来的是一样的,这样就完成了对NG的扩展了。

    结尾

      由于此次是在学习angular的过程当中,遇到了控件组的问题,由于本人对于css实在是很烂,无法实现漂亮的组件于是我就放弃了,便有了想要继续使用easyui的念头,但是引入easyui后发现它与bootstrap存在着样式兼容性问题,因此移除了bootstrap,但是编码当中发现了2个库之间的各种原理上的冲突,经过几次失败之后,终于找到了可以将2者结合在一起的方法,因此就有了此篇文章,希望此次分享能给其他人带来帮助,如果存在问题或者错误的话,请告诉我,谢谢。

  • 相关阅读:
    python基础(6)---set、collections介绍
    Vue Router滚动行为 scrollBehavior
    CSS expression属性
    定时器setTimeout实现函数节流
    axios封装
    vue项目结构
    搭建vue项目环境
    javascript参数传递中处理+号
    微信支付 chooseWXPay:fail
    微信支付get_brand_wcpay_request:fail
  • 原文地址:https://www.cnblogs.com/ahl5esoft/p/3593414.html
Copyright © 2011-2022 走看看