Comments (5)
关于initChildren行为的问题,我的思考过程如下,抛砖引玉:
initChildren使用场景
首先
,initChildren方法不是给控件使用者用的,而是给控件开发者用的。在控件的渲染(包括重绘)过程中,可能会使用initChildren方法初始化子控件。
其次
,initChildren( {HTMLElement} wrap )初始化子控件的场景有两种:
- wrap内部的html结构完全是控件开发者生成的。
- wrap内部的html结构有可能是控件使用者(如使用setContent)传入的。这里我们先不考虑这种方式是否需要支持,先假设有这种场景
如果initChildren支持自动树状结构
不算问题的问题1
<div data-ui-type="Tab">
<ul data-role="navigator">
<li data-for="a-element">a</li>
</ul>
<div id="a-element">
<textarea data-ui-type="TextBox"></textarea>
</div>
</div>
上面的case,TextBox是Tab的子控件,但其实Tab根本不需要关心TextBox的存在。当然,其作为Tab的的子控件并没有逻辑上的问题。
可以解决的问题2
另外一个场景,Dialog自己在render时生成一个childName为close的子控件,但是用户使用setBodyContent方法,传入下面这样一个html,就会有childName的冲突问题。所以,如果我们要支持使用场景2
,控件内部自己render时生成的子控件,childName命名就必须使用__name__
。这个就需要控件开发者保证。
<button data-ui-type="Button" data-ui-child-name="close"></button>
可能是问题的问题3
想想Dialog控件的控件开发者,生成下面这段html,并且initChildren。在绑事件的时候,他就需要调用多次getChild。这让我想起很多写.parentNode.parentNode.parentNode.setAttribute()
的同学...
<!-- 下面是Dialog开发者给main灌的innerHTML -->
<div data-ui-type="Panel" data-ui-child-name="head">
<h3 data-ui-type="Label" data-ui-child-name="title"></h3>
<button data-ui-type="Button" data-ui-child-name="close"></button>
</div>
<div data-ui-type="Panel" data-ui-child-name="body"></div>
<div data-ui-type="Panel" data-ui-child-name="foot">
<button data-ui-type="Button" data-ui-child-name="ok"></button>
<button data-ui-type="Button" data-ui-child-name="cancel"></button>
</div>
// 下面是绑定事件代码
this.getChild( 'head' ).getChild( 'close' ).on( 'click', closeHandler );
var footChild = this.getChild( 'foot' );
footChild.getChild( 'ok' ).on( 'click', okHandler );
footChild.getChild( 'cancel' ).on( 'click', cancelHandler );
而且,close/ok/cancel确实应该是Dialog的子控件,因为其行为是归Dialog管的。
不可解决的问题4,这是我最介意的点
性能,是不可解决的问题。这个不可解决在于遍历过程
。
现在的机制是,getElementsByTagName('*')
,结果缓存一遍(当然是缓存成数组),然后对缓存数组进行处理。简单的说,就是遍历过程仅仅调用1次dom method。
如果是树状结构,我们缓存结果的遍历过程,就只有两种可能:
- element.firstChild + element.nextSibling
- element.children
我们曾经做过测试,一个稍微复杂的页面(一个门户站首页改版前的页面)。
- children遍历是最慢的,超过1s
- firstChild + nextSibling是400多ms
- getElementsByTagName('*')是100多ms
所以,我想说,initChildren支持自动树状结构,性能的2-3倍损失,我们为了什么?得到了什么?开发更方便?
曾经灰大说过,esui是他见过设计比较奇怪,但是性能最高的ui组件库。其实,很多设计,很多不做的事情,都是为性能做的考虑。
from esui.
首先有一点,事实上这个initChildren
的问题,本质上是main.init
的问题。而main.init
是会给业务开发人员用到的,如果main.init
没有生成树型的结构,业务开发人员主没办法通过树型的结构去取到自己要的东西,而被迫使用比较容易重复的id
来做这事,这在多人协同的情况下更容易出乱子。
以DOM作为比较,我们可以用getElementById
获取唯一的元素,但同时也提供通过children
的层级查找,不然jQuery的选择器也没有意义了。所以我认为我们不应该放弃main.init
实现树状,并且让业务开发者可以用children
的可能性。(似乎children
和getChild
的设计也不是私有的,业务人员应该去用)
抛开上面这个,再来谈谈后面的几个问题。
@errorrik 提的前面的几个问题均认可,就是__childName__
的形式不大愿意接受,理由是无端洁癖不解释,当然为了解决洁癖必然要有方案提出来,见下文。
关键点在性能上,这个非常重要,所以我尝试设计了一个方式,可以维护性能不会明显降低的情况下实现层级结构的initChildren
,以下是一个main.init
方法的伪代码,我没验证是否正确,就请 @errorrik 看下能不能实现并保证正确性吧:
function init(wrap) {
var elements = wrap.getElementsByTagName('*');
elements = toArray(elements);
var controls = [];
var map = {};
for (var i = 0; i < elements; i++) {
var element = elements[i];
if (isControl(element)) { // 判断`data-ui`
var control = createControl(element):
map[control.id] = control;
element.setAttribute('data-ui-id', control.id);
var parent = findParent(wrap, element);
if (parent) {
parent.addChild(control);
}
else {
controls.push(control);
}
}
}
return controls;
}
function findParent(wrap, element, map) {
var parent = element.parentNode;
while (parent !== wrap
&& parent.hasAttribute('data-ui-id')) {
parent = parent.parentNode;
}
if (parent !== wrap) {
return map[parent.getAttribute('data-ui-id')];
}
return null;
}
这套方案基于2个前提:
getElementsByTagName
返回的元素顺序是 深度优先的 ,因此 当前元素的父元素肯定已经被处理过- DOM的深度层级通常不会太深,因此作纵向的遍历不会有太多消耗
因此就使用一个Map管理已经处理过的元素与控件的对应关系,并在元素上通过data-ui-id
(用户可能也会写上这属性,所以这属性加上也无所谓)标记对应的键并声明这个元素是一个控件。当子元素发现自己的某个祖先元素(不超过wrap
范围)是控件时,通过id自动加到这个控件里去,并且不在返回的数组中。
我认为一般DOM的深度有5层就非常可观了,且通常来说往上找1-2层肯定能遇上控件,多层普通HTML元素里套一个控件的场景不多(我特地去看了下CLB现在的状态,确实不多或者说非常之少),因此这个方案的性能开销,相当于每个元素多读1次parentNode
并在parentNode
上多读一次data-ui-id
属性,感情上不觉得有很大开销。
同时通过 先移除wrap,处理完再放回来 也能提升不少的性能(直觉上这样不会有问题),因此我觉得性能 并非不可突破的屏障 ,至少绝对不会有 2-3倍的损失 。
from esui.
这个问题,我想听听大家意见,不想我们两个人就敲了。还有人来讨论不。。。
from esui.
两位已经把创建树和不创建树的优缺点讲的很透彻了,我还是倾向 不创建树,效率优先 。
创建树的优点是多人协同下,可以解决childName
冲突的问题,不容易出乱子。
但是我理解,控件的开发会在充分了解现有代码的基础上进行,这样的冲突场景不会太多。
所以我认为引入子控件树增加了复杂度,收益可能并没有那么高,不如保持简单。
from esui.
于是我没什么意见,有讨论理清思路就好,就按不创建树来做吧,这边的几个控件发了一下以后也较容易兼容了这种模式,我想其他人也不会来参与了,关了吧?
from esui.
Related Issues (20)
- 日程投放控件 HOT 4
- InputCollection 应当继承 ControlCollection HOT 1
- Table 的 overflowX 属性为非 hidden 的时候多出一个横向滚动条 HOT 3
- BoxGroup有一处事件没使用addDOMEvent绑定
- 解决set和setProperties触发change的问题
- Table的依赖不全
- 控件初始化子控件时的valueReplacer管理
- 控件初始化子控件时的valueReplacer管理
- 控件初始化子控件时的valueReplacer管理
- 指定元素的销毁子控件
- Select 控件对于value比较判断的兼容性问题 HOT 2
- 希望能添加一些布局相关的组件 HOT 4
- 对于带有数据源的控件是否应该支持外部不提供数据源的场景的表决 HOT 19
- addChild的时候添加校验 HOT 6
- viewContext的疑问 HOT 3
- 加个Lisence HOT 1
- MonthView的年月下拉框格式可调 HOT 1
- 渐变背景的问题
- Panel控件的addContent方法不适用table布局 HOT 2
- 关于拓展组件
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from esui.