选择器 API
编辑控件通常需要直接访问控件对象。然而,把所有可变对象分配给变量会将UI代码弄得一团乱。因此,Tabris.js API 提供了通过某些属性查找控件的方法,甚至一次操作多个控件。可以通过类型、ID、class 属性或基于CSS的格式来选择控件。
通过类型选择控件
根据控件类型选择控件是最简单的方法。例如,下面的代码会取消页面中所有选择框的选中状态:
page.find('CheckBox').set('selection', false);
通过ID选择控件
控件的id
属性和其他属性一样。它的初始值是undefined,因此你需要自己为控件指定ID。通常在创建控件时需要这样做:
new Button({id: 'submit'});
为了使用ID选择控件,可以使用选择器表达式'#id'
,其中 id
是控件的ID:
page.find('#submit').set('enabled', false);
ID应该是唯一的。尽管这不是框架强制要求的,但在组件中不使用相同的ID是比较好的实践,以避免混淆。
通过class属性选择控件
class
是用空格分割“class”列表的一个字符串。class是一个状态或类别的名字,从而使控件能够被辨识。它只能包含字母、数字、_
和 -
。
new TextView({class: 'label important'});
Class可以混用、复用,并且可以在任何控件上、在任何时间改变。使用classList
属性是比较方便的方式:
textView.classList.push('important');
为了使用class选择控件,使用选择器表达式'.class'
,其中 class
是class名:
page.find('.important').set('textColor', 'red');
选择器表达式
支持下面的选择器表达式:
'*'
匹配全部控件。'Type'
匹配类型是所提供类型的控件,比如'Button'
匹配全部Button控件。'.class'
匹配class列表中具有所提供class的控件,比如'.foo'
匹配class
被设置为'foo'
的控件,但也匹配'foo bar
。'#id'
匹配具有所提供ID的控件,例如'#foo'
匹配所有ID是'foo'
的控件。
选择器函数
所有接受选择器表达式的方法也可以以一个函数作为参数来调用,从而检测集合中的每一个控件。为每个控件调用该函数,如果函数返回true
就包含控件,返回false
则跳过。比如,下面的代码片段会选择页面中所有可见的控件:
let visibleChildren = page.children(widget => widget.visible);
使用选择器
下面的控件方法接收选择器表达式作为参数:
widget.find(selector)
选择匹配选择器的所有后代。widget.children(selector)
选择匹配选择器的所有直接子控件,但不包括更深层次的控件。widget.siblings(selector)
选择匹配选择器的所有兄弟控件。
这些方法返回一个WidgetCollection。你可以使用first()
和 last()
,或者使用数组索引获取集合中的控件:
let submitButton = page.find('#submit').first(); // or
let submitButton = page.find('#submit')[0];
你也可以为选择的控件设置属性,而不用获取它们:
page.find('.input').set('enabled', false);
apply方法
配置组件中的多个控件的高效方式是,在父控件中使用 apply()
方法。
apply方法的原理
apply({<selector: properties>*})
apply方法只需调用一次,就可以用选择器将不同的属性集合应用到不同的控件上。比如,将背景颜色应用到页面中的所有控件,可以这样调用:
page.apply({'*': {background: 'green'}});
你可以将不同的属性设置到不同的控件上:
page.apply({
'#okbutton': {text: 'OK!', background: 'yellow'},
'#cancelbutton': {text: 'Cancel!', textColor: 'red'}
});
这些属性被应用的顺序,取决于选择器的类型。顺序是:
'*'
>'Type'
>'.class'
>'#id'
例如,下面的调用会把所有的控件设置为蓝色,但Button
是绿色、'#mybutton'
是红色。
page.apply({
'#mybutton': {background: 'red'},
'Button': {background: 'green'},
'*': {background: 'blue'}
});
在对象字面量中看到的属性顺序是没有意义的。因为在EcmaScript标准中,JavaScript对象成员没有明确的顺序。
如何使用
虽然我们在上面的示例中使用的是对象字面量,但是apply方法可以非常高效地与模块一起使用,从而可以从代码中获取大多数或所有属性值(除了ID)。
试想一下,比如,你想根据地区为控件设置不同的文字。你可以这样做:
let lang = device.language;
try {
page.apply(module.require('./texts-' + lang));
} catch() {
// fallback if the desired language file does not exist:
page.apply(module.require('./texts-en'));
}
由于JSON文件可以作为模块,语言文件可以(例如texts-en.json
)像下面这样:
{
'#okbutton': {'text': 'OK'},
'#cancelbutton': {'text': 'Cancel'}
}
另一种模式是始终使用相同的模块…
page.apply(module.require('./texts'));
然后使用模块中的脚本计算实际值:
let texts = {
en: {
'#okbutton': {text: 'OK!'}
'#cancelbutton': {text: 'Cancel!'}
},
//...
};
module.exports = texts[device.language] || texts.en;
同样的模式也可以用来设置针对不同平台的颜色、基于屏幕宽度的字体大小、或取决于设备方向的布局数据:
page.on('resize', ({width, height}) => {
page.apply(require('./layout-' + (width > height) ? 'landscape' : 'portrait'));
});
最好是以页面的长宽比为基础来布局,而不是依据设备的方向。这是因为当设备旋转方向时,页面会先重新计算,然后再用动画旋转。而且,在未来的tabris.js版本中,页面可能并不总是和屏幕保持相同的长宽比。