Thư viện dart:html - tương tác với HTML DOM

Thư viện để Dart làm việc với DOM HTML là dart:html, nên trước khi sử dụng cần nạp thư viện này ở đầu file:

import 'dart:html';

Cũng cần tìm hiểu về HTML DOM trước Cơ bản về DOM

Khi thư viện này được nạp, chúng ta lập tức có biến (thuộc tính) với tên:

  • document biến có kiểu HtmlDocument đó là nút gốc của DOM, từ biến này có thể truy cập mọi thành phần DOM (nó giống document trong JavaScript)
  • window biến kiểu Window biểu diễn cửa sổ trình duyệt (Gống window trong JS), từ đây có thể truy cập các hàm JS thông dụng đã biết, ví dụ alert window.alert('Hello!');

Tham khảo Web Dart - Ứng dụng đầu tiên, hãy tạo ra một dự án theo hướng dẫn đó, để thực hành các đoạn code ngắn ở đây. Tạm thời nội dung file main.dart, main.css index.html như sau:

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Web Dart 02</title>
    <link rel="stylesheet" href="main.css">
    <script defer src="main.dart.js"></script>
  </head>
  <body>
  </body>
</html>
main.dart
void main() {

}
main.css
body {
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
    font-weight: normal;
    line-height: 1.2em;
    margin: 15px;
  }

Chạy thử truy cập http://localhost:8080 chỉ là trang trắng, vì chưa có gì trong HTML và chưa có code trong main.dart

Lớp Element phần tử HTML

Lớp Element cùng với các kế thừa của nó dùng để biểu diễn các phần từ HTML trong DOM như các phần tử <a> <img> <article> <p> <div> ...

Đối tượng Element có được bằng cách khởi tạo đối tượng mới hoặc bằng cách tìm nó trong DOM hiện hành.

Gọi hàm khởi tạo Element.tag(tagname) để tạo ra phần tử HTML có tên là tagname (như a, p, img ...) hoặc gọi hàm tạo theo tên phần tử HTML Element.a(); Element.img(); Element.table()); ... ví dụ:

var $srcimg = 'https://upload.wikimedia.org/wikipedia/commons/2/2f/Google_2015_logo.svg';
var img = Element.tag('img');                       //Tạo phần tử HTML Img
img
..setAttribute('src', $srcimg)
..style.width='150px';
document.body.children.add(img);                    //Nối vào cuối HTML

var linka = Element.a();                            //Ví dụ tạo phần tử a
linka
..text = 'XuanThuLab'
..setAttribute('target', '_blank')
..setAttribute('href', 'https://xuanthulab.net');
document.body.children.add(linka);                  //Nối vào cuối HTML

Kết quả chạy thử:

webdart

Nếu muốn lấy phần tử đang có trong DOM dùng đến phương thức querySelectorquerySelectorAll trình bày phần dưới

Một số phương thức, thuộc tính trong Element

attributes Map chứa các thuộc tính của phần tử HTML, mỗi phần tử HTML có nhiều thuộc tính - xem Thuộc tính HTML để biết chi tiết.
children Thuộc tính biểu diễn danh sách (List) các phần tử con của nó
parent Thuộc tính trỏ đến phần tử cha
className Chuỗi biểu diễn lớp CSS của phần tử
classes Tập hợp (Set) các lớp CSS của phần tử
id ID của phần tử
innerHtml Văn bản HTML trong phần tử
title Thuộc tính title của phần tử HTML
text Thuộc tính chứa nội dung text của phần tử
dataset Map cho phép truy cập các thuộc tính dạng tên dạng data-*, ví dụ dataset['abc'] truy cập đến thuộc tính HTML data-abc
appendHtml(String html) Phương thức để nối thêm văn bản HTML vào phần tử
appendText(String html) Phương thức để nối thêm văn bản (không phải HTML) vào phần tử
getAttribute(String nameAttr) Lấy thuộc tính của phần tử
querySelector(String selectors) Tìm 1 phần tử con theo selector - xem phần dưới
querySelectorAll(String selectors) Tìm tất cả phần tử con theo selector - xem phần dưới
addEventListener Thêm một Listener cho sự kiện - xem phần Thêm sự kiện
remove() Loại bỏ phần tử ra khỏi DOM
onBlur() Lấy luồng biêu diễn sự kiện blur (chuột trên phần tử)
onChange() Lấy luồng biêu diễn sự kiện change (thay đổi giá trị phần tử)
onClick() Lấy luồng biêu diễn sự kiện click (bấm vào phần tử)

Xem đầy đủ tại Element Class

Lấy phần tử, tạo và chèn phần tử trong DOM

Có 2 phương thức để tìm ra phần tử trong DOm là querySelectorAll(string selectors) và phương thức querySelector(String selectors), trong đó selectorsCSS Selector quen thuộc nhất là nếu đã từng sử dụng jQuery như "a", như ".class", như "#id" ..., hãy xem phần Selector CSS, Chọn phần tử trong DOM với JS, Selector với jQuery để biết về các biểu thức selector

  • querySelector(String selectors) trả về phần tử Element đầu tiên nó tìm thấy thỏa mãn selector
  • querySelectorAll(string selectors) trả về danh sách các Element (List<Element>) thỏa mãn selector

Trở lại ví dụ trên, xóa bỏ đi code bên trong main.dart và biên tập index.html, main.css như sau:

index.html
<!DOCTYPE html>

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Web Dart 02</title>
    <link rel="stylesheet" href="main.css">
    <script defer src="main.dart.js"></script>
  </head>
  <body>
    <p>Các bài học lập trình với <span id="langid">Dart</span></p>
    <ul id="ulcacbaihoc">
      <li>Nội dung 1</li>
      <li>Nội dung 2</li>
    </ul>

    <p>Các bài đã học</p>
    <ul id="cacbaidahoc">
    </ul>
    <button id="buttonreset">Reset</button>
  </body>
</html>
main.css
body {
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
    font-weight: normal;
    line-height: 1.2em;
    margin: 15px;
  }
  ul li {
    border: 1px solid green;
    padding: 10px;
    margin: 10px;
  }

.elementli {
  font-weight: bold;
  color: red;
}

Đây là code HTML, CSS thông thường chạy thử http://localhost:8080 được

web dart 02

Giờ muốn thực hiện các tác vụ như sau khi mở trang (code trong main.dart):

Thay nội dung Dart trong phần tử spanidlangid thành WEB DART

var lang = querySelector('#langid');   //Tìm phần tử theo ID
lang.text = 'WEB DART';

Lấy tất cả các li trong ulid="ulcacbaihoc", mỗi phần tử li tìm được thiết lập cho nó lớp CSS elementli (chữ màu đỏ), đồng thời thay nôi dung tương ứng là Bài học 1, Bài học 2 ...

var baihoc = 0;
var lis = querySelectorAll('#ulcacbaihoc li');  //Lấy tất cả li trong UL
lis.forEach((Element li) {
    baihoc ++;
    li.text = 'Bài học ' + baihoc.toString();   //Thiết lập nội dung li
    li.classes.add('elementli');                //Thêm CSS class vào LI
});

Chạy thử đến lúc này được

web dart 03

Tiếp tục, tạo ra 3 phần tử li và chèn vào ul, các li có nội dung là Bài học 3 ... Bà học 5

Thêm vào main.dart đoạn code

var ul = querySelector('#ulcacbaihoc');
for (int j=1; j <=3; j++) {
  var li = Element.li();                        //Khởi tạo phần tử li
  li.text = 'Bài học ' + (++baihoc).toString(); //Thiết lập nội dung li
  ul.children.add(li);                          //Thêm vào UL
}

Đến lúc này main.dart có nội dung tổng hợp lại là

import 'dart:html';
void main()  {
    var lang = querySelector('#langid');
    lang.text = 'WEB DART';

    var baihoc = 0;
    var lis = querySelectorAll('#ulcacbaihoc li');
    lis.forEach((Element li) {
        baihoc ++;
        li.text = 'Bài học ' + baihoc.toString();
        li.classes.add('elementli');
    });


    var ul = querySelector('#ulcacbaihoc');
    for (int j=1; j <=3; j++) {
      var li = Element.li();
      li.text = 'Bài học ' + (++baihoc).toString();
      ul.children.add(li);
    }
}

Kết quả kiểm tra http://localhost:8080

web dart 04

EventListener - Lắng nghe sự kiện cho phần tử

Các sự kiện phát đi từ phần tử (như bấm vào phần tử, thay đổi giá trị phần tử ...) được biểu diễn bằng đối tượng lớp Event, đối tượng này được làm tham số cho hàm thi hành mà sự kiện xảy ra - hàm đó gọi là Listener

Một Listener là một hàm, khai báo dạng:

void ListenerFunction(Event e) {

}

Khi có các Listener, đăng ký nó lắng nghe các sự kiện trên phần tử bằng các sử dụng các thuộc tính biểu diễn luồng sự kiện trên phần tử như: Element.onClick, Element.onBlur, Element.onChange, Element.onKeyDown, Element.onKeyPress, Element.onSubmit, Element.onReset, Element.onSubmit, Element.onDoubleClick, Element.onFocus ... Từ thuộc tính này đăng ký listener theo dạng như sau:

//Đăng ký listener cho sự kiện bấm vào phần tử element
element.onClick.listen(listener);

Một số thuộc tính, phương thức trong Event

target Đối tượng phát sự kiện
type Chuỗi biểu diễn kiểu sự kiện
preventDefault() Dừng thi hành hành động mặc định của sự kiện - Xem thêm preventDefault
stopPropagation() Dừng lan truyền sự kiện - Xem thêm stopPropagation

Trở lại ví dụ trên, thực hiện chức năng khi bấm vào phần tử li, sẽ di chuyển nó từ ulid=ulcacbaihoc đến ulid=cacbaidahoc và ngược lại, tùy thuộc phần tử đó đang nằm ở ul nào

void main()  {
    var lang = querySelector('#langid');
    lang.text = 'WEB DART';

    var baihoc = 0;
    var lis = querySelectorAll('#ulcacbaihoc li');
    lis.forEach((Element li) {
        baihoc ++;
        li.text = 'Bài học ' + baihoc.toString();
        li.classes.add('elementli');
    });


    var ul = querySelector('#ulcacbaihoc');
    for (int j=1; j <=3; j++) {
      var li = Element.li();
      li.text = 'Bài học ' + (++baihoc).toString();
      ul.children.add(li);
    }

    //Lấy tất cả li
    lis = querySelectorAll('#ulcacbaihoc li');
    lis.forEach((Element li) {
      //Thiết lập Listener khi bấm vào li
      li.onClick.listen(moveLiElement);
    });

}

//Listener lắng nghe bấm vào li
void moveLiElement(Event e) {
  LIElement li = e.target;
  if (li.parent.id == 'ulcacbaihoc') {
      querySelector('#cacbaidahoc').children.add(li);
  }
  else {
      querySelector('#ulcacbaihoc').children.add(li);
  }
}
web dart
Đăng ký theo dõi ủng hộ kênh