(十三)Dart正則表達(dá)式及常用的APIs、類、工具

一、Dart正則表達(dá)式

RegExp 類提供了類似 JavaScript 正則表達(dá)式同樣的功能。 正則表達(dá)式可以高效率的搜索和匹配 字符串。

// 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 類提供了 訪問(wèn)正則表達(dá)式匹配到的內(nèi)容。

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 上可以使用很多常用的集合函數(shù)。 Iterable 類定義了一些常用的功能, List 和 Set 實(shí)現(xiàn)了 Iterable 。

注意: 雖然 Map 沒(méi)有實(shí)現(xiàn) Iterable,但是 Map 的 keys 和 values 屬性實(shí)現(xiàn)了 Iterable。

  • 使用 forEach() 函數(shù)可以對(duì)集合中的每個(gè)數(shù)據(jù)都應(yīng)用 一個(gè)方法:
var teas = ['green', 'black', 'chamomile', 'earl grey'];
teas.forEach((tea) => print('I drink $tea'));
  • 在 Map 上使用 forEach() 的時(shí)候,方法需要能 接收兩個(gè)參數(shù)(key 和 value):
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.
});
  • Iterables 也有一個(gè) map() 函數(shù),這個(gè)函數(shù)返回一個(gè)包含所有數(shù)據(jù)的對(duì)象:
var teas = ['green', 'black', 'chamomile', 'earl grey'];

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

注意: map() 函數(shù)返回的對(duì)象也是一個(gè) Iterable,該對(duì)象是懶求值(lazily evaluated) 的,只有當(dāng)訪問(wèn)里面的值的時(shí)候, map 的方法才被調(diào)用。

  • 可以使用 map().toList() 或者 map().toSet() 來(lái) 強(qiáng)制立刻執(zhí)行 map 的方法:
var loudTeaList = teas
    .map((tea) => tea.toUpperCase())
    .toList();
  • Iterablewhere() 函數(shù)可以返回所有滿足特定條件的數(shù)據(jù)。 any() 判斷是否有數(shù)據(jù)滿足特定條件, every() 判斷是否所有數(shù)據(jù)都滿足 特定條件。
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 循環(huán)。當(dāng)你創(chuàng)建一個(gè)類的時(shí)候,繼承或者實(shí)現(xiàn) Iterable 可以 提供一個(gè)用于 for-in 循環(huán)的 Iterators。 實(shí)現(xiàn) Iterator 來(lái)定義實(shí)際的遍歷操作。

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 對(duì)象代表某個(gè)時(shí)刻。時(shí)區(qū)是 UTC 或者 本地時(shí)區(qū)。

一些構(gòu)造函數(shù)可以創(chuàng)建 DateTime 對(duì)象:

// 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');
  • millisecondsSinceEpoch 屬性返回自從 “Unix epoch”—January 1, 1970, UTC 以來(lái)的毫秒數(shù)值:
// 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);
  • 使用 Duration 類可以計(jì)算兩個(gè)日期之間的間隔, 還可以前后位移日期:
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 來(lái)在 DateTime 對(duì)象上前后移動(dòng)數(shù)天可能會(huì)有問(wèn)題, 比如像夏令時(shí)等時(shí)間問(wèn)題。如果要按照天數(shù)來(lái)位移時(shí)間,則 需要使用 UTC 日期。

更多詳細(xì)信息參考 DateTimeDuration 的 API 文檔。

四、Math 庫(kù)

Math 庫(kù)提供了常見的數(shù)學(xué)運(yùn)算功能,例如 sine 和 cosine, 最大值、最小值等,還有各種常量 例如 pi 和 e 等。Math 庫(kù)中 的大部分函數(shù)都是頂級(jí)方法。

導(dǎo)入 dart:math 就可以使用 Math 庫(kù)了。 下面的示例代碼使用前綴 math 來(lái)引用庫(kù)中的頂級(jí) 方法和常量:

import 'dart:math' as math;

4.1. Trigonometry(三角函數(shù))

Math 庫(kù)中提供了常見的三角運(yùn)算功能:

// 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);

注意: 上面這些函數(shù)是基于弧度的不是基于角度的。

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

Math 庫(kù)提供了 max()min() 函數(shù)用來(lái)計(jì)算最大值和最小值:

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

4.3.Math constants(數(shù)學(xué)宏)

Math 庫(kù)中提供各種數(shù)學(xué)常量,例如 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(隨機(jī)數(shù))

使用 Random 類可以生成隨機(jī)數(shù)。 在 Random 構(gòu)造函數(shù)中還可以提供一個(gè)隨機(jī)種子:

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

也可以生成隨機(jī)的布爾值:

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

詳細(xì)的信息可以參考 Math API 文檔 來(lái)了解。 還可以參考下面這些類的 API 文檔 num、 intdouble。

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

如果要和瀏覽器打交道則需要使用 dart:html 庫(kù), 訪問(wèn) DOM 元素和使用 HTML5 API。 DOM 是 Document Object Model 的縮寫,用來(lái) 描述 HTML 頁(yè)面的結(jié)構(gòu)。

dart:html 還可以用來(lái)操作樣式表(CSS)、用 HTTP 請(qǐng)求 來(lái)獲取數(shù)據(jù),使用 WebSockets 來(lái)獲取數(shù)據(jù)。 HTML5 (和 dart:html) 具有很多其他的 API 在這里并沒(méi)有介紹。 只有 Web 應(yīng)用可以使用 dart:html,命令行應(yīng)用無(wú)法使用該庫(kù)。

注意: 關(guān)于構(gòu)建 Web 應(yīng)用的更高層級(jí)的框架,請(qǐng)參考 Polymer DartAngular 2 for Dart。

在 web 應(yīng)用中導(dǎo)入 dart:html 就可以使用 HTML 相關(guān)的功能了:

import 'dart:html';

5.1.Manipulating the DOM(操縱DOM)

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

一個(gè) Window 對(duì)象代表 瀏覽器實(shí)際的窗口。每個(gè)窗口都有一個(gè)文檔(Document)對(duì)象, 文檔對(duì)象是當(dāng)前正在加載的界面。Window 對(duì)象還可以訪問(wèn)各種 API,例如 用于存儲(chǔ)數(shù)據(jù)的 IndexedDB、用于動(dòng)畫的 requestAnimationFrame 等。 在多窗口瀏覽器中,每個(gè)窗口(tab 也)都有 自己的 Window 對(duì)象。

使用 Document 對(duì)象, 可以創(chuàng)建和操縱 document 中的 Elements 對(duì)象。 注意 Document 本身也是一個(gè) element,也是可以 被修改的。

DOM 模型是很多 Nodes 組成的樹狀結(jié)構(gòu)。這些 nodes 通常 是 elements,但是也可以是 attributes、 text、 comments、 和其他 DOM 類型。 除了跟節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn)以外,其他 DOM 中的節(jié)點(diǎn)都有一個(gè) 父節(jié)點(diǎn),還有可能帶有很多子節(jié)點(diǎn)。

5.2. Finding elements(找元素)

在操作一個(gè) element 之前,你需要先找到這個(gè) element。 使用查詢語(yǔ)法可以查找所需要的 element。

使用頂級(jí)方法 querySelector()querySelectorAll() 可以查找一個(gè)或者多個(gè)符合條件的 element??梢愿鶕?jù) ID、class、tag、name 或者 這些的組合來(lái)查詢 element。 CSS 選擇器 規(guī)范 定義了選擇器的形式, 例如使用 # 前綴代表 ID,英文句號(hào) (.) 代表 classes。

使用 querySelector() 方法可以獲取第一個(gè)符合選擇器要求的元素; 而 querySelectorAll() 返回所有符合 選擇器要求的元素結(jié)合。

// 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)來(lái)修改 element 的狀態(tài)。 Node 和子類型 Element 定義了所有 element 都具有的屬性。例如, 所有 element 都有 classes, hidden, id, style, 和 title 屬性,你可以使用這些屬性來(lái)修改 element 的狀態(tài)。 Element 的 子類還定義了其他屬性,比如 AnchorElement 定義了 href 屬性。

例如下面的示例在 HTML 中設(shè)置一個(gè)錨鏈接:

<a id="example" >link text</a>

<a> 標(biāo)簽使用 href 定義了一個(gè) element 和一個(gè)包含文字 “l(fā)inktext” 的 text node(使用 text 屬性訪問(wèn))。使用 AnchorElementhref 屬性 可以修改點(diǎn)擊該鏈接跳轉(zhuǎn)的地址:

querySelector('#example').;

通常你需要在多個(gè) element 上設(shè)置屬性。例如,下面的示例在 所有 class 樣式帶有 “mac”, “win”, 或者 “l(fā)inux” 的 element 上設(shè)置 hidden 屬性。設(shè)置 hidden 屬性為 true 和 設(shè)置 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.
  }
}

當(dāng)屬性不能訪問(wèn)或者不方便訪問(wèn)的時(shí)候,可以使用 Element 的 attributes 屬性。 這個(gè)屬性是一個(gè)Map<String, String>,里面的 key 為屬性名字。所有 HTML 元素的 屬性名字以及意義,請(qǐng)參考 MDN Attributes 網(wǎng)頁(yè)。下面是一個(gè)設(shè)置 屬性值的示例:

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

5.4.Creating elements(創(chuàng)建元素)

還可以創(chuàng)建新的 element 然后添加到 HTML 頁(yè)面的 DOM 中。下面的示例創(chuàng)建了一個(gè) 段落 (<p>) 元素:

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

使用 HTML 文本也可以創(chuàng)建 element。所包含的子元素 也一起被創(chuàng)建:

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

注意上面的 elem2 對(duì)象是一個(gè) ParagraphElement 。

給新創(chuàng)建的 Element 指定一個(gè)父節(jié)點(diǎn)可以把這個(gè) Element 添加到 DOM 中。 可以把 Element 添加到任何已經(jīng)存在于 DOM 中的其他 Element 的 children 中。 例如,下面的示例,body 是一個(gè) element,使用 children 屬性來(lái) 訪問(wèn)該元素的所有子元素(返回的是一個(gè) List<Element>),然后把新的 elem2 添加 到子元素集合中。

document.body.children.add(elem2);

5.5.Adding, replacing, and removing nodes(添加、替換、移除節(jié)點(diǎn))

之前說(shuō)過(guò),element 也是 node 的一種。使用 Node 的 nodes 屬性可以 獲取到當(dāng)前 node 的所有子元素,nodes 返回的是 List<Node> ( children 屬性只包含 Element 類型的 nodes)。 獲取到這個(gè) Node list 后,就可以使用 List 的各種函數(shù)來(lái) 處理這些 Node 對(duì)象了。

使用 List 的add() 函數(shù)可以把一個(gè) node 添加到所有子元素的 最后:

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

使用 Node 的 replaceWith() 函數(shù)可以替換一個(gè) Node:

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

使用 Node 的 remove() 函數(shù)來(lái)刪除 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 樣式。 在一個(gè) element 上附加 IDclass 屬性可以修改 其應(yīng)用的 CSS 樣式。

沒(méi)有 element 都有一個(gè) classes 屬性(field),該屬性的類型為 List。 添加和移除上面的 CSS 類就是向這個(gè)集合中添加和刪除字符串。 流入,下面的示例中給 element 添加了 warning CSS 類樣式。

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

通過(guò) ID 來(lái)查找元素非常高效。通過(guò) id屬性你可以動(dòng)態(tài)給一個(gè) Element 指定 一個(gè) ID 值。

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

使用級(jí)聯(lián)調(diào)用可以減少 需要編寫的代碼:

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

使用 ID 和 CSS 的 classes 來(lái)應(yīng)用樣式是最佳的方式,但是有時(shí)候 你還是希望直接在 element 上應(yīng)用具體的樣式,則 可以直接使用 style 屬性:

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

5.7.Handling events(處理事件)

要響應(yīng)像點(diǎn)擊、聚焦等外部事件,你需要使用事件監(jiān)聽器。 在頁(yè)面上的任何 element 上都可以注冊(cè)事件監(jiān)聽器。 事件分發(fā)和傳遞是一個(gè)很復(fù)雜的議題: 如果你是 Web 開發(fā)新手, 請(qǐng)到 這里來(lái) 詳細(xì)研究這個(gè)事件分發(fā)機(jī)制

使用 *element*.on*Event*.listen(*function*)來(lái)添加事件監(jiān)聽器, 這里的 *Event* 是事件的名字,而*function* 是事件處理器。

例如,下面是處理按鈕點(diǎn)擊的事件:

// 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();
});

事件可以通過(guò) DOM 樹來(lái)向上或者向下傳遞。 通過(guò) e.target 可以獲取是那個(gè) element 觸發(fā)該事件的:

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

要查看所有可以注冊(cè)的事件名字,可以查看 Element 文檔中的 “onEventType” 屬性。 下面是一些常見的事件:

  • change

  • blur

  • keyDown

  • keyUp

  • mouseDown

  • mouseUp

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容