Dart语法糖

(十三)Dart正则表达式及常用的APIs、类、工具

2020-01-05  本文已影响0人  小哥_xiaoge

一、Dart正则表达式

RegExp 类提供了类似 JavaScript 正则表达式同样的功能。 正则表达式可以高效率的搜索和匹配 字符串。

// Here's a regular expression for one or more digits.
var numbers = new RegExp(r'\d+');

var allCharacters = 'llamas live fifteen to twenty years';
var someDigits = 'llamas live 15 to 20 years';

// contains() can use a regular expression.
assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// Replace every match with another string.
var exedOut = someDigits.replaceAll(numbers, 'XX');
assert(exedOut == 'llamas live XX to XX years');

还可以直接操作 RegExp 类。Match 类提供了 访问正则表达式匹配到的内容。

var numbers = new RegExp(r'\d+');
var someDigits = 'llamas live 15 to 20 years';

// Check whether the reg exp has a match in a string.
assert(numbers.hasMatch(someDigits));

// Loop through all matches.
for (var match in numbers.allMatches(someDigits)) {

  /**
   * Returns the string matched by the given [group].
   *
   * If [group] is 0, returns the match of the pattern.
   *
   * The result may be `null` if the pattern didn't assign a value to it
   * as part of this match.
   */
  print(match.group(0)); // 15, then 20
}

二、Iteration

2.1. Iterable 类

List, Set, 和 Map 上可以使用很多常用的集合函数。 Iterable 类定义了一些常用的功能, List 和 Set 实现了 Iterable

注意: 虽然 Map 没有实现 Iterable,但是 Map 的 keys 和 values 属性实现了 Iterable

var teas = ['green', 'black', 'chamomile', 'earl grey'];
teas.forEach((tea) => print('I drink $tea'));
hawaiianBeaches.forEach((k, v) {
  print('I want to visit $k and swim at $v');
  // I want to visit Oahu and swim at
  // [Waikiki, Kailua, Waimanalo], etc.
});
var teas = ['green', 'black', 'chamomile', 'earl grey'];

var loudTeas = teas.map((tea) => tea.toUpperCase());
loudTeas.forEach(print);

注意: map() 函数返回的对象也是一个 Iterable,该对象是懒求值(lazily evaluated) 的,只有当访问里面的值的时候, map 的方法才被调用。

var loudTeaList = teas
    .map((tea) => tea.toUpperCase())
    .toList();
var teas = ['green', 'black', 'chamomile', 'earl grey'];

// Chamomile is not caffeinated.
bool isDecaffeinated(String teaName) =>
    teaName == 'chamomile';

// Use where() to find only the items that return true
// from the provided function.
var decaffeinatedTeas = teas
    .where((tea) => isDecaffeinated(tea));
// or teas.where(isDecaffeinated)

// Use any() to check whether at least one item in the
// collection satisfies a condition.
assert(teas.any(isDecaffeinated));

// Use every() to check whether all the items in a
// collection satisfy a condition.
assert(!teas.every(isDecaffeinated));

2.2. Iteration

IterableIterator 类支持 for-in 循环。当你创建一个类的时候,继承或者实现 Iterable 可以 提供一个用于 for-in 循环的 Iterators。 实现 Iterator 来定义实际的遍历操作。

class Process {
  // Represents a process...
}

class ProcessIterator implements Iterator<Process> {
  Process current;
  bool moveNext() {
    return false;
  }
}

// A mythical class that lets you iterate through all
// processes. Extends a subclass of Iterable.
class Processes extends IterableBase<Process> {
  final Iterator<Process> iterator =
      new ProcessIterator();
}

main() {
  // Iterable objects can be used with for-in.
  for (var process in new Processes()) {
    // Do something with the process.
  }
}

三、Dates and times

DateTime 对象代表某个时刻。时区是 UTC 或者 本地时区。

一些构造函数可以创建 DateTime 对象:

// Get the current date and time.
var now = new DateTime.now();

// Create a new DateTime with the local time zone.
var y2k = new DateTime(2000);   // January 1, 2000

// Specify the month and day.
y2k = new DateTime(2000, 1, 2); // January 2, 2000

// Specify the date as a UTC time.
y2k = new DateTime.utc(2000);   // 1/1/2000, UTC

// Specify a date and time in ms since the Unix epoch.
y2k = new DateTime.fromMillisecondsSinceEpoch(
    946684800000, isUtc: true);

// Parse an ISO 8601 date.
y2k = DateTime.parse('2000-01-01T00:00:00Z');
// 1/1/2000, UTC
y2k = new DateTime.utc(2000);
assert(y2k.millisecondsSinceEpoch == 946684800000);

// 1/1/1970, UTC
var unixEpoch = new DateTime.utc(1970);
assert(unixEpoch.millisecondsSinceEpoch == 0);
var y2k = new DateTime.utc(2000);

// Add one year.
var y2001 = y2k.add(const Duration(days: 366));
assert(y2001.year == 2001);

// Subtract 30 days.
var december2000 = y2001.subtract(
    const Duration(days: 30));
assert(december2000.year == 2000);
assert(december2000.month == 12);

// Calculate the difference between two dates.
// Returns a Duration object.
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k was a leap year.

警告: 使用 Duration 来在 DateTime 对象上前后移动数天可能会有问题, 比如像夏令时等时间问题。如果要按照天数来位移时间,则 需要使用 UTC 日期。

更多详细信息参考 DateTimeDuration 的 API 文档。

四、Math 库

Math 库提供了常见的数学运算功能,例如 sine 和 cosine, 最大值、最小值等,还有各种常量 例如 pi 和 e 等。Math 库中 的大部分函数都是顶级方法。

导入 dart:math 就可以使用 Math 库了。 下面的示例代码使用前缀 math 来引用库中的顶级 方法和常量:

import 'dart:math' as math;

4.1. Trigonometry(三角函数)

Math 库中提供了常见的三角运算功能:

// Cosine
assert(math.cos(math.PI) == -1.0);

// Sine
var degrees = 30;
var radians = degrees * (math.PI / 180);
// radians is now 0.52359.
var sinOf30degrees = math.sin(radians);
// sin 30° = 0.5
assert((sinOf30degrees - 0.5).abs() < 0.01);

注意: 上面这些函数是基于弧度的不是基于角度的。

4.2.Maximum and minimum(最大和最小)

Math 库提供了 max()min() 函数用来计算最大值和最小值:

assert(math.max(1, 1000) == 1000);
assert(math.min(1, -1000) == -1000);

4.3.Math constants(数学宏)

Math 库中提供各种数学常量,例如 pi, e 等。

// See the Math library for additional constants.
print(math.E);     // 2.718281828459045
print(math.PI);    // 3.141592653589793
print(math.SQRT2); // 1.4142135623730951

4.4.Random numbers(随机数)

使用 Random 类可以生成随机数。 在 Random 构造函数中还可以提供一个随机种子:

var random = new math.Random();
random.nextDouble(); // Between 0.0 and 1.0: [0, 1)
random.nextInt(10);  // Between 0 and 9.

也可以生成随机的布尔值:

var random = new math.Random();
random.nextBool();  // true or false

详细的信息可以参考 Math API 文档 来了解。 还可以参考下面这些类的 API 文档 numintdouble

五、dart:html - browser-based apps(基于APP的浏览器)

如果要和浏览器打交道则需要使用 dart:html 库, 访问 DOM 元素和使用 HTML5 API。 DOM 是 Document Object Model 的缩写,用来 描述 HTML 页面的结构。

dart:html 还可以用来操作样式表(CSS)、用 HTTP 请求 来获取数据,使用 WebSockets 来获取数据。 HTML5 (和 dart:html) 具有很多其他的 API 在这里并没有介绍。 只有 Web 应用可以使用 dart:html,命令行应用无法使用该库。

注意: 关于构建 Web 应用的更高层级的框架,请参考 Polymer DartAngular 2 for Dart

在 web 应用中导入 dart:html 就可以使用 HTML 相关的功能了:

import 'dart:html';

5.1.Manipulating the DOM(操纵DOM)

要使用 DOM 你需要了解 windows, documents, elements, 和 nodes 等概念。

一个 Window 对象代表 浏览器实际的窗口。每个窗口都有一个文档(Document)对象, 文档对象是当前正在加载的界面。Window 对象还可以访问各种 API,例如 用于存储数据的 IndexedDB、用于动画的 requestAnimationFrame 等。 在多窗口浏览器中,每个窗口(tab 也)都有 自己的 Window 对象。

使用 Document 对象, 可以创建和操纵 document 中的 Elements 对象。 注意 Document 本身也是一个 element,也是可以 被修改的。

DOM 模型是很多 Nodes 组成的树状结构。这些 nodes 通常 是 elements,但是也可以是 attributes、 text、 comments、 和其他 DOM 类型。 除了跟节点没有父节点以外,其他 DOM 中的节点都有一个 父节点,还有可能带有很多子节点。

5.2. Finding elements(找元素)

在操作一个 element 之前,你需要先找到这个 element。 使用查询语法可以查找所需要的 element。

使用顶级方法 querySelector()querySelectorAll() 可以查找一个或者多个符合条件的 element。可以根据 ID、class、tag、name 或者 这些的组合来查询 element。 CSS 选择器 规范 定义了选择器的形式, 例如使用 # 前缀代表 ID,英文句号 (.) 代表 classes。

使用 querySelector() 方法可以获取第一个符合选择器要求的元素; 而 querySelectorAll() 返回所有符合 选择器要求的元素结合。

// Find an element by id (an-id).
Element elem1 = querySelector('#an-id');

// Find an element by class (a-class).
Element elem2 = querySelector('.a-class');

// Find all elements by tag (<div>).
List<Element> elems1 = querySelectorAll('div');

// Find all text inputs.
  List<Element> elems2 =
      querySelectorAll('input[type="text"]');

// Find all elements with the CSS class 'class'
// inside of a <p> that is inside an element with
// the ID 'id'.
List<Element> elems3 = querySelectorAll('#id p.class');

5.3.Manipulating elements(操作元素)

可以使用属性(properties)来修改 element 的状态。 Node 和子类型 Element 定义了所有 element 都具有的属性。例如, 所有 element 都有 classes, hidden, id, style, 和 title 属性,你可以使用这些属性来修改 element 的状态。 Element 的 子类还定义了其他属性,比如 AnchorElement 定义了 href 属性。

例如下面的示例在 HTML 中设置一个锚链接:

<a id="example" href="http://example.com">link text</a>

<a> 标签使用 href 定义了一个 element 和一个包含文字 “linktext” 的 text node(使用 text 属性访问)。使用 AnchorElementhref 属性 可以修改点击该链接跳转的地址:

querySelector('#example').href = 'http://dartlang.org';

通常你需要在多个 element 上设置属性。例如,下面的示例在 所有 class 样式带有 “mac”, “win”, 或者 “linux” 的 element 上设置 hidden 属性。设置 hidden 属性为 true 和 设置 CSS 样式 display:none 是同样的效果。

<!-- In HTML: -->
<p>
  <span class="linux">Words for Linux</span>
  <span class="macos">Words for Mac</span>
  <span class="windows">Words for Windows</span>
</p>

// In Dart:
final osList = ['macos', 'windows', 'linux'];

// In real code you'd programmatically determine userOs.
var userOs = 'linux';

for (var os in osList) { // For each possible OS...
  bool shouldShow = (os == userOs); // Matches user OS?

  // Find all elements with class=os. For example, if
  // os == 'windows', call querySelectorAll('.windows')
  // to find all elements with the class "windows".
  // Note that '.$os' uses string interpolation.
  for (var elem in querySelectorAll('.$os')) {
    elem.hidden = !shouldShow; // Show or hide.
  }
}

当属性不能访问或者不方便访问的时候,可以使用 Element 的 attributes 属性。 这个属性是一个Map<String, String>,里面的 key 为属性名字。所有 HTML 元素的 属性名字以及意义,请参考 MDN Attributes 网页。下面是一个设置 属性值的示例:

elem.attributes['someAttribute'] = 'someValue';

5.4.Creating elements(创建元素)

还可以创建新的 element 然后添加到 HTML 页面的 DOM 中。下面的示例创建了一个 段落 (<p>) 元素:

var elem = new ParagraphElement();
elem.text = 'Creating is easy!';

使用 HTML 文本也可以创建 element。所包含的子元素 也一起被创建:

var elem2 =
    new Element.html('<p>Creating <em>is</em> easy!</p>');

注意上面的 elem2 对象是一个 ParagraphElement 。

给新创建的 Element 指定一个父节点可以把这个 Element 添加到 DOM 中。 可以把 Element 添加到任何已经存在于 DOM 中的其他 Element 的 children 中。 例如,下面的示例,body 是一个 element,使用 children 属性来 访问该元素的所有子元素(返回的是一个 List<Element>),然后把新的 elem2 添加 到子元素集合中。

document.body.children.add(elem2);

5.5.Adding, replacing, and removing nodes(添加、替换、移除节点)

之前说过,element 也是 node 的一种。使用 Node 的 nodes 属性可以 获取到当前 node 的所有子元素,nodes 返回的是 List<Node> ( children 属性只包含 Element 类型的 nodes)。 获取到这个 Node list 后,就可以使用 List 的各种函数来 处理这些 Node 对象了。

使用 List 的add() 函数可以把一个 node 添加到所有子元素的 最后:

// Find the parent by ID, and add elem as its last child.
querySelector('#inputs').nodes.add(elem);

使用 Node 的 replaceWith() 函数可以替换一个 Node:

// Find a node by ID, and replace it in the DOM.
querySelector('#status').replaceWith(elem);

使用 Node 的 remove() 函数来删除 node:

/ Find a node by ID, and remove it from the DOM.
querySelector('#expendable').remove();

5.6.Manipulating CSS styles(操纵CSS 样式)

CSS(cascading style sheets 的缩写)定义了 DOM 元素的 UI 样式。 在一个 element 上附加 IDclass 属性可以修改 其应用的 CSS 样式。

没有 element 都有一个 classes 属性(field),该属性的类型为 List。 添加和移除上面的 CSS 类就是向这个集合中添加和删除字符串。 流入,下面的示例中给 element 添加了 warning CSS 类样式。

var element = querySelector('#message');
element.classes.add('warning');

通过 ID 来查找元素非常高效。通过 id属性你可以动态给一个 Element 指定 一个 ID 值。

var message = new DivElement();
message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing list.';

使用级联调用可以减少 需要编写的代码:

var message = new DivElement()
    ..id = 'message2'
    ..text = 'Please subscribe to the Dart mailing list.';

使用 ID 和 CSS 的 classes 来应用样式是最佳的方式,但是有时候 你还是希望直接在 element 上应用具体的样式,则 可以直接使用 style 属性:

message.style
    ..fontWeight = 'bold'
    ..fontSize = '3em';

5.7.Handling events(处理事件)

要响应像点击、聚焦等外部事件,你需要使用事件监听器。 在页面上的任何 element 上都可以注册事件监听器。 事件分发和传递是一个很复杂的议题: 如果你是 Web 开发新手, 请到 这里来 详细研究这个事件分发机制

使用 *element*.on*Event*.listen(*function*)来添加事件监听器, 这里的 *Event* 是事件的名字,而*function* 是事件处理器。

例如,下面是处理按钮点击的事件:

// Find a button by ID and add an event handler.
querySelector('#submitInfo').onClick.listen((e) {
  // When the button is clicked, it runs this code.
  submitData();
});

事件可以通过 DOM 树来向上或者向下传递。 通过 e.target 可以获取是那个 element 触发该事件的:

document.body.onClick.listen((e) {
  var clickedElem = e.target;
  print('You clicked the ${clickedElem.id} element.');
});

要查看所有可以注册的事件名字,可以查看 Element 文档中的 “onEventType” 属性。 下面是一些常见的事件:

上一篇下一篇

猜你喜欢

热点阅读