zoukankan      html  css  js  c++  java
  • 从Dojo1.6到Dojo1.8(三)—— Parser,Dijit,DojoX

    前面两篇文章介绍了Dojo1.8的AMD以及Dojo core当中相关模块的变化。接下来我们介绍一下Dijit,Dojox这两个控件组件模块的变化。

    Parser

    在具体讲Dijit之前,我们先了解一下dojo/Parser模块,这个模块由原先dojo.parser转变而来。dojo对于控件的使用提供了编程式(programmatic)和声明式(declarative markup)两种方式。dojo/parser是用来翻译声明式的控件定义,并将它们渲染成控件的实例对象和控件相应的dom节点。

    对于dojo/parser的调用方式如下:

    require(["dojo/parser", "dojo/ready"], function(parser, ready){
      ready(function(){
        parser.parse();
      });
    });

    尽管在dojoConfig中依然可以写parseOnLoad:true的配置,但是还是需要手动去require parser模块。所以代码段中的方式是推荐的方式。

    在dojo/parser内部最大的变化是增强了对于符合HTML5规范的属性的支持。具体的举例如dojoType被改成data-dojo-type,对于控件属性的定义,也被统一放到data-dojo-props属性中。这种方式符合HTML5的属性定义规范。举例老的写法:

    <button dojoType="dijit.form.Button" tabIndex=2
        iconClass="checkmark">OK</button>

    新的写法将是:

    <button data-dojo-type="dijit/form/Button" tabIndex=2
        data-dojo-props="iconClass: 'checkmark'">OK</button>

    上面代码中的dijit/form/Button,替换了之前的dijit.form.Button,使用的是模块ID(MID),这也是我们之前在AMD的章节中讨论过的新写法。

    这里需要注意的是,在使用某个MID之前,需要在require([...])调用中加载相应的模块,一般在<head>节点中,这样可以保证<body>中需要使用的控件都已经加载。

    dijit widget

    在1.8中,dijit包中的控件也遵循了新的模块方式的写法,即原先所有的全局的diji.*都被放到了各自相应的模块当中。如dijit.form.Button,现在为dijit/form/Button模块。

    其实在dijit的这些变化当中,最先引起我注意的是dijit.byId()这个函数的变化。如今的dijit.byId()被移到了dijit/registry模块当中,相应的调用改成了registry.byId()。相应的dijit.byNode()也成了registry.byNode()。

    下面我们具体介绍一下在dijit内部的一些机制和函数发生的变化,这些使我们在使用、扩展尤其是写自己的控件的时候需要注意的。

    dojo/Stateful和dojo/Evented

    在这里首先要引入在扩展或创建dijit时需要理解的两个比较重要的模块:dojo/Stateful和dojo/Evented。

    dojo.Stateful提供了访问控件属性的统一接口:set()和get(),同时还提供了监测(watch)控件属性的能力。例如,你可以使用如下的代码:

    require(["dijit/form/Button", "dojo/domReady!"], function(Button){
      var button = new Button({
        label: "A label"
      }, "someNode");
     
      // Sets up a watch on button.label
      var handle = button.watch("label", function(attr, oldValue, newValue){
        console.log("button." + attr + " changed from '" + oldValue + "' to '" + newValue + "'");
      });
     
      // Gets the current label
      var label = button.get("label");
      console.log("button's current label: " + label);
     
      // This changes the value and should call the watch
      button.set("label", "A different label");
     
      // This will stop watching button.label
      handle.unwatch();
     
      button.set("label", "Even more different");
    });

    dojo/Evented的on()和emit()方法提供了事件监听和触发的功能。你可以有一下的写法:

    define(["dojo/Evented", "dojo/_base/declare"], function(Evented, declare){
      var MyComponent = declare([Evented], {
        startup: function(){
          // once we are done with startup, fire the "ready" event
          this.emit("ready", {});
        }
      });
    
      component = new MyComponent();
      component.on("ready", function(){
        // this will be called when the "ready" event is emitted
        // ...
      });
      component.startup();
    });

    on()方法被dijit引入用来做事件的绑定,后面会具体谈。

    set(),get()

    dojo1.6之前的版本,对于控件属性的获取使用的是getValue(),setValue(),或者attr()方法。而现在使用的是统一的get()和set()方法。如下:

    //老的写法
    myEditor.getValue()
    myTextBox.attr("value")
    myForm.setValue(...);
    
    //新的写法
    myEditor.get("value")
    myTextBox.get("value")
    myForm.set("value", ...);

    watch(), on()

    1.6及之前版本我们只能通过dojo.connect/this.connect来监测某些事件的发生,而1.8可以以更加优雅的方式来监测某些属性的变化或者方法的调用。使用的方法是on()和watch().

    //老的写法:
    dojo.connect(myForm, "onValidStateChange", function(){ ... });
    dojo.connect(myButton, "onClick", clickCallback);
    
    //新的写法
    myForm.watch("valid", function(name, oldVal, newVal){
      console.log(myForm.id + ": " + name + " changed from " +
      oldVal + " to " + newVal);
    });
    myButton.on("click", clickCallback);

    基于模版的控件(Templated Widgets)

    在1.6版本中的dijit._Templated被划分到了dijit/_TemplatedMixin和dijit/_WidgetsInTemplatedMixin两个模块。此外,dojoAttachPoint和dojoAttachEvent两个属性和事件的绑定也被改成了HTML5的形式:data-dojo-attach-point和data-dojo-attach-event。举例来说:

    dojo.require("dojo.declare");
    dojo.require("dijit._Widget");
    dojo.require("dijit._Templated");
    
    dojo.declare("SimpleTemplate", [dijit._Widget, dijit._Templated], {
      templateString: "<button><span dojoAttachPoint="label"></span></button>"
    });

    新的写法:

    require(["dojo/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin"],
    function(declare, _WidgetBase, _TemplatedMixin){
      declare("SimpleTemplate", [_WidgetBase, _TemplatedMixin], {
        templateString: "<button><span data-dojo-attach-point="label"></span></button>"
      });
    });

    如果widget的template中包含其他的widget,需要使用_WidgetInTemplateMixin。

    对于template文件的引用也发生了变化,不在支持templatePath,dojo.cache()也不再使用。

    老的写法中对template的引用,会使用下面的写法:

    templatePath: dojo.moduleUrl("templates", "myTemplate.html")

    而在新的控件定义中:

    define([..., "dojo/text!./templates/myTemplate.html",
    function(..., myTemplate){
      ...
      templateString: myTemplate

    另一个改变是控件中的waiRole和waiState属性不再支持,因为在现在的方式中可以更加直接的使用role和state属性。(查了一下,dojo的wai是跟accessbility resource相关的接口,大家可以Dijit Accessibility Resources这篇文章中去参考)。

    this.connect(),this.subscribe(),this._supportingWidgets

    这几个方法用来绑定控件的DOM元素事件或者某个内部方法被调用,_supportingWidgets用来注册创建或者改变过的内部控件。这些本来都可以由dojo的基本事件来完成,如dojo.connect(),dojo.subscribe(),这里以this的方式来调用,主要是将这些事件绑定记录在控件内部,从而在控件被销毁的时候,释放和销毁这些事件的绑定,以避免内存泄漏的发生。

    在1.8中,这几个方法不再被使用,取而代之的是this.own()函数来记录所有的这些内部的事件和控件。而事件绑定的函数则使用dojo标准模块中的接口如dojo/on,dojo/aspect,dojo/tpoic等。this.own()可以被多次调用,每次可以包含多个事件绑定或者控件的创建。这些被this.own()注册的事件绑定和控件会在控件被销毁的时候一起被释放和销毁。下面是一个可能的使用场景:

    this.own(
      // setup an event handler (automatically remove() when I'm destroyed)
      on(this.domNode, "click", function(){ ... }),
    
      // watch external object (automatically unwatch() when I'm destroyed)
      aStatefulObject.watch("x", function(name, oVal, nVal){ ... }),
    
      // create a supporting (internal) widget, to be destroyed when I'm destroyed
      new MySupportingWidget(...)
    );

    DojoX

    1.8中DojoX还是作为dojo包的一部分发布出来,但是到2.0的时候,DojoX的模块将被冲标准dojo包中移除。原先DojoX中的功能,有一部分将被移到Dojo和Dijit包中,还有一些将被放到另外的包当中。用户可以通过一些包管理工具从repository中获取。

    关于让我欢喜让我忧的Dojo Grid,将由新一代的GridX替代。GridX的架构完全不同于DataGrid和EnhancedGrid,它采用模块化的方式组织起来,提供了更加简洁和直接的接口,更加灵活和精简。尽管我没有用过GridX,但希望它能够在功能和性能上都有更好的表现。

    说实话,看到DojoX的这个变化我也有点吃惊,不过鉴于DojoX中的控件一直不是很稳定,而模块化轻量化也是现在前台框架发展的趋势,所以Dojo的这一动作也在情理之中。只是现在正在使用DojoX的朋友门要尽早做打算了,如果要升级到2.0的话还是会有很多的工作要做。正在准备使用1.8的朋友也要有一定的超前仪式,尽量避免对DojoX的过度依赖。使用AMD加载而不再使用dojox全局变量是必须要遵循的原则。

    总结

     好了,到这里我的这篇《从Dojo1.6到Dojo1.8》的系列文章(或翻译)终于介绍完了,希望能对关注Dojo的同学有所帮助,也希望能看到大家的评论和意见。

    让我们一起期待Dojo2.0的发布吧,相信那会是Dojo新的春天!

  • 相关阅读:
    定时器
    表单事件
    闭包,string类,Array类
    构造函数,原型链补充
    Elasticsearch安装(6.4.3版)
    快速配置ssh免密登录
    idea远程debug SpringBoot项目
    java获取一个对象的内存大小
    nginx代理其他网站
    外呼系统实现平均分配策略的实现方式之一
  • 原文地址:https://www.cnblogs.com/owenChen/p/2831311.html
Copyright © 2011-2022 走看看