选择器 API

编辑控件通常需要直接访问控件对象。然而,把所有可变对象分配给变量会将UI代码弄得一团乱。因此,Tabris.js API 提供了通过某些属性查找控件的方法,甚至一次操作多个控件。可以通过类型IDclass 属性或基于CSS的格式来选择控件。

通过类型选择控件

根据控件类型选择控件是最简单的方法。例如,下面的代码会取消页面中所有选择框的选中状态:

  1. page.find('CheckBox').set('selection', false);

通过ID选择控件

控件的id属性和其他属性一样。它的初始值是undefined,因此你需要自己为控件指定ID。通常在创建控件时需要这样做:

  1. new Button({id: 'submit'});

为了使用ID选择控件,可以使用选择器表达式'#id',其中 id 是控件的ID:

  1. page.find('#submit').set('enabled', false);

ID应该是唯一的。尽管这不是框架强制要求的,但在组件中不使用相同的ID是比较好的实践,以避免混淆。

通过class属性选择控件

class是用空格分割“class”列表的一个字符串。class是一个状态或类别的名字,从而使控件能够被辨识。它只能包含字母、数字、_-

  1. new TextView({class: 'label important'});

Class可以混用、复用,并且可以在任何控件上、在任何时间改变。使用classList属性是比较方便的方式:

  1. textView.classList.push('important');

为了使用class选择控件,使用选择器表达式'.class',其中 class 是class名:

  1. page.find('.important').set('textColor', 'red');

选择器表达式

支持下面的选择器表达式:

  • '*' 匹配全部控件。
  • 'Type' 匹配类型是所提供类型的控件,比如'Button' 匹配全部Button控件。
  • '.class' 匹配class列表中具有所提供class的控件,比如'.foo' 匹配class被设置为'foo'的控件,但也匹配'foo bar。
  • '#id' 匹配具有所提供ID的控件,例如'#foo' 匹配所有ID是'foo'的控件。

    选择器函数

所有接受选择器表达式的方法也可以以一个函数作为参数来调用,从而检测集合中的每一个控件。为每个控件调用该函数,如果函数返回true就包含控件,返回false则跳过。比如,下面的代码片段会选择页面中所有可见的控件:

  1. let visibleChildren = page.children(widget => widget.visible);

使用选择器

下面的控件方法接收选择器表达式作为参数:

  • widget.find(selector) 选择匹配选择器的所有后代。
  • widget.children(selector) 选择匹配选择器的所有直接子控件,但不包括更深层次的控件。
  • widget.siblings(selector) 选择匹配选择器的所有兄弟控件。
    这些方法返回一个WidgetCollection。你可以使用first()last(),或者使用数组索引获取集合中的控件:
  1. let submitButton = page.find('#submit').first(); // or
  2. let submitButton = page.find('#submit')[0];

你也可以为选择的控件设置属性,而不用获取它们:

  1. page.find('.input').set('enabled', false);

apply方法

配置组件中的多个控件的高效方式是,在父控件中使用 apply() 方法。

apply方法的原理

  • apply({*})
    apply方法只需调用一次,就可以用选择器将不同的属性集合应用到不同的控件上。比如,将背景颜色应用到页面中的所有控件,可以这样调用:
  1. page.apply({'*': {background: 'green'}});

你可以将不同的属性设置到不同的控件上:

  1. page.apply({
  2. '#okbutton': {text: 'OK!', background: 'yellow'},
  3. '#cancelbutton': {text: 'Cancel!', textColor: 'red'}
  4. });

这些属性被应用的顺序,取决于选择器的类型。顺序是:

  • '*' > 'Type' > '.class' > '#id'
    例如,下面的调用会把所有的控件设置为蓝色,但Button是绿色、'#mybutton'是红色。
  1. page.apply({
  2. '#mybutton': {background: 'red'},
  3. 'Button': {background: 'green'},
  4. '*': {background: 'blue'}
  5. });
:point_right: 在对象字面量中看到的属性顺序是没有意义的。因为在EcmaScript标准中,JavaScript对象成员没有明确的顺序。

如何使用

虽然我们在上面的示例中使用的是对象字面量,但是apply方法可以非常高效地与模块一起使用,从而可以从代码中获取大多数或所有属性值(除了ID)。

试想一下,比如,你想根据地区为控件设置不同的文字。你可以这样做:

  1. let lang = device.language;
  2. try {
  3. page.apply(module.require('./texts-' + lang));
  4. } catch() {
  5. // fallback if the desired language file does not exist:
  6. page.apply(module.require('./texts-en'));
  7. }

由于JSON文件可以作为模块,语言文件可以(例如texts-en.json)像下面这样:

  1. {'#okbutton':{'text':'OK'},'#cancelbutton':{'text':'Cancel'}}

另一种模式是始终使用相同的模块…

  1. page.apply(module.require('./texts'));

然后使用模块中的脚本计算实际值:

  1. let texts = {
  2. en: {
  3. '#okbutton': {text: 'OK!'}
  4. '#cancelbutton': {text: 'Cancel!'}
  5. },
  6. //...
  7. };
  8. module.exports = texts[device.language] || texts.en;

同样的模式也可以用来设置针对不同平台的颜色、基于屏幕宽度的字体大小、或取决于设备方向的布局数据:

  1. page.on('resize', ({width, height}) => {
  2. page.apply(require('./layout-' + (width > height) ? 'landscape' : 'portrait'));
  3. });
:point_right:最好是以页面的长宽比为基础来布局,而不是依据设备的方向。这是因为当设备旋转方向时,页面会先重新计算,然后再用动画旋转。而且,在未来的tabris.js版本中,页面可能并不总是和屏幕保持相同的长宽比。

原文:

https://youjingyu.github.io/Tabris-Documention/?folderName=guide&pageName=selector.html