ecomfe / esui Goto Github PK
View Code? Open in Web Editor NEWenterprise simple ui library
Home Page: https://ecomfe.github.io/esui-family/
enterprise simple ui library
Home Page: https://ecomfe.github.io/esui-family/
在控件的开发中,免不了要往main
元素上加事件,也免不了要在dispose()
的时候把这些事件去掉。
但是这里存在几个问题:
this
或者me
),这就必然导致事件的处理函数是一个在闭包内的函数(为了固定this
或能引用me
),也进一步导致,在取消这些事件的时候,容易找不回那个处理函数(因为在闭包里)不好取消。dispose()
的时候一一去掉,就要记住注册了哪些事件,用哪些处理函数,这些逻辑全部用代码来写而不抽象出来早晚会混乱。当然一个非常简单的方法,就是参考现在的controlHelper
模块,用onxxx
属性来挂事件,到时候只要onxxx = null;
就能去掉,但这不仅仅受到 一个事件只能注册一个函数 的限制,同时也只解决了问题1,没解决问题2。看看controlHelper
中的initMouseBehavior
和dispose
中的处理,并不是十分潇洒漂亮的形式,这也仅仅是限定地处理了鼠标相关的,有更多事件的话会更难管理。
因此,建议在控件上(事实上是controlHelper
模块)中添加一个专门负责main
对象上的事件处理,通过addDOMEvent
和removeDOMEvent
、clearDOMEvents
等方法来管理DOM事件,保证注册上就能去掉,而且在dispose()
的时候可以去干净。
如果大家认为确实可以有这样一个模块的话,我会负责实现之。
Button
- Control
"Button"
任何元素都可做为按钮的控件主元素。默认的控件主元素为button。
按钮的显示文字。不进行HTML过滤。
按钮的高度。
按钮的宽度。
设置按钮的显示文字。
参数:
设置按钮的高度。
参数:
设置按钮的高度。
参数:
当按钮被点击时触发。
事件对象成员:
虽然E-JSON中说明树的数据源结构应该是一个Object
,但是很多系统中的树,其实并不需要一个要,而是一个标题(<h3>
之类)下直接放一列的一级节点,形如:
*选择频道*
+ 其它频道
+ 频道1
- 频道2
- 子频道1
- 子频道2
- 子频道3
+ 频道3
很多时候,树的根节点并没有什么意义,第一层直接显示才是正常的。
因此,需要让Tree
控件的datasource
属性支持一个数组。
Calendar
- InputControl
- Control
日历控件包括一个日期显示框和一个弹出层形式的单月日历。
"Calendar"
控件主元素必须为div。
选中的日期,为Date类型的Javascript对象。
允许选择日期区间“range”的数据格式,以一个Object表示。该Object拥有name为begin和end的成员,分别为Date类型。
{
begin: new Date(1983, 8, 3),
end: new Date(2011, 10, 4)
}
日期显示的格式化方式。默认'yyyy-MM-dd'。
日期参数的格式化方式。默认'yyyy-MM-dd'。
可选中的日期区间。可选,默认
{
begin: new Date(1983, 8, 3),
end: new Date(2046, 10, 4)
}
当前选中的日期的原始数据。
获取当前选中的日期。
设置允许选中的日期区间。
参数:
支持字符串型,‘,’分割起始时间和结束时间。如:1983-09-03,2046-11-04。
通过日期格式,设置当前选中的日期。
参数:
当选择的日期发生改变时触发。
事件对象成员:
select calendar schedule 等都有onchange事件。
以前有讨论过,我的意见是data-ui属性中,类似style
属性写法的值,key和value都应该去掉前面的空格。
因为很多情况下会这么写:
<div data-ui="type: Panel; id: panel;"></div>
在冒号和分号后会习惯性地加一个空格,这也使得代码更清晰易读,因此应该在解析的时候去掉这空格。
对于 原本就故意想加空格 这样的需求,是否可以要求其车用data-ui-*
属性完成?
原定emptyText
是在 什么都没选择 的情况下显示的文字,但这里有几点比较奇怪:
Select
的交互过程中,只有刚渲染完会出现 什么都没选择 的情况,而为了保证后续还能回到这个状态,在下拉框中会保留一项<select>
元素是没这种东西的,默认选中第一项,由<option>
控制datasource
满足了emptyText
的需求,即有一个默认项,此时去不掉emptyText
的配置会很麻烦因此,建议把这个属性修改一下,新的描述如下:
emptyText
指定在datasource
之外,增加一个value
为空的选项的文字。如果此属性的值为空,则不增加额外的一项。额外的一项永远加在最前面。
据有关部门了解,这个属性是用来把Select
控件变成一个命令菜单用的。但其实命令菜单不应该是InputControl
,因此建议单独实现CommandMenu
控件,优势如下:
CommandMenu
只需{ text: handler }
或[ text ... ]
的配置,而不需要{ text: value }
的配置,因此两个控件的datasource
是不同的CommandMenu
没有随表单提交的需求,不会额外生成提交的参数Select
控件中大量逻辑在处理value
、rawValue
和selectedIndex
这三个属性的同步问题,而CommandMenu
不需要Select
处理同步已经有很大的负担,再额外增加staticText
复杂性会太高几个事情需要提一下:
Extension
是给业务人员用的,控件开发人员 不能使用 ,这就类似一个基础库的代码不能去依赖业务线的代码,这是一种强制性的设计理念。Table
中有用到Command
,虽然可能辛苦点,但希望Table
可以清理一下这一块的代码,写成标准的DOM事件。不然会导致不少的问题(比如在使用Table
的时候再配一个Command
扩展会冲突等)Command
在修发后,我发现当触发command
事件时,会带上两个参数:e
和element
,这两个参数全是 DOM相关 的,而ESUI的理念是 屏蔽全部DOM相关的逻辑 ,因此在ESUI体系下暴露的事件对象中让使用者可以访问到DOM是 不合理 的,现在由于Table
依赖着他,因此我还没去掉这些代码,希望清理Table
后可以去除Table
由于过于庞大,且最近事多,没来得及详细看一遍,后续我会尽量抽时间Review。
请 @wurongyao 关注一下
控件第一次渲染称为 渲染 ,已经渲染后因为属性的变化等导致的再次渲染(主要是setProperties
这方法)称为 重渲染 ,希望确定几个事:
afterrender
事件上注册main
的DOM事件,如果再次重渲染,这个DOM事件不应该再注册一次,因此建议是有区分的set
方法是否默认调用repaint
,我认为是不需要的,默认调用repaint
的方法应该通过setXxx
方法暴露出来。有时因为业务需要,想在控件上挂一点和控件本身没啥关系的数据,ESUI又不希望开发者直接挂属性,所以会用set
,这要是set
一次repaint()
一次,会很糟糕参考:http://fe.baidu.com/doc/ecom/std/ui/v1.1/tip.text
hideDelay
属性,控制消失的延迟时间,注意计时器不要混乱mode
属性,控制交互的事件show
和hide
事件另,建议增加:
showDelay
属性,当mode
值为over
时生效,不要鼠标路过就显示出来,默认值为100msarrow
为1或true等非字符串值,或者无arrow
时,自动根据空间判断放置的位置和箭头(可二期再做)title
和content
属性,避免在js中还要写HTML或者需要在模板中分离对应的内容的尴尬(可二期再做)请 @badplum 关注,尽快实现
createMain
接受参数options
,从参数中拿mode
等值render
方法,使用initStructure
来注册focus
、blur
等事件和其它逻辑setRawValue
,交由repaint
处理textarea
模式下不应该把enter
事件丢出去helper.addDOMEvent
,这样inputHandler
也不用挂上面了,dispose
方法可以去掉我们还是谁写的谁负责的原则,请 @errorrik 辛苦一下
几个问题:
disabled
状态,各控件在disabled
状态下的行为如何标准化,如Panel
控件如果有disabled
状态,则是否其子控件都进入disabled
状态?disabled
状态下,修改其属性是否重新渲染,如TextBox
在disabled
状态下调用setValue(value)
是否有效?readOnly
状态下,修改属性是否重新渲染?个人意见:
disabled
状态,但InputControl
一定会有。如Label
、Panel
、Dialog
这一些并不需要这样的状态。disabled
和readOnly
状态下均 正常进行 repaint
操作,这一点参考HTML的<input>
系控件。面包屑导航条是不少系统有的内容,但在业务级别上制作这个会有一些通用的东西可以抽取:
建议提供一个简单的Crumb
控件,接受一个数组作为数据源来绘制面包屑
保持功能原子性
在从HTML生成控件main.init
时,建议在生成控件后,为元素加上一个data-ui-id
属性,这个属性的值就是控件的id值。
分为以下3个情况:
data-ui
属性,里面有id的值,则再写回去也没问题data-ui-id
这个属性,控件自动生成一个id,后加上这个属性也没问题因此认为这么做没有副作用。
这么做的好处是:
ViewContext.prototype.get
去拿到并调试getControlFromElement
(虽然不希望这方法存在)可以更方便地找到对应的控件请 @errorrik 评估一下,OK的话我去加上
在ESUI中新加了painters
模块,该模块用于生产实现repaint
方法的对象,具体使用大致如下:
var paint = require('./painters');
XxxControl.prototype.repaint = require(./controlHelper').createRepaint(
paint.style('width'),
paint.html('content'),
{
name: 'personName',
paint: function (control, value) {
control.main.innerHTML = 'Hello ' + value;
}
}
);
大致描述过程可以总结为:
painters
模块painter
对象controlHelper.createRepaint
,以第2步创建的数组为参数,生成repaint
方法的实现一个painter
对象描述 使用什么方法渲染哪个属性 ,painter
对象是一个普通的javascript对象,但其必须有以下2个属性:
{string} name
:指定负责的属性名称,一个painter
对象只能负责一个属性{function(Control, *)} paint
:指定渲染该属性的方法,方法接受 控件的实例 和** 属性的值** 作为参数内置有以下painter
对象的生成函数(自己看源码更容易理解):
style({string} name, {string} property)
:将控件属性的值作为main
元素的样式,会自动加上px
html({string} name, {string} member, {function} generate)
:将属性的值作为某个类型为HTMLElement
的成员(默认为main
)的innerHTML
使用,可提供generate
方法指定如何生成HTMLtext({string} name, {string} member, {function} generate)
:将属性的值作为某个类型为HTMLElement
的成员(默认为main
)的innerText
使用,可提供generate
方法指定如何生成HTML,注意generate
方法生成的是HTML,不需要转义delegate({string} name, {string} member, {string} method)
:将更新委托给某个成员的某个方法,用于组合控件时如将title
转给titleLabel.setText
方法。以下是Select
控件的示例,Select
控件需要关注的属性有:
width
和height
影响到主元素的样式datasource
修改后,下拉弹层中的内容需要更新rawValue
修改后,需要更新和值相关的界面disabled
变成true时,如果已经打开了下拉层,则要关上实现如下:
/**
* 根据控件的值更新其视图
*
* @param {Select} select Select控件实例
* @inner
*/
function updateValue(select) {
// 同步`value`
var hidden = select.main.getElementsByTagName('input')[0];
hidden.value = select.rawValue;
// 同步显示的文字
var selectedItem = select.datasource[select.selectedIndex];
var displayText = selectedItem ? selectedItem.text : '';
var textHolder = select.main.getElementsByTagName('span')[0];
textHolder.innerHTML = require('./lib').encodeHTML(displayText);
}
var paint = require('./painters');
/**
* 重绘
*
* @param {Array=} 更新过的属性集合
* @protected
*/
Select.prototype.repaint = require('./controlHelper').createRepaint(
// 宽和高通过样式设定
paint.style('width'),
paint.style('height'),
// datasource更新后通过getLayerHTML生成selectionLayer的innerHTML,
// selectionLayer是延迟生成的,可能不存在,painter会自行处理
paint.html('datasource', 'selectionLayer', getLayerHTML),
// 禁用时关上弹层
{
name: 'disabled',
paint: function (select, value) {
if (value && select.selectionLayer) {
hideLayer(select);
}
}
},
// rawValue变化时,需要的逻辑有些复杂,且不通用,所以单独一个方法
{
name: 'rawValue',
paint: updateValue
}
);
为了更好地使用这套机制,框架层面有以下变化:
setProperties
方法添加返回值,将设置的值中有变化的部分返回,返回一个对象。对象的键是属性名,值为一个变更项,包含name
、oldValue
和newValue
属性。这一变更是为了子类可以调用父类setProperties
后知道哪些值有变化过,并触发如change
之类的事件。
repaint
现在有了2个参数,第2个参数是第一个参数的索引,没实际意义,只是实现了上面一点后这个毫无代价顺手就给了。
Select
的selectedIndex
和rawValue
,这种通常通过setProperties
里额外处理,去掉其中一个属性来实现。但是painter
是不是需要支持多个属性的管理,即多个属性更新一个或多个时,执行一次paint
几个意见:
appendTo
或render
,所以不需要继承InputControl
或Control
,是个辅助类就行了Form
控件,我建议在Form
控件中提供getInputControlsByName({string} name, {string=} type)
方法,不要再用getElementsByName
+ getControlFromElement
的结构了,维持更好的结构性请 @kitemao 参考,如果OK我去发动BoxGroup
和Form
需要一个高灵活性的实现,不同项目展示验证消息的方式大不一样。
建议:把showValidity
丢到InputControl.prototype
下去,helper
模块是不对外的,无法提供劫持的功能
问题:默认的实现怎么样的合适,在InputControl
后面插一个label
元素放内容?
请 @errorrik @DDDBear @kitemao @wurongyao 一起讨论下吧,现在各系统的验证显示是长啥样的?
Table
控件形如HTML中的<table>
元素,主要用于二维数据的展现。
- Control
- Table
Table
控件的主元素是一个<div>
元素。
表格体的宽度,单位为px。默认自适应内容宽度。
如果设置该值,则将按照该宽度绘制Table,而不再根据父容器大小自适应。
表格体的最大高度,单位为px。
表格内容是否允许断行。默认false。
控件的数据源,数据源中的每一个对象称为 数据项,对应到表格每行的显示数据 。
控件的不可用状态。默认false。处于不可用状态时,表格拖拽、排序、行选中等功能都将禁用。
表格是否允许拖拽改变列宽。默认true。
在滚动条纵向滚动时,是否表头跟随。默认false。
没有数据时,表格体中显示的html内容。默认null。
表格是否不显示标题。默认false。
设置表格的选择方式。single(单选)|multi(多选)。默认null。
设置表格的选择模式。line|box。默认box。如果设置了值为line,则点击行时触发选择。
表格是否允许排序。默认false,
表格是否允许子行。默认false,
表格子行是否互斥,也就是打开一子行其他子行是否需自动关闭。默认false,
表格的列配置。
初始化的参数中,fields是一个数组,作为表格显示的列设置。其中每一列的可选属性如下:
列内容的排序方式。left | center | right。 默认left。
列是否允许断行。默认应用控件breakLine属性。
每一行该列需要显示的内容。为Function时应用返回值。
Function的接口形式为 fn(item, index),item为每行对应数据项,index对应datasource数组序号。
该列是否允许拖拽改变列宽。默认true。
该列的字段名。主要用于可排序表格中的可排序字段。
该列的最小宽度。表格分配列宽时分配宽度不会小于设置的minWidth。
是否固定列。表格分配列宽时不会影响到固定列。默认false。
是否依据该列进行数据排序,默认false。
该列标题需要显示的内容。
该列标题需要显示的提示信息,当鼠标移动到表头的tip控件上时显示。
设置该列的宽度。未设置stable时,会自动根据其他列设置的width,按比例分配,增减调整宽度。
获取表格子行的元素。
参数:
自适应表格宽度。
若之前已设置Table的width属性,该方法将不起效果。
当控件主元素被点击时触发。
事件对象成员:
事件对象成员:
当用户点击表格排序时触发。
事件对象成员:
当用户点击展开子行按钮时触发
事件对象成员:
当用户点击展开子行按钮时触发
事件对象成员:
控件主元素的固定结构如下:
<div>
<div> <!-- head -->
<table>
<tr><th>标题</th></tr>
<tr><th>标题</th></tr>
......
</table>
</div>
<div> <!-- body -->
<div> <!-- rows -->
<table>
<tr><td>数据</td></tr>
<tr><td>数据</td></tr>
......
</table>
</div>
<div>
<table>
<tr><td>数据</td></tr>
<tr><td>数据</td></tr>
......
</table>
</div>
......
</div>
<div> <!-- foot -->
<table>
<tr><th>信息</th></tr>
</table>
</div>
</div>
以下两点是我 强烈 要推动的(甚至希望强制之):
因此,我提出以下建议:
hover
、active
、press
、focus
这些state由控件自己决定,仅样式上的变化的话,通过CSS处理,不通过鼠标事件管这事。:hover
、:active
、:focus
这几个伪类,样式通过这些伪类实现,不去使用这几个state相关的class。通过鼠标事件修改的class通常只能管理鼠标操作的情况,键盘操作不能覆盖,远没有伪类来得正确。InputControl
的主元素必须有tabindex
,默认值为0,这个可以在InputControl.prototype.initStructure
中实现。Select
应该能通过TAB聚焦,然后按方向键下或者回车打开层,使用方向键选择具体的项,按回车确认。参考以下代码:
var label = new Label();
label.main; // null
label.setText('Hello World');
label.appendTo(document.body);
需要确定几个问题:
appendTo
导致生成main
元素前,setText
能不能调用(调用时是否允许异常)setText
,则在渲染后,这个Label的文字要不要显示为 Hello World (即是否允许在main
出现前的相关属性调用被丢弃)Wizard
控件用于多步骤的引导式导航。
- Control
- Wizard
Wizard
控件的主元素 只能 是<ol>
或<ul>
元素,推荐(默认)使用<ol>
。
指定步骤,数组中的每一项称为 单步数据项 ,一个单步数据项可以包含以下属性:
{string} text
:显示的文字{string=} panel
:每个步骤可提供一个对应的面板的DOM元素的id,如果有该属性,则当该步骤激活时显示该面板,非激活的步骤对应的页面将被隐藏。指定所有步骤完成时的文字。如果有该属性,则将在所有的步骤之后多出一个节点显示该文字
当前激活的步骤的下标。
获取当前激活的步骤对应的单步数据项。
当前激活的步骤对应的单步数据项。
进入下一步,会随带触发enter
事件。
回到上一下,会随带触发enter
事件。
在进入某一步时触发。
nodeTemplate
属性可以用来指定控件中每一项生成时的HTML模板,其中占位符包含:
${text}
:显示的文本。占位符的替换均在经过HTML编码后进行。
该方法用于生成控件中每一项的HTML串,默认实现是基于nodeTemplate
属性的字符串格式化操作。
重写该方法后,nodeTemplate
的功能将失效。
控件的标准DOM结构如下:
<ol class="ui-wizard">
<!-- for ${steps} as ${step} -->
<li class="ui-wizard-node">${step.text}</li>
<!-- /for -->
<!-- if ${finishText} -->
<li class="ui-wizard-last ui-wizard-finish">${finishText}</li>
<!-- /for -->
</ol>
与状态相关的class如下:
ui-wizard-node-first
:第一个节点。ui-wizard-node-last
:最后一个节点,如果有finishText
属性,则最后一个节点永远是完成提示文字的节点。ui-wizard-active
:当前的节点。ui-wizard-done
:已经完成的节点。ui-wizard-active-prev
:当前节点的前一个节点。ui-wizard-last-active
:既是最后一个节点又是激活的节点。ui-wizard-panel-hidden
:由Wizard
控件控制的被隐藏的面板。关于Tree控件的设计
Tree
控件从实现上来说可能并不是最难的,但就交互来说,绝对可以算得上最烦杂的控件,甚至可以说没有之一。一个Tree
控件最常用的交互有以下2个:
expand
collapse
但在这2个交互发生时,采取的行为却大为不同:
XMLHttpRequest
来加载但是Tree
作为一个控件,去引入XMLHttpRequest
之类的,并且来根据自己的数据源判断进行这些操作,显然不合理且会增加实现的复杂度。
因此,我对Tree
进行了一个重新设计,看下图:
这个设计下,Tree
控件仅提供最基本的事件和方法,有:
expand
和collapse
事件,提供节点对象(数据源中的对象,非DOM节点)作为参数fillNode
方法,向一个节点中填充子节点emptyNode
方法,清掉一个节点中的子节点indicateNodeLoading
方法:指示某个节点的数据正在加载当点击一个节点时,Tree
控件仅会根据节点的状态触发一个事件,本身不做任何的数据查询、加载、绘制工作,直到注册事件的逻辑来调用fillNode
或emptyNode
,才进行数据的填充操作
当然这么设计的话,控件使用会变得非常麻烦,因此再提供一个叫TreeDatasource
的扩展(名字现在觉得不太对,要再想想),来实现这些功能。
TreeDatasource
是一个针对Tree
设计的类,esui提供的默认实现是接受一个树状的对象(参见EJSON相关章节)。当这个扩展起作用后,会注册Tree
的expand
和collapse
事件,当事件发生时,在Tree
的datasource
中找到对应节点,取出子数据,自动调用fillNode
或emptyNode
完成视图展现。
这么做的好处是,对于一个非常依赖数据,同时有可能需要延迟加载数据的控件,进一步把 数据 和 视图 分离,保证控件只关注视图和交互,不关心数据的存取。如果需要延迟加载数据,则可以进一步提供一个RemoteTreeDatasource
的扩展(后续由ef项目提供),这样esui不用关心XMLHttpRequest
,又能非常简单地挂载上数据的远程加载。
对于这个设计,还存有几个问题:
Tree
提供的方法是不是够,从我对Tree
的使用来看是够了,看看其它项目组有没进一步的需求(注意每个节点加个checkbox不是这一需求覆盖范围,有另外的设计支持)TreeDatasource
应该是个扩展,还是Tree
自身抽象出来的一个组件。
Tree
自身要求的一个组件,则认为是必须有的,作为Tree
的一个属性,同时避免扩展只为特定控件服务的情况。点击[全周投放]等快捷按钮时报错:
Uncaught TypeError: Cannot read property 'getVal' of undefined
Tree
是树控件,将一个树状的数据源对象以树型显示出来,同时控制节点的展开/收起操作。
- Control
- Tree
Tree
控件的主元素可以是<div>
或任何流式元素,默认使用<div>
元素。
树的数据源,其中一个节点的对应的数据称为 节点数据项 ,一个节点数据项可包含以下属性:
{string} id
:节点的唯一id,必须在所有节点中具有唯一性。{string} text
:显示的文字。{Array.<Object>=} children
:子节点,数组中每个对象是一个节点数据项。与当前树关联的交互策略对象,详见 扩展点 部分对TreeStrategy
的介绍。
需注意的是,strategy
属性是 一次性 的,在实例化的时候设置,随后 不能 修改。
展开指定的节点,如提供了children
参数,则使用该数组作为子节点数据。
{string} id
:待展开的节点的id。{Array.<Object>=} children
:填充的子节点数据。当children
未提供时,将按以下规则处理:
id
对应的节点数据中的children
属性作为数据填充。通常来说,当对应的节点已经有children
属性时,调用expandNode
时不需要传递children
参数,以免在原来节点已经展开过的情况下,再次生成子树的DOM结构造成不必要的性能损失。
收起指定的节点,并根据removeChild
参数决定是否移除已经生成的子树的DOM结构。
{string} id
:待收起的节点的id。{boolean} removeChild
:默认值为false
。如果此参数为true
,则在收起的时会移除子树的DOM结构。当需要有效减少节点数量和控制性能时,建议传递此参数。将指定节点标记为“加载中”状态。通常当树的节点展开时需要从远程加载数据,则可以在数据加载期间调用此方法给予用户提示。
{string} id
:需要标记的节点的id。当一个收起的节点被请求展开时触发。
需注意的是,Tree
控件仅触发该事件,并不会直接展开节点,需要配合TreeStrategy
来添加默认展开的效果。
事件对象属性如下:
{Object} node
:待展开的节点对应的节点数据项。当一个展开的节点被请求收起时触发。
需注意的是,Tree
控件仅触发该事件,并不会直接收起节点,需要配合TreeStrategy
来添加默认收起的效果。
事件对象属性如下:
{Object} node
:待收起的节点对应的节点数据项。itemTemplate
属性可以用来指定控件中每一项生成时的HTML模板,其中占位符包含:
${text}
:显示的文本。${id}
:节点的id。占位符的替换均在经过HTML编码后进行。
该方法用于生成控件中每一项的HTML串,默认实现是基于itemTemplate
属性的字符串格式化操作。
重写该方法后,itemTemplate
的功能将失效。
由于树是一个无限定深度的数据结构,Tree
控件往往会面对数据量很大,需要按需加载的情形。但是控件应当负责 数据的展现 ,而不对 数据的获取和处理 负责,因此提供TreeStrategy
类来对数据的获取和处理进行抽象。
TreeStrategy
类是对 树的数据相头的策略 的抽象,其包含以下方法:
{boolean} isLeafNode({Object} node)
:判断一个节点是否为叶子节点,树对叶子节点的展现样式是特殊的。{boolean} shouldExpand({Object} node)
:判断一个节点是否应当展开,当树渲染一个节点时会调用此方法。如果需要展开,则会进一步渲染其children
属性。{void} attachTo({Tree} tree)
:绑定到对应的控件上,使当前策略生效。通常来说,一个TreeStrategy
的attachTo
方法需注册expand
和collapse
事件,在事件的处理函数中获取数据,并调用expandNode
和collapseNode
来使树得到正确的交互。
当collapse
事件发生时,通常简单地调用collapseNode
方法收起节点即可,需要时可以通过collapseNode
方法的removeChild
参数控制子节点的删除以回收内存和提高性能。
当expand
事件发生时,需要根据数据的获取方案来提供不同的逻辑,一般如下:
expandNode
,不传递children
参数,由控件自动查找数据并生成子节点。indicateNodeLoading
方法,使节点进入加载状态。XMLHttpRequest
等手段加载远程数据,在收到数据后调用expandNode
并传递children
参数展开节点。注意在调用expandNode
时,如果提供了children
参数,则Tree
控件会将提供的参数作为该节点的children
属性保存,因此下一次调用时不再需要传递该参数。框架内默认提供的TreeStrategy
类实现了对静态数据的处理,远程动态数据需使用方自行实现。
控件的标准DOM结构如下:
<div class="ui-tree">
<div class="ui-tree-root ui-tree-node">
<span class="ui-node-indicator">节点前的指示器</span>
${getItemHTML}(${datasource})
<!-- if ${datasource.children} && ${datasource.children.length} > 0 -->
<ul class="ui-tree-sub-root">
<!-- for ${datasource.children} as ${node} -->
<li>
<!-- 与上面一样 -->
<span class="ui-node-indicator">节点前的指示器</span>
${getItemHTML}(${node})
<!-- if ${node.children} && ${node.children.length} > 0 -->
<ul class="ui-tree-sub-root">
<!-- 递归 -->
</ul>
<!-- /if -->
</li>
<!-- /for -->
</ul>
<!-- /if -->
</div>
</div>
状态相关的class如下:
ui-tree-root-expanded
:根节点处于展开状态ui-tree-root-collapsed
:根节点处于收起状态ui-tree-node-expanded
:该节点处于展开状态。ui-tree-node-collapsed
:该节点处于收起状态。ui-tree-sub-root-expanded
:该子树处于展开状态。ui-tree-sub-root-collapsed
:该子树处于收起状态。ui-tree-node-indicator-expanded
:该指示器对应的节点处于展开状态。ui-tree-node-indicator-collapsed
:该指示器对应的节点处于收起状态。ui-tree-node-indicator-busy
:该指示器对应的节点处于加载状态。CheckBox
的多选树的扩展点设计。Select
控件形如HTML中的<select>
元素,是一个下拉列表,可以选择其中一项。
- Control
- InputControl
- Select
Select
控件的主元素可以是一个<div>
或者其它类型的流式元素,也可以是一个<select>
元素。
当使用<select>
元素作为主元素时,控件会删除该元素,并在相同的位置放置一个<div>
元素作为替换。
当满足以下2个条件时:
<select>
元素作为主元素时datasource
属性Select
控件会从主元素的<option>
子元素中提取数据作为自身的datasource
属性。
指定控件的宽。
指定控件的高。
控件的数据源,数据源中的每一个对象称为 数据项 ,一个数据项需包含:
- `{string} text`:该项的文本,与`name`二选一。
- `{string} name`:该项的文本,与`name`二选一。
- `{*} value`:该项的值,通常是字符串类型,否则在显示时将被转为字符串。
如果name
和text
均存在,则 以name
为优先 。
该属性指定当控件未选择任何一项时显示的文本。如果此属性不为空,则该文本将在以下情况出现:
value
、rawValue
及selectedIndex
属性,导致未选中任何项。value
、rawValue
或selectedIndex
不在datasource
范围内,如给了一个datasource
不包含的value
,或者一个超出datasource.length
的selectedIndex
值。datasource
,导致原来选中的项不在新的datasource
中。需要注意的是,如果修改datasource
后,原来选定的rawValue
还在新的datasource
的范围内,则不会显示emptyText
,而是继续选中该项。此时如果需要回到未选任何一项的状态,可以通过select.set('selectedIndex', -1);
来完成。
选中的项在datasource
中的下标,可以通过设置该属性来选中指定的项。如果该值小于0或者大于datasource.length
,则会根据是否有emptyText
属性来决定显示emptyText
或者选中第一项。
控件的原始值,当有一项被选中时,返回该项的value
属性。当未选中任何一项时,返回null
。
当选中项变化时触发。
itemTemplate
属性可以用来指定控件中每一项生成时的HTML模板,其中占位符包含:
${text}
:显示的文本。${value}
:数据项的值。占位符的替换均在经过HTML编码后进行。
该方法用于生成控件中每一项的HTML串,默认实现是基于itemTemplate
属性的字符串格式化操作。
重写该方法后,itemTemplate
的功能将失效。
控件主元素的固定结构如下:
<div>
<span>${text}</span>
<input name="${name}" type="hidden" value="${value}" />
</div>
另Select
控件会在document.body
下创建一个元素,用于显示下拉层,该元素会在任意地方(除控件自身外)发生mousedown
事件时隐藏。
<div class="ui-select-layer">
<!-- for ${datasource} as ${item} -->
${getItemHTML}(${item})
<!-- /for -->
</div>
默认的getItemHTML
返回内容如下:
<span>${text}</span>
optgroup
形式的分组内容。 为了控件更好的封闭性,控件的main元素不宜暴露给用户。
但是用户还是会有往控件上添加某些数据的需求,如其交互关联Dom元素的Id,或某些业务信息。
这些数据以前用户往往会加在main元素的属性中,现在这个main元素不再返回了,可能会给用户带来一些麻烦。
如果能往控件元素上增加存储数据的data属性,将方便用户的使用,用户也将大大降低对main元素本身的依赖。将数据属性和元素属性区分开来,好处是不会干扰控件本身的属性。
方法可以参考html5 中的 data-* 属性,并在控件中增加 setData getData。( 或者其他合适的命名)
配合 ecomfe/edp#34 ,希望edp code-gen control SomeControl inherits InputControl
能自动生成一个模板的js文件
私有成员与方法是下划线_
开头,还是仅仅通过注释标识?
状态
是一个kv,做为控件的属性,是命名为state
/states
/stateMap
?
对Array类型的,应该是+s,这点应该没有疑问。
MonthView
- Control
单月日历控件包括日期选择、月份选择、年份选择、单月浏览。
"MonthView"
控件主元素必须为div。
选中的日期,为Date类型的Javascript对象。
允许选择日期区间“range”的数据格式,以一个Object表示。该Object拥有name为begin和end的成员,分别为Date类型。
{
begin: new Date(1983, 8, 3),
end: new Date(2046, 10, 4)
}
使用data-ui定义range时,支持字符串型,‘,’分割起始时间和结束时间。如:1983-09-03,2046-11-04。
日期显示的格式化方式。默认'yyyy-MM-dd'。
可选中的日期区间。可选,默认
{
begin: new Date(1983, 8, 3),
end: new Date(2046, 10, 4)
}
当前选中的日期的原始数据。
如果rawValue超出range范围,则该日期有可能不会展示在日历上。
获取当前选中的日期。
设置允许选中的日期区间。
参数:
通过日期格式,设置当前选中的日期。
参数:
当选择的日期发生改变时触发。
事件对象成员:
当选择的年份发生改变时触发。
事件对象成员:
当选择的月份发生改变时触发。
事件对象成员:
待修复
Tab
控件可以用于标签页的切换。每个标签可以对应一个容器元素,Tab
控件自动控制容器的切换。
Tab
标签自身会创建一个导航条,包含各个标签的元素。
- Control
- Tab
`Tab`控件的主元素可以是一个<div>或者其它类型的流式元素,默认使用`<nav>`元素。
当给定主元素时,主元素下可以存在一个导航元素,导航元素 必须 是一个<ul>
或<ol>
元素,内含若干个<li>
元素。
导航元素 必须 有data-role="navigator"
属性,且 必须 是主元素的 直接子元素 。
一个标准的导航元素结构如下:
<ul data-role="navigator">
<li data-for="intro">简介</li>
<li data-for="character">人物介绍</li>
<li data-for="content">正文</li>
<li data-for="publish">出版信息</li>
</ul>
当实例化控件时,如果未给定tabs
属性或者tabs
属性为空数组,且主元素下有导航元素,则按以下规则,从导航元素的子元素中提取出tabs
属性:
innerText
作为title
属性。data-for
属性的值作为panel
属性。需要注意的是,导航元素的子元素仅起到标记的意义,不要依赖子元素的具体样式。当控件渲染时,会把导航元素中的内容 清空 , 重新生成 符合规范的子元素结构。
当实例化控件时,如果同时满足以下所有条件时:
tabs
属性或tabs
属性为空数组则会将主元素下的每一个直接子元素作为一个面板,按以下规则生成tabs
属性:
title
属性作为title
属性。id
属性作为panel
属性。随后控件渲染时,会建立导航元素并作为主元素的 第一个子元素 。
标签页的配置,数组中的每一项称为 配置项 ,一个配置项的结构如下:
{string} title
:标签页的显示名称。{string=} panel
:对应的元素的id,当一个标签被激活时,该标签配置项的panel
属性对应的DOM元素将被显示出来,其它配置项对应的DOM元素则被隐藏。是否允许删除标签,默认值为false
。当此属性值为true
时,会在每个标签页中显示一个关闭的标记,点击后会删除该标签页。
当标签页删除时,其panel
属性对应的DOM元素并不会被删除,但会被隐藏。
指定当前激活的标签的下标。当修改此属性时,会触发activate
事件。
激活config
属性对应的标签页。
{Object} config
:需激活配置项,使用全等(===
)进行判断。在最后添加一个新标签页。
{Object} config
:添加的标签页的配置项,不去重。在指定位置添加一个新标签页。
{Object} config
:添加的标签页的配置项,不去重。{number} index
:插入的位置。如果小于0则会插在第一个,如果大于现有标签页的数量则插在最后。移除指定的标签页。
{Object} config
:需移除的标签页配置项,使用全等(===
)进行判断。移除指定位置的标签页。
{number} index
:需移除的位置,如果在现有标签页范围之外则无效果。一个标签由未激活状态转为激活状态时触发,事件对象的属性如下:
{number} activeInex
:激活的标签的下标。{Object} tab
:激活的标签的配置项。添加一个标签时触发,事件对象的属性如下:
{number} activeInex
:激活的标签的下标。{Object} tab
:激活的标签的配置项。移除一个标签时触发,事件对象的属性如下:
{number} activeInex
:激活的标签的下标。{Object} tab
:激活的标签的配置项。contentTemplate
属性可以用来指定控件中每个标签页生成时的HTML模板,其中占位符包含:
${title}
:显示的文本。占位符的替换均在经过HTML编码后进行。
该方法用于生成控件中每一项的HTML串,默认实现是基于contentTemplate
属性的字符串格式化操作。且当第2个参数(allowClose
)为true
时,追回一个<span>
标签。
重写该方法后,contentTemplate
的功能将失效。
默认生成的结构如下:
<nav>
<ul>
<!-- for ${tabs} as ${item} -->
<li>${item.title}</li>
<!-- /for -->
</ul>
</nav>
当开启allowClose
属性时,每个标签页中的内容变为
<li>
${item.title}
<span class="ui-tab-close">关闭</span>
</li>
一个被激活的标签页会增加ui-tab-active
类。
Dialog
- Control
对话框控件包括三个部分:标题、主体、腿部。
对话框控件内置两种模式:alert、confirm。可通过静态方法调用。
"Dialog"
控件主元素必须为div。
使用html搭建dialog时支持将title、content、foot内容预写入主元素下。并使用data-role属性指定节点角色。如:
<div data-ui="type:Dialog;width:400;mask:true;id:staticDg">
<h1 data-role="title">我来自静态html</h1>
<div data-role="content">
<p>第一行</p>
<span data-ui="type:Button;id:springBtn;skin:spring">显示文字</span>
</div>
</div>
是否自动定位居中。默认值为false。
是否具有关闭按钮。默认值为true。
内容区域的显示内容。默认为主元素内容区域的内容。支持html。
可以通过boolean指定对话框是否具有遮挡层。
标题的显示文字。支持html。
对话框的宽度,单位为px。默认值为600。
对话框的高度,单位为px。默认值为175。
对话框是否需要足部内容。有些对话框不需要使用foot来装载负责确认或取消操作的按钮,此时可以将此值置为false。
对话框的足部显示内容。默认值包含两个按钮:确定和取消。可以自定义符合自己要求的内容。
显示警告对话框。
args参数各项成员:
显示询问对话框。
args参数各项成员:
获取对话框主体的控件对象。
获取对话框腿部的控件对象。
获取对话框头部的控件对象。
显示对话框。
隐藏对话框。
设置对话框的标题。
参数:
设置对话框主体的内容。
参数:
设置腿部内容。
参数:
设置对话框的宽度,单位为px。
参数:
设置对话框的高度,单位为px。
参数:
当对话框被显示时触发。
事件对象成员:
当对话框被隐藏时触发。
事件对象成员:
Crumb
控件用作面包屑导航,用于展现一系列有递进层次的链接。
- Control
- Crumb
Crumb
控件的主元素可以是<div>
或任何流式元素,默认使用<nav>
。
指定导航的路径,数组中的每一项称为 节点数据项 ,一个节点数据项可以包含以下属性:
{string} text
:显示的文字{string=} href
:跳转的链接地址,可以没有该属性,如果没有该属性,则对应的节点是一个文本而非链接。指定每两个节点之间的分割符,可以是一段HTML,控件不负责对其进行HTML转义。默认值为>
。
用来指定控件中文本节点生成时的HTML模板,其中占位符包含:
${text}
:显示的文本。占位符的替换均在经过HTML编码后进行。
用来指定控件中链接节点生成时的HTML模板,其中占位符包含:
${text}
:显示的文本。${href}
:链接地址。占位符的替换均在经过HTML编码后进行。
该方法用于生成控件中每一项的HTML串,默认实现是基于textNodeTemplate
或linkNodeTemplate
属性的字符串格式化操作。
重写该方法后,textNodeTemplate
和linkNodeTemplate
的功能将失效。
控件的标准DOM结构如下:
<nav class="ui-crumb">
<ol>
<!-- for ${path} as ${node} -->
<li class="ui-crumb-node">
<!-- if ${node.href} -->
<a href="${item.href}">${item.text}</a>
<!-- /if -->
<!-- else -->
<span>${item.text}</span>
<!-- /else -->
</li>
<li class="ui-crumb-separator">${separator}</li>
<!-- /for -->
</ol>
</nav>
与状态相关的class如下:
ui-crumb-node-first
:第一个节点。ui-crumb-node-last
:最后一个节点。以下是新的Tab控件UI标准,供大家讨论
Tab
控件可以用于标签页的切换。每个标签可以对应一个容器元素,Tab
控件自动控制容器的切换。
Tab
标签自身会创建一个导航条,包含各个标签的元素。
Tab
-> Control
"Tab"
以下属性可在构造函数中传入,也可在运行过程中通过set
或setProperties
修改。
{Array} tabs
:指定标签页的配置。{boolean} allowClose
:如果此项为 true ,则每个标签上会出现一个关闭元素,点击该元素会自动删除该标签。默认值为 false 。{number} activeIndex
:指定当前激活的标签的下标。默认值为 0 。其中tabs
中的每一项包含以下内容:
{string} title
:标签的标题,必须有。{string=} panel
:标签对应的面板元素的id,可选。其中activeIndex
的变化如下:
activeIndex
始终指向当前激活的标签的下标。activeIndex
的值为 -1 。tabs
导致activeIndex
超出标签的数量,则其值将会被修正为 0 。Tab
控件的控件主元素必须是<div>
元素,如果构造控件时没给定主元素,则创建一个空的<div>
元素作为主元素。
Tab
控件的主元素中可以包含一个导航条元素,该导航条元素结构必须如下所示:
<ul data-role="navigator">
<li data-for="a">tab1</li>
<li data-for="b">tab2</li>
<li data-for="c">tab3</li>
</ul>
导航条元素满足以下条件:
<ul>
或<ol>
等可包含<li>
元素的容器。data-role="navigator"
属性。<li>
元素。当Tab
控件发现导航条后,会采取以下行为:
<li>
元素抽取标签选项,以data-for
为panel
属性,以innerText
为title
属性。tabs
选项 。Tab
控件会自己建立符合需求的导航条。当符合以下 全部 条件时:
tabs
选项,或该选项为一个空数组。则Tab
控件自动将每一个子元素作为一个标签配置项,元素的title
属性作为配置项的title
属性,元素的id
属性作为配置项的panel
属性。
在最后面添加一个标签,其中config
包含title
和可选的panel
选项。
在指定位置添加一个标签,其中config
包含title
和可选的panel
选项。
移除指定的标签,其中config
必须是控件tabs
属性中已有的对象,通过引用判断相等。
移除指定位置的标签。
激活指定的标签,其中config
必须是控件tabs
属性中已有的对象,通过引用判断相等。
激活指定位置的标签。
当添加或插入一个标签时触发,事件对象包含:
tab
:添加的标签的配置项。通过方法或点击关闭标签的元素从而移除一个标签时触发,事件对象包含:
tab
:移除的标签的配置项。因任何情况导致一个标签被激活时触发,事件对象包含:
activeIndex
:当前激活的标签的下标tab
:当前激活的标签配置项注意,当因为插入或移除标签导致activeIndex
变化,但当前激活的标签并没有改变时, 不会 触发该事件。
setActiveIndex
、getActiveIndex
等方法,现在可以使用set('activeIndex')
来操作add
事件,从而实现可变的标签页功能有时候,一个控件的样式,可以使用CSS3来做,同时降级到低级浏览器能看。但又有时候,感觉降级的效果并不那么漂亮,所以要再加一些或者改变一下更合适。
因此,学习一下Modenizr,让esui也在body上加一些class,以方便写css吧。具体要什么样式,各控件自己控制吧,定义控件的时候加上去就好,但要求 **统一用ui-support-xxx
的形式。
求讨论
Select控件当前实现时,使用setProperties({value: ${value}})的方式,value的值发生了改变,但再次打开下拉选项时,该value未处于选中样式。
很多自动化测试和工具依赖于元素的id的稳定性,如果每次进页面的guid计算是以当前时间为基准的,会导致自动化的代码找不到对应的元素。
需要修改helper.getGUID
的实现,使用一个与时间无关的算法,建议设置一个初始值,然后稳定自增
貌似没必要这么麻烦
Form
控件类同<form>
元素,指代一个表单,基到普通的面板提供一些额外的方法。
- Control
- Panel
- Form
Form
控件的主元素可以是任何流式元素,推荐(默认)使用<form>
。
指定表单提交的URL,暂无作用。如果主元素是<form>
元素,则会设置对应的属性。
指定表单提交时的动作,暂无作用。如果主元素是<form>
元素,则会设置对应的属性。
可以用该属性指定一个Button
控件的id,当点击该按钮时,表单将触发submit
事件。
在当前Form
下查询符合条件的InputControl
,并返回一个集合。该方法对InputControl
的判断采用以下策略:
InputControl
或其子类的实例。Form
的元素下。name
参数或者控件的name
属性与name
参数相等。type
参数或者控件的type
属性与type
参数相等。Form
使用同一个ViewContext
实例。InputControl
的子控件存在。该方法返回一个InputCollection
对象,InputCollection
是对输入控件的集合的封装,除了正常的for
循环外,还支持以下方法:
{void} checkAll()
:全选。{void} uncheckAll()
:全部取消选择。{void} checkInverse()
:反选。{void} checkByValue(Array.<string> values)
:选中给定值的控件。{string} getValueAsString()
:获取逗号分隔的值的字符串形式。将当前Form
下的InputControl
的rawValue
收集起来并返回一个对象。对象的键为控件的name
属性,值为rawValue
属性。
该方法找InputControl
的策略与getInputControls
相同。
当submitButton
指定的按钮被点击时触发。
现在的initChildren
,会把一段HTML中的所有元素分解成控件,且 无论其层级,统一作为自己的子控件 ,如下代码:
var html = [
'<div data-ui="type: Panel; childName: header;">',
'<span data-ui="type: Label; childName: close;">关闭</span>',
'</div>',
'<div data-ui="type: Panel; childName: foot;">',
'<div data-ui="type: Button; childName: close;">关闭</div>',
'</div>'
];
this.main.innerHTML = html.join('');
this.initChildren();
会产生2个childName
为 close 的控件,且不会 一个在header中,一个在foot中 ,而是统一作为自己的子控件。那么只会有一个可以通过this.getChild('close')
访问到。
而我希望的是,可以通过this.getChild('foot').getChild('close').on('click', closeThis)
来注册事件。
由于控件的开发者是不能在里面写id
的,因此一个有层级的childName
会起到更好的效果。不然childName
就要像id
一样写成一个是 headerClose 一个是 footClose ,这让childName
和id
的概念之间产生混淆。
从命名上来说,我认为initChildren
的意思是 初始化子控件 ,但并不代码一定 所有控件都是子控件 ,而是应该以递归的方式创建出一个树。
Region用于地域选择。
Region支持单选和多选两种选择模式。
单选以下拉选框形式展示。
Region
- InputControl
- Control
"Region"
控件主元素必须为div。
多选模式下,value的字符串格式为逗号分割的地域id数组。
如果选择了某城市,则value串种除了包含该城市下的所有区域id,还包括该城市的id。
地域列表可通过静态参数配置,也可初始化时传入。地域列表是一个Array,列表中的每一项是一个可具有id、text、children属性的多重结构的数据。
[
{
id: "China",
text: "**地区",
children: [
{
id: "North",
text: "华北地区",
children: [
{id: "1", text: "北京"},
{id: "3", text: "天津"},
{id: "13", text: "河北"},
{id: "26", text: "山西"},
{id: "22", text: "内蒙古"}
]
},
{
id: "NorthEast",
text: "东北地区",
children: [
{id: "21", text: "辽宁"},
{id: "18", text: "吉林"},
{id: "15", text: "黑龙江"}
]
},
{
id: "East",
text: "华东地区",
children: [
{id: "2", text: "上海"},
{id: "19", text: "江苏"},
{id: "32", text: "浙江"},
{id: "9", text: "安徽"},
{id: "5", text: "福建"},
{id: "20", text: "江西"},
{id: "25", text: "山东"}
]
},
{
id: "Middle",
text: "华中地区",
children: [
{id: "14", text: "河南"},
{id: "16", text: "湖北"},
{id: "17", text: "湖南"}
]
},
{
id: "South",
text: "华南地区",
children: [
{id: "4", text: "广东"},
{id: "8", text: "海南"},
{id: "12", text: "广西"}
]
},
{
id: "SouthWest",
text: "西南地区",
children: [
{id: "33", text: "重庆"},
{id: "28", text: "四川"},
{id: "10", text: "贵州"},
{id: "31", text: "云南"},
{id: "29", text: "西藏"}
]
},
{
id: "NorthWest",
text: "西北地区",
children: [
{id: "27", text: "陕西"},
{id: "11", text: "甘肃"},
{id: "24", text: "青海"},
{id: "23", text: "宁夏"},
{id: "30", text: "**"}
]
},
{
id: "Other",
text: "其他地区",
children: [
{id: "34", text: "香港"},
{id: "36", text: "澳门"},
{id: "35", text: "**"}
]
}
]
},
{
id: "Abroad",
text: "国外",
children: [
{id: "7", text: "日本"},
{id: "37", text: "其他国家"}
]
}
]
地域列表。默认应用构造器中的REGION_LIST设置。
选择模式。multi|single。默认值为multi。
当前选中的地域value
当mode为‘single'时,地域id字符串格式。
当mode为‘multi'时,地域id数组格式。
获取选中的地域,数组格式。
通过数组格式,设置选中的地域。
参数:
当选中地域发生改变时触发。
事件对象成员:
貌似没必要这么麻烦
.inline-block()
提供兼容IE的display: inline-block;
的功能.iconize(url)
将元素中的文字进行大量偏移使其消失,并设置背景图片为指定的图标.reset-list()
将<ul>
或<ol>
的padding
、margin
和list-style
设置为无setViewContext
更换时,是否要确保main
上的data-ctrl-view-context
属性同步变化?viewContext
是只读的,以避免这一类问题的出现?想不到需要改变viewContext
的情况。如果是只读的,我考虑删掉setViewContext
方法。比如说我们new一个控件的时候吧,会传一个options
对象,这个对象里可能有个main
属性提供HTML元素,这时就有问题了。
有一些参数,会从main
上去提取,但同时options
对象里又有同名的参数,这里的优先级需要讨论,典型的如下代码:
var a = document.createElement('a');
a.href = 'http://www.baidu.com';
document.body.appendChild(a);
var link = new Link({ main: a, href: 'http://www.google.com' });
link.render();
那么,这个link
控件的href
到底应该是百度还是Google呢?
同样的问题也出在从HTML解析出控件的时候:
<a href="http://www.baidu.com"
data-ui-type="Link"
data-ui-href="http://www.google.com">
This is a link
</a>
RangeCalendar用于选择日期区间。
RangeCalendar
- InputControl
- Control
"RangeCalendar"
控件主元素必须为div。
RangeCalendar的value字符串格式为"yyyy-MM-dd,yyyy-MM-dd",逗号分隔的前后分别代表开始和结束日期。
对于rawValue以及可选择日期区间的数据格式,都以一个Object表示。该Object拥有name为begin和end的属性,分别为Date类型。
{
begin: new Date(1983, 8, 3),
end: new Date(2011, 10, 4)
}
可以通过获取RangeCalendar类修改,效果作用于控件全局。
日期显示的格式化方式。默认'yyyy-MM-dd'。
日期参数的格式化方式。默认'yyyyMMdd'。
日期区间快捷选项列表。默认提供“昨天 | 最近7天 | 上周 | 本月 | 上个月 | 上个季度”六种快捷方式。每种快捷方式的定义格式如下:
{
name: '昨天',
value: 0,
getValue: function () {
var yesterday = new Date(this.now.getTime());
yesterday.setDate(yesterday.getDate() - 1);
return {
begin: yesterday,
end: yesterday
};
}
}
创建时定义,效果作用于单个控件实例。
需要显示的mini日历快捷方式。默认全部。格式:‘[快捷方式显示名],[快捷方式显示名]’,如'昨天,最近7天'
可选中的日期区间。默认
{
begin: new Date(2011, 8, 3),
end: new Date(2011, 10, 4)
}
当前选中的日期区间,Object格式。
{
begin: new Date(2011, 8, 3),
end: new Date(2011, 10, 4)
}
当前选中的日期区间的字符串形式,"yyyy-MM-dd hh:mm:ss,yyyy-MM-dd hh:mm:ss",逗号分隔的前后分别代表开始和结束日期。
如:'2011-08-03 00:00:00,2011-10-04 23:59:59'
日历可以配置为“无结束时间”即“无限”模式。endlessCheck为true时开启模式。rawValue中如果不包含结束时间,无限模式将被自动开启。
获取当前选中的日期区间,对象格式。
设置允许选中的日期区间。
参数:
支持字符串型,‘,’分割起始时间和结束时间。如:1983-09-03,2046-11-04。
通过对象格式,设置当前选中的日期区间。
参数:
当选择的日期发生改变时触发。
事件对象成员:
看了下lib的函数,总结一下几个问题:
比如bind
函数,原实现是可以从scope
中取fun
为名字的方法的,我认为这是原tangram为了某些业务线的需求而产生的功能,我们不应该鼓励和提倡这种用法,因此我去掉了。
同样的问题在很多函数中都存在,例如:
format
函数支持${name}
和{index}
两种形式,是否只支持${name}
就OK了hasClass
、addClass
和removeClass
支持多个class以空格分隔,确实这功能非常强大,jQuery也提供这一功能,但在一个UI控件体系中,代码都是可掌握的高质量代码,是否有必要提供这种 看似便利实则可能导致混乱和不一致性 的功能tangram的继承实现是没错的,但是它提供了一些额外的东西,包括:
__type
属性表示类型superClass
属性引用基类extends
方法生产子类其中superClass
比较广泛,可以认可(虽然我个人很反对这一做法),但是__type
和extends
从我的角度来看是完全没有存在的意义的,是否还需要保留。
现有的lib其实是比较混乱的,语言层面的东西(trim
、clone
等)、字符串层面的东西(encodeHTML
等)和DOM层面的东西(g
、hasClass
等)混在一个下面,这种设计是没有问题的,我个人也很推崇这种,毕竟没多少东西,不必要再细分。
但是奇怪的是,有一个page
二级“命名空间”,这货的存在意义是什么……?
题外话:如果现在lib中的东西是原封不动从tangram弄过来的话,这大概是我第一次认真地看tangram的源码,只想吐槽这代码质量是有多差……
有几个系统有向导型的表单交互,即先填一个页,然后“下一步”填另一些项,再“下一步”继续填写,然后完成
这个控件和Crumb
控件有点像,但有一些不同:
WizardGuide
会把所有的路径全显示出来,并且有一个“当前激活”的WizardGuide
的每一项并不是一个链接,且没有点击事件这个控件和Tab
也有点像,但又有一些不同:
WizardGuide
的各项之间是有顺序的WizardGuide
由于通常关联着一个很复杂的大表单,因此本身并不一定是通过多个panel的显示和隐藏来完成逻辑的配置说明:
steps
:说明整个向导过程中的步骤,每个step
包含以下:
text
:显示的文字panel
:对应的面板,可以没有finishText
:有些向导在最后有一个“完成”的字样,点击不起任何作用,仅视觉效果,通过这个字段可配置activeIndex
:当前激活的步骤的索引,如果有finishText
则可能取到超出steps.length - 1
的值activeStep
: 只读 ,当前激活的步骤对象,如果有finishText
则可能取到undefined
,此时是在最后一步上事件说明:
enter
:进入某一步骤时触发,如果有panel
属性会控制对应panel的隐藏和显示后再触发方法说明:
stepNext
:去下一步,如果已经是第一步则无反应stepPrevious
:去上一步,如果已经是最后一步(有finishText
的情况下会多出一步)则无反应A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.