热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用avalonmsui绑定实现基于组件的开发

使用avalonms-ui绑定实现基于组件的开发让日子过得轻松,必须让代码不断往上抽象。avalon的一切就是为这个崇高的目的而迸进——操作数据即操作DOM,远离DOM进行前端开发。javascri

使用avalon ms-ui绑定实现基于组件的开发

让日子过得轻松,必须让代码不断往上抽象。avalon的一切就是为这个崇高的目的而迸进——操作数据即操作DOM,远离DOM进行前端开发。Javascript之所以在生命的前十年碌碌无为,都是因为开发者被这些兼容性问题搞怕了。在前十年,人们都是用着那些很底层的原生DOM方法,JS方法进行编程,效率异常低下。随着Prototype.js, jQuery等库的出现, 把几乎所有能封装都给封装了, 我们的生活才变得美好起来。但开发企业内部管理系统,却鲜有听说用jQuery来搞,大家都爱用开箱即用的EXT UI框架。UI组件无疑是比jQuery这些DOM操作对象强上一截,是更高程度的抽象与封装。但组件的制定性一般很差,比如说zTree,它就使用插件化来进行扩展。对于目前业界给出的方案,avalon是怎么做的呢?

首先,像ms-class, ms-hover, ms-on其实是在jQuery的事情,不同的是,它没有依赖Sizzle这些动则上千行的选择器引擎,而是通过扫描与转换绑定属性实现。绑定属性会转换一个求值函数,求值函数内部与ViewModel挂钩,因此能即时同步,外部套着一个DOM操作函数,比如说ms-class,就是根据求值函数的返回值的真假来调用toggleClass, ms-hover则是通过绑定mouseenter, mouseleave来toggleClass, ms-checked是处理表单元素的checked属性, ms-visible负责元素的显示隐藏, ms-if负责将元素移出或插入DOM……短短一个绑定属性就包含非常高密度的DOM操作,比jQuery更加write less, do more, do simple!这个园子已经有人在用我的avalon,反映都是很不错的,当然也提了不少改进见意。

其次是组件层面,avalon与angular一样,提供面向组件的开发,但比angular用法简单多了。avalon参考了bootstrap这个twitter开发的UI库,利用data-*属性进行功能定制(当然,它还有其他形式的配置方式)。并且像bootstrap那样,只要引入JS,在相关元素上添加ms-ui="组件名",元素节点就会转换为UI组件,一行代码也不用你写。

ms-ui绑定能给我们带来以下好处:将元素上的绑定属性减到最少,只需添加ms-ui="组件名",或最多添加data-id="xxx", 保证对HTML最少限度的干扰。也就是说,美工与前端有了非常明确的分工。而data-id中的值则是对应ViewModel的ID,我们可以通过此ID在avalon.models[ID]中取得ViewModel,从而实现操作数据即操作DOM。

基于组件,使得我们的表现层变成由一个个“积木”堆积而成。Page规则转向如何协调这些组件的运作,而不是盯着一个个元素节点。不过avalon已经帮你搞定了大部分了。比如说,基本URL远程请求不同的资源,然后转换为ViewModel,然后生成某个页面的区域。还有消息中心(也叫事件中心),由于ViewModel本来就是用观察者模式实现的,一个活生生的消息中心,你不需再造轮子。随着我们项目的深入,我们积累的各种积木也就越来越多,也就是,我们的工作就越轻松,工作效率也就越来越高。

与其他UI库不一样的,avalon编写UI太简单,太方便了,这得益于它强大的双向绑定机制。

拿avalon.tabs组件的源码举例吧:

(function(avalon) {
    var defaults = {
        active: 0,
        event: "click", //可以使用click, mouseover
        collapsible: false,
        bottom: false,
        removable: false
    };
    avalon.ui.tabs = function(element, id, opts) {
        var el, tabsParent, tabs = [], tabpanels = [];
        var $element = avalon(element);
        //1,设置参数对象optiOns= defaults + opts + $element.data()
        var optiOns= avalon.mix({}, defaults);
        if (typeof opts === "object") {
            avalon.mix(options, opts.$json || opts);
        }
        avalon.mix(options, $element.data());
         
        $element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
 
        //2, 清空它内部所有节点,并收集其内容,构建成tabs与tabpanels两个数组
        while (el = element.firstChild) {
            if (!tablist && (el.tagName === "UL" || el.tagName === "OL")) {
                tabsParent = el;
            }
            if (el.tagName === "DIV") {
                tabpanels.push(el.innerHTML);
            }
            element.removeChild(el);
        }
 
        for (var i = 0; el = tabsParent.children[i++]; ) {
            tabs.push(el.innerHTML);
        }
        //3 设置动态模板
        var tablist = '
     +
                ' ms-class-ui-corner-all="!bottom"  ms-class-ui-corner-bottom="bottom" ms-each-tab="tabs">' +
                '
  •  +
  •                 ' ms-class-ui-corner-top="!bottom"' +
                    ' ms-class-ui-corner-bottom="bottom"' +
                    ' ms-class-ui-tabs-active="active == $index"' +
                    ' ms-class-ui-state-active="active == $index"' +
                    ' ms-' + options.event + '="activate"' +
                    ' ms-hover="ui-state-hover"' + // float: left; margin: 0.4em 0.2em 0 0; cursor: pointer;这样jquery ui没有封装进去
                    ' >{{tab|html}}';
            var panels = '
     +
                    ' ms-class-ui-corner-bottom="!bottom"' +
                    ' ms-visible="active == $index" >{{panel|html}}
    ';
            //4 构建组建的ViewModel
            var model = avalon.define(id, function(vm) {
                vm.active = options.active;
                vm.collapsible = options.collapsible;
                vm.tabs = tabs;
                vm.tabpanels = tabpanels;
                vm.removable = options.removable;
                vm.activate = function(e) {
                    e.preventDefault();
                    vm.active = this.$scope.$index;
                };
                vm.remove = function(e) {
                    e.preventDefault();
                    var index = this.$scope.$index;
                    vm.tabs.removeAt(index);
                    vm.tabpanels.removeAt(index);
                    avalon.nextTick(function() {
                        vm.active = 0;
                    });
                };
                vm.bottom = options.bottom;
            });
             
            avalon.nextTick(function() {
                //5 当这一波扫描过来,再将组建的DOM结构插入DOM树,并绑定ms-*属性,然后开始扫描
                element.innerHTML = options.bottom ? panels + tablist : tablist + panels;
                element.setAttribute("ms-class-ui-tabs-collapsible", "collapsible");
                element.setAttribute("ms-class-tabs-bottom", "bottom");
                avalon.scan(element, model);
            });
            return model;
        };
    })(window.avalon);

    它基本分为五个步骤,首先怎么也有5个参数给你传过来,element为绑定了ms-ui的元素节点,id为data-id的值,没有框架为你随机生成一个,opts,这个是ms-ui-optsName="uiName"的一个参数,opts就是框架在众多ViewModel通过hasOwnerProperty操作分别出来的参数对象。然后第一步,就是设置配置对象,它由defaults + opts + $element.data()组成,制定性应该非常强与灵活。

    第二步,将element元素的内部节点进行处理,有时它们也有绑定属性,但我们不需要立即处理它们——扫描器是从上到下扫描,扫描过后来移除它们,因此阻止它们此时被扫描到——最好方法是将它们移出DOM树。这个过程可能还要做些操作,随你喜欢。

    第三步,编写UI的HTML结构。

    第四步,定义ViewModel,这时它的ID为我们上面的传参。

    第五步,重新开始扫描,但这时,我们不需要整个页面都扫描了,只从这个元素开始就行。

    有关这个tabs的示例可到这里查看。

    这里有两个重点,一个是扫描。扫描总是从上到下,从左到右,想让它不被扫描,有三个办法,ms-skip,这几乎是永久性的,ms-important,只有ViewModel匹配才进行此区域,最后一个是移出DOM树。扫描不但是为了转换绑定,还起到存储这些关键节点的作用(竟然这些节点做了绑定,说明要通过JS处理,而在以前这些都是通过选择器引擎来做,但一般的jQueryer很少自觉将它们缓存起来,每次用到时都重新选择,不断地遍历DOM树)。第二个是UI组件的ViewModel的构建,它是我们远离DOM编程的关键。它拥有所有关键参数与方法,相当于后端的XML配置文件。当然你也可以什么也不做,defaults其实已经调试好一切了。

     
     
     
    标签: Javascript
    推荐阅读
    • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
    • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
    • Nginx使用(server参数配置)
      本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
    • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
    • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
    • 从零基础到精通的前台学习路线
      随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
    • 如何实现JDK版本的切换功能,解决开发环境冲突问题
      本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
    • android listview OnItemClickListener失效原因
      最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
    • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
    • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
      本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
    • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
      本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
    • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
    • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
      转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
    • 猜字母游戏
      猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
    • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
      本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
    author-avatar
    一恒谢永泰_661
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有