Dojo 1.7做为变化重大的一个版本,已经Release近两个月,而如今已经放出了1.7.2的小版本更新,包括了一些小的fix。让人难以理解的是即便Dojo 1.7已经Release这么久,可是其release notes至今仍然是draft状态。。这也致使了迟迟不能对它进行翻译。看来Dojo社区的那帮老大彻底是技术狂,对于文档和社区其余用户的关注还远远不够啊,须要改进。。javascript
尽管Release notes仍然是草稿状态,但也算相对完整,包括了对重要更新的介绍,以及一小部分的升级指南。因而咱们对其进行了翻译,但愿能帮助你们尽快了解Dojo1.7的新特性,重点关注依然是:AMD。咱们同时会保持对英文版release notes的同步更新,你们也能够关注咱们的新浪微博:http://weibo.com/dojotoolkit 来得到最新进展。html
浏览器支持
通过有效的测试,Dojo1.7支持全部下面列出的浏览器。即便某个浏览器不在列表中,也有多是支持的,尤为是那些快速release的浏览器(好比Chrome,Firefox)。另外再随后的一些小的release中,Dojo可能会包含一些针对最新浏览器的修复,可是并不必定能保证。
桌面系统
- Firefox 3.6-8
- Safari 5.0-5.1
- Chrome 13-15
- IE 6-9
- Opera 10.50-11.50
- Mobile (dojox/mobile)
iOS 4.x, 5.0 (Mobile Safari) (including all Dijit widgets except Editor, Dialog)
- Android 2.2, 2.3, 3.1
- Blackberry 6
- Mobile compatibility on desktop browsers: IE 8-9, Firefox 3.6-7, Safari 5.0-5.1, Chrome 13-15
基本功能
Dojo Base
AMD
Dojo如今彻底支持AMD模块的异步加载,而且同步或者异步加载是能够经过“async”属性进行配置的。
- <script data-dojo-config="async: true" src="dojo.js"></script>
<script data-dojo-config="async: true" src="dojo.js"></script>注意之前被强制加载的模块,如今在异步模式下会被隐含加载。须要确保在require()的参数列表里列出全部模块中须要使用的其余依赖模块(包括再parseOnLoad设为true时须要引入dojo/parser)。好比:
- <script src="/dojo/dojo.js"
- data-dojo-config="parseOnLoad: true, async: true"></script>
-
- <script>
- require([
- "dojo/dom", // needed for dojo.byId
- "dijit/registry", // needed for dijit.byId
- "dojo/parser", // needed for parseOnLoad to run
- ...
- ], function(dom, registry, parser){
- // callback when above modules finish loading
- function update(){
- var viewNode = dom.byId("view1");
- var view1 = registry.byId("view1");
- view1.domNode.innerHTML = "...";
- }
- });
-
- </script>
<script src="/dojo/dojo.js" data-dojo-config="parseOnLoad: true, async: true"></script> <script> require([ "dojo/dom", // needed for dojo.byId "dijit/registry", // needed for dijit.byId "dojo/parser", // needed for parseOnLoad to run ... ], function(dom, registry, parser){ // callback when above modules finish loading function update(){ var viewNode = dom.byId("view1"); var view1 = registry.byId("view1"); view1.domNode.innerHTML = "..."; } }); </script>注意,许多Dojo核心和dijit中的模块都在1.7中拆分红更小的模块,以便再异步加载的状况下能支持轻量级的应用。另外,做为这项改动的一部分,Dojo核心中的模块尚未被完美拆分,这项工做将在1.8中继续进行。
Limitations
一些局限性
某些已有的Dojo 1.7以前的模块被设计成只支持同步加载模式。这些模块经过使用同步模式能够继续使用,但若是将async设置为true,即异步模式,则没法工做。Dojo社区正在研究一些可能的控件替换,使得这些功能可以无缺的支持异步模式。这是Dojo 2.0以前的工做。
DTL (dojox.dtl - Django Templating):
dojox.dtl就是一个例子,它的设计以同步加载为前提。但这个模块已经被重构以支持异步的AMD加载,可是全部的tag和filter的类库须要被显示的引入。这个限制对于在用户定义的类库和dojox.dtl的默认类库都是同样的。
下面的表格列出了内置的tag和它们对应的模块:
Tag Library |
Tags |
dojox/dtl/tag/date |
now |
dojox/dtl/tag/logic |
if, for, ifequal, ifnotequal |
dojox/dtl/tag/loader |
extends, block, include, load, ssi |
dojox/dtl/tag/misc |
comment, debug, filter, firstof, spaceless, templatetag, widthratio, with |
dojox/dtl/tag/loop |
cycle, ifchanged, regroup |
举个例子,若是一个模版使用"{% for" 标签, 那么 'require("dojox/dtl/tag/logic")' 就必须经过应用来加载,从而使得“for”标签可以运行。node
下面的表格列出了内置的filter和它们对应的模块:git
Filter Library |
Filters |
dojox/dtl/filter/dates |
date, time, timesince, timeuntil |
dojox/dtl/filter/htmlstrings |
linebreaks, linebreaksbr, removetags, striptags |
dojox/dtl/filter/integers |
add, get_digit |
dojox/dtl/filter/lists |
dictsort, dictsortreversed, first, join, length, length_is, random, slice, unordered_list |
dojox/dtl/filter/logic |
default, default_if_none, divisibleby, yesno |
dojox/dtl/filter/misc |
filesizeformat, pluralize, phone2numeric, pprint |
dojox/dtl/filter/strings |
addslashes, capfirst, center, cut, fix_ampersands, floatformat, iriencode, linenumbers, ljust, lower, make_list, rjust, slugify, stringformat, title, truncatewords, truncatewords_html, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap |
has.js
Dojo 1.7 引入了一个称之为has()的特性检测API。大多数Dojo核心和dijit模块已经被转换为使用这些特性检查。这项工做将继续在1.8中进行。
dojo.connect
This has been refactored to use the new dojo/on module for event handling. See dojo/on below for more information.
这个API已经被重构为新的dojo/on模块以用于事件处理。参见下面对dojo/on的介绍。
dojo/on
这个新模块提供了一套新的事件处理系统,包含以下的新功能:
- 事件代理: 事件类型能够包含元素选择符来指定特定的触发对象,例如:on(list, "li:click", onListItemClickHandler);
- 扩展事件:可以建立并使用自定义事件类型做为扩展事件。新的dojox.gesture.*实现了一些扩展事件。
- 可暂停事件:事件处理能够经过on.pausable暂停。
- 单次执行事件:经过on.once使监听函数仅被调用一次。
- (手动)发射事件:浏览器内置事件能够用on.emit(target, "click", event);来(手动)触发。
- 自包含的事件处理对象:on()调用返回的对象包含remove()方法,可直接用于中止对该事件的监听。
- 触摸事件的标准化:触摸事件实现了跨平台(Android,iOS)的标准化。
- 基于has()的功能检测:这使得为特定浏览器打包(移除该浏览器不须要的功能,例如一些针对IE的特殊代码)成为可能。
这个模块去除了一些遗留的键盘事件处理代码(最好使用keydown事件),所以减小了代码量。
这个API计划在Dojo2.0中代替现存的dojo.connect函数。针对非DOM事件所传的参数与事件名称在Dojo2.0中会有改变,所以目前Dojo1.x的应用若是使用dojo.connect连接了非DOM事件,就不该迁移到dojo/on,以避免在未来受到影响。
dojo/query
这个新模块提供了查询DOM结点的功能(相似于dojo.query)。该模块还能加载其余的选择符引擎,例如Sizzle、Slick、Dojo新的轻量级查询选择符引擎、甚至是浏览器内置的选择符查询引擎(但其CSS兼容性最差)。在异步模式下(参见新的Dojo config设置),当dojo/main没有加载时,dojo/query将载入一个采用浏览器自带的qeurySelectAll方法的轻量级引擎,而且只在须要的时候加载完整的acme选择符引擎。dojo/query采用了新的has()方法作功能检测,以便在针对特定浏览器打包时只加载该浏览器所需的最小的选择符引擎。
dojo/data/ObjectStore
若是底层的object store是"Observable"的,这个模块如今将广播该store所产生的全部通知。若是底层的object store在返回结果(results)上有一个observe()方法(一般是用dojo.store.Observable包装),那么dojo/data/ObjectStore就会监听object store中发生的变化,并发送出dojo.data通知事件。
Parser(解析器)
Dojo的页面解析器在新版本中获得了进一步加强。如今您能够区分浏览器自带的捏制属性和Dojo对象的属性,将内置属性直接写在html标签中,而将Dojo对象属性都写到data-dojo-props属性里,例如:
- <input data-dojo-type="dijit.form.TextBox" name="dept" data-dojo-props="scrollOnFocus: true"/>
<input data-dojo-type="dijit.form.TextBox" name="dept" data-dojo-props="scrollOnFocus: true"/>
解析器还支持声明方式建立dojo.on和object.watch的监听函数。方法是加入type="dojo/on"或type="dojo/watch"的<script>标签。下面是一个type="dojo/on"的例子:
- <button data-dojo-type="dijit.form.Button">
- Click Me!
- <script type="dojo/on" data-dojo-event="click" data-dojo-args="e">console.log("I was clicked!");</script>
- </button>
<button data-dojo-type="dijit.form.Button"> Click Me! <script type="dojo/on" data-dojo-event="click" data-dojo-args="e">console.log("I was clicked!");</script> </button>
一个type="dojo/watch"的例子(基于dojo/on):
- <button data-dojo-type="dijit.form.Button">Click Me!
- <script type="dojo/on" data-dojo-event="click" data-dojo-args="e">
- dijit.byId("textBox1").set("value", "New Value!");
- </script>
- </button>
- <div data-dojo-type="dijit.form.TextBox" id="textBox1" data-dojo-props="value: 'Old Value'">
- <script type="dojo/watch" data-dojo-prop="value" data-dojo-args="prop,oldValue,newValue">
- console.log("Prop '"+prop+"' was '"+oldValue+"' and is now '"+newValue+"'");
- </script>
- </div>
<button data-dojo-type="dijit.form.Button">Click Me! <script type="dojo/on" data-dojo-event="click" data-dojo-args="e"> dijit.byId("textBox1").set("value", "New Value!"); </script> </button> <div data-dojo-type="dijit.form.TextBox" id="textBox1" data-dojo-props="value: 'Old Value'"> <script type="dojo/watch" data-dojo-prop="value" data-dojo-args="prop,oldValue,newValue"> console.log("Prop '"+prop+"' was '"+oldValue+"' and is now '"+newValue+"'"); </script> </div>
注意:
目前再也不支持type="dojo/watch"的<script>标签的prop属性,解析器只能识别data-dojo-prop属性。
提醒:
当使用异步模式时,您须要显示地加载dojo/parser模块以确保parseOnLoad: true可以生效。(在非异步模式下,dojo/parser将会自动加载,但会出现一条“不推荐”警告。从技术角度而言,dojo/parser是不被自动加载的,但在1.7以前,它在许多状况下都会被自动加载,这是由于dijit/_Templated依赖于它,而许多widget都依赖dijit/_Templated。
dojo/touch
这个模块提供了一组统一的触摸事件:"press | move | release | cancel"。这些事件可以兼容大量设备(包括桌面设备)。
其原理很是简单,"press | move | release | cancel"分别对应于:
所以有了dojo/touch,咱们在切换设备平台时就再也不须要关心如何正确设置各类内置事件了。
dojo/touch基于
dojo/on ,下面的示例在桌面环境和触摸屏设备(包括Android 2.2/2.3以及针对1.7的iOS3+)上都能正常工做:
针对桌面浏览器的开发的Web应用常常在手机浏览器上运行失败。为避免这种状况,Dojo从1.7开始,除了Editor控件之外的dijit控件增长了对主流手机平台(苹果、安卓以及黑莓)的基本支持。
另外,在手机平台上运行Dialog控件时,必须把draggable参数设为false,以确保Dialog的关闭图标工做正常。将在将来的版本中修复这个bug。
_WidgetBase
_WidgetBase类添加了getParent()方法,可使用该方法获得当前控件的父容器控件,不论父控件是否有isContainer标记。同时isContainer标记已被废弃。
_TemplatedMixin, _WidgetsInTemplateMixin
新增了两个粒度更小的模板聚合类:_TemplatedMixin和_WidgetsInTemplatedMixin。在控件模板内部不包含其余控件时,使用_TemplatedMixin做为控件的模板类;若是空间模板内部包含控件时,除使用_TemplatedMixin外,还要添加_WidgetsInTemplateMixin做为控件的模板类。原先的模板类_Templated功能以及接口保持不变。
_setXXXAttr
_setXXXAttr方法做为函数在以前的版本能够设置对象属性,或者触发设置属性时要被执行的逻辑。在新版本中_setXXXAttr还能被做为单纯的对象使用,如下举例说明:1._setTabIndexAttr: "focusNode"
该语句会把对象tabIndex属性直接添加到控件的focusNode上:this.focusNode.tabIndex;
2._setTitleAttr: { node: "titleNode", type: "innerHTML" }
该语句会使用title属性对控件的titleNode.innerHTML进行赋值,如myWidget.set(“title”, “hello world”)会给myWidget的titleNode.innerHTML赋为hello world。
这样就替换了本来的attributeMap的功能,attributeMap参数已被废弃并将在2.0版本中删除。
dijit/focus, dijit/place, and dijit/popup
focus、place以及popup三个模块从dijit/_base移到了dijit目录下,因此这三个模块都不会在加载dijit时默认加载。也就是说,控件可根据须要选择性的加载这三个模块,避免增长没必要要的代码。
There are a few API changes in the top level modules compared to the ones in dijit/_base (although for backwards compatibility the modules in dijit/_base maintain their old API):
做为可独立加载的模块,focus、place以及popup中的方法也作了相应的修改:
• popup.around()替换了dijit.popup.placeAroundElement(),同时参数也从{BL:”TL”,…}变为更人性化的[“before”,”after”,…];
• dijit/focus再也不包含选择(selection)相关的代码,只包含focus相关代码;
• dijit/focus提供了watch()和on()方法以检测控件的得到焦点事件;
• dijit/_base/popup中一些原先可接受节点或控件做为参数的方法,在新版本中只接受控件参数。
另外,dijit/popup模块只能经过新的AMD API加载,如:
require(["dijit/popup"], function(popup){ popup.open(...); });
CalendarLite
dijit.CalendarLite是针对手机平台开发的新日历控件。其基本功能与Calendar相同,不过不支持键盘操做,也不包含月份下拉列表。
ComboBox, FilteringSelect
ComboBox和FilteringSelect为应用dojo.store(新的数据读写接口)作了相应的修改,同时依然支持旧的dojo.data 接口。
图表 (Charting)
Action2d 包已经包括了新的缩放(Zoom)和摇摆(Pan)功能,以及数据指示和交互功能。它们使得用户能用鼠标或者触摸手势来与图表进行交互。
在移动设备方面采用各类方法类提升性能。大多数图表类型都支持新的容许缓存参数,可以容许缓存和重用gfx图形。
使用AMD模块格式
经过两个BidiSupport类来支持图表的双向文字.(一个类用于dojox.charting, 一个类用于dojox.charting.widget) 在程序中为了支持双向文字必须请求这些类。
仪表 (Gauges)
仪表从原来位于dojox.widget移动到了新的命名空间dojox.guages
加入了几种新的指示器来用于建立用户本身的仪表,例如文字指示器可用于以文字的形式绘出仪表的刻度值。
建立圆形仪表时可以选择顺时针或者逆时针走向。
改进了圆形刻度的标签布局
仪表如今可以支持在移动设备上的触摸交互
Dojox.gauges使用AMD 模块格式
能够直接得到三种的新内建仪表:GlossyHorizontalGuage, GlossyCircularGauge和GlossySemiCircularGauge
地图 (GeoCharting Map)
Dojox.geo.charting模块实现了多种改进:包括tooltip管理,当更改数据列时模拟颜色变化
提供新的数据源结构,以及地图元素和数据源元素之间的数据绑定
经过安装专门的交互类,容许交互式的经过鼠标或者触摸手势来对地图进行缩放和摇摆
经过新的地图 Dijit控件将非dijit dojox.geo.charting 地图控件封装,从而实现更轻松的整合
使用AMD模块格式
Gfx
如今每一个形状都由一个关联的惟一的id(Shape.getUID())来标识. 此外,新的dojox.gfx.shape.byId() 函数将返回与此形状关联的id。
添加了输入事件来支持画布提供者。这个功能缺省是打开的,能够经过设置dojoConfig中的“canvasEvents”标志来关闭之。
鼠标事件指向的Gfx形状能够经过事件自己的“gfxTarget”属性来获取:
group.connect("onmousedown", function(evt){ var s = evt.gfxTarget; ... });
Gesture
基于dojo/touch和dojo/on,这个新的模块提供了一种机制,让咱们能够实现能良好运行在不一样的设备上的手势行为,包括桌面和各类各样的可触摸设备。
dojox/gesture/Base
一个用于实现各类手势行为的抽象基类,它主要用于:
• 绑定 on() 监听器用于处理手势事件,如tap, taphold, doubletap
• 监听底层事件并执行不一样阶段动做 - 'press'|'move'|'release'|'cancel'
• 基于on() 接口触发手势事件
实现一个手势动做只须要扩展和覆写适当阶段的处理函数便可 - press() | move() | release() | cancel() 用于识别和触发手势
dojox/gesture/tap(只适用于单触摸)
• 提供公共的tap手势方式,包括tap, tap.hold and tap.doubletap
• 用户可配置 e.g. Tap.hold的阈值, tap.doubletap有效半径
dojox/gesture/swipe(只适用于单触摸)
• 提供公共的swipe手势方式,包括swipe, swipe.end
touch & gesture demo 展现了基于dojo/touch 和dojox/gesture.的dijit/form/HorizontalSlider 控件和dojo/dnd 是如何运行在 iOS4+ 的操做系统上的。 除了一个tap手势, 这个示例也展现了基于多触摸实现一个新的旋转的手势是很是容易的。
更多详细信息请参考 dojox/gesture doc .
Grid
DataGrid/EnhancedGrid/TreeGrid/LazyTreeGrid
• 1.7 修复的大量的缺陷和问题, 更多详细信息请参考 defect list
下一代Grid
• 进行中的项目:dgrid 和 gridx 正密切合做,目标下一代Grid
Mobile
Dojo Mobile 是目前市场上一流的移动web开发库, 支持AMD加载方式和新的Build模式,如今有一个专门为Dojo移动开发库制定的新的指导手册和详细的API文档Dojo Mobile Reference Guide
• 加入了新的BlackBerry OS6 皮肤,迄今为止,已支持以上列表中全部的移动设备和操做系统。
• dojox.mobile.deviceTheme是一个皮肤加载器,他会识别访问的设备并加载相应合适的皮肤。
• 新的SpinWheel控件让你能够经过该控件设置和选择相应的值,支持两种方式:SpinWheelDatePicker 和SpinWheelTimePicker,
• 新的卡盘(Carousel)控件,他会显示一个图像列表,用户能够从中选择相应的元素。
• 新的RoundRectDataList 和EdgeToEdgeDataList 控件,他们基于RoundRectList 和EdgeToEdgeList控件,支持数据驱动。
• 新的PageIndicator控件,他会显示当前的页号,并配合以小圆点。该控件能够和 SwapView 或者Carousel合用。
• 加入了一些新的动画效果: Dissolve, Flip2, Cover, Reveal, Slide Vertical, Cover Vertical, Reveal Vertical, Swirl, Zoom In/Out, and Scale In/Out.
• 将FlippableView 控件改名为SwapView.
• dojox.mobile 如今均基于 AMD 模式
• TextBox 控件从原来的 mobile/app/ 包下面移动到 mobile/包下面。
• 新的Tooltip 控件会弹出一个容器,该容器可包含简单文本或另外一个新的控件。
• 新的Overlay控件从下方滑入,完成后则向下方滑出。
• 新的Opener控件加入了实时的屏幕大小侦测器,并配合以使用Tooltip控件(针对大屏的移动设备)和Overlay 控件(针对小屏的移动设备)。
• 新的ComboBox 控件(实验阶段) 支持文字搜索(同dijit.form.ComboBox)
• 新的ExpandingTextarea 控件支持纵向的基于文字内容的伸展和收缩。
• 新的Slider 控件使用户可以很方便的经过触摸/手势来控制其值。
• 新的HTML 表单控件包装器 (Textarea, CheckBox, RadioButton) 使得表单能够和各类dijit的控件联合使用,如:container/dialog 等等控件.
Limitations:
• 不少动画效果是基于CSS 3 transition / animation的,而且他们的行为依赖于具体的移动设备和移动浏览器,因此有些动画效果在 Android 和BlackBerry等移动设备上并非很流畅。
• ScrollableView 在HTC Android设备上常常会被“冻死”, 如:HTC Evo, HTC Desire,等等,尤为是当你在屏幕已经在滑动的同时,进行另一个滑动操做。这是JavaScript 的一个缺陷,目前尚未好的解决方案。
• 在Android设备上,当你经过触摸的方式试图选中ScrollableView中一个表单中的一个输入框或者按钮时,会发现有时没法让该控件获取焦点,可能你须要多试几回才行。
MVC
dojox.mvc 是一个新的实验性质的dojox 项目,基于MVC的思想,实现Client段的Model,Control和View三层的分离,使得基于Dojo开发诸如企业级应用,IT应用,CRUD 应用,主从模式应用等等的复杂应用变得更为简单。这个release包括:
• 一流的数据模型,能与data stores直接交互
• 能让控件或者可视化组件绑定到数据模型的数据绑定功能
• MVC 还包括分组(用于分级数据) 和重复(用于重复的数据,如:数组)
• 还有诸如 数据绑定输出和数据驱动的UI生成器的MVC控件
• 能够基于以上MVC模型构造出各类各样的富数据模式示例
OpenLayers Maps
• 新的dojox.geo.openlayers 工具包基于已开源的OpenLayers库,详细可 (参见 http://www.openlayers.org/ ).
• 用户可在以OpenLayers地图为背景的区域内添加添加 地图相关Gfx 形状或者控件.
• 基于AMD 的形式.
升级指南
加载器,构建器相关
<script>
在之前的版本中,能够经过<script>标签来加载模块(module)和layer, 例如
<script src="/mysite/app/MyWidget.js">尽管这种用法在1.7的构建后的build中依然有效,但将不推荐使用,而且在未构建的源代码版本中将没法使用,强制使用会致使程序出错同时控制台中会出现"multipleDefine" 错误。在这种状况下应使用dojo.require(), 例如
dojo.require("app.MyWidget");或者直接用最新的AMD的require() API全局变量
在之前的版本中,能够在一个模块中经过以下方式定义全局方法:
dojo.provide("my.module");
function myOnClick(){ ... }
而后在1.7中,全部模块都在一个封闭的方法中被解释(evaluated),上述的方法将只存在于对应的闭包(closure)中而非全局空间中。若是须要在模块中定义全局空间中的方法或变量,应使用dojo.global:
dojo.provide("my.module");dojo.global.myOnClick = function(){ ... }
关于定制压缩Build的注意事项
selectorEngine
值得注意的是acme 查询引擎(acme query engine) 默认将再也不包含在压缩后的dojo.js中,所以在dojo/query 或 Dojo base 加载时会致使额外的网络请求以获取。若是但愿将acme query engine包含到压缩后的dojo.js中,能够在build profile中定义selectorEngine: "acme" 或直接在build命令行中添加selectorEngine=acme 参数,也能够参考Dojo 1.7.1中自带的standard.profile.js
关于更多selector engines的信息,请参考dojo/query documentation.
dijit/_base
之前的版本中,在压缩时dijit/_base 会自动导入其所依赖的dijit/_Widget模块. 在1.7版本中dijit/_Widget模块只会在非AMD(向后兼容)模式中被导入。所以Dojo构建器再也不认为dijit/_base依赖于dijit/_Widget。
为了不可能额外的网络请求,建议在上述状况下将dijit/_Widget做为显示的依赖添加到build profile中。
跨域模式中使用本地模块 Dojo 1.7 有一个局限性,在非AMD向后兼容的模式下,跨域访问即dojo.js是从第三方域加载的轻快下,Dojo 没法加载使用非AMD即dojo.require形式的模块。目前惟一的办法是将本地模块改写成新的AMD语法,或者在这种状况下避免使用跨域访问,请参见 defect #14459. debugAtAllCosts 在1.7版本中,djConfig 中的debugAtAllCosts 参数将没法使用,可使用以下相应的方式替换: 将应用转成新的AMD语法并使用异步加载模式(async:true), 全部经过标准AMD加载的模块即可进行调试 经过运行压缩build, 将全部非AMD模块转成新的AMD 语法。 注意:在将应用转换正最新的AMD语法时可能会须要额外的时间例如来移除旧的API - dojo.getObject 等,尽管这可能会比直接压缩一个build费时,但将能得到1.7带来的全面改进特性。