Upload
ngoc-duong-minh
View
689
Download
0
Embed Size (px)
Citation preview
Knockout JS là thư viên javascript giúp bạn tạo các ứng dụng linh hoạt và mượt mà với tầng Data
Model bên dưới. Ví dụ khi bạn có một giao diện và cần phải cập nhật dữ liệu động từ View xuống
Model hoặc tự động cập nhật lại View mỗi khi Model thay đổi hoặc Model với Model (người ta còn hay
gọi là 2 ways binding), thì Knockout JS sẽ giúp bạn thực hiện tính năng đó một cách đơn giản và dễ
dàng bảo trì sau này.
Để sử dụng thư viện này, các bạn hãy download tại: http://knockoutjs.com/downloads/index.html
Hoặc sử dụng Bower tool: bower install knockout
Trước khi chúng ta tìm hiểu Observables thì mình xin giới thiệu sơ về mô hình MVVM.
Model View View-Model (MVVM) là một Design Pattern giúp bạn phát triển ứng dụng linh hoạt bằng
cách tách biệt ra 3 phần là Model, View và View Model.
Model: là phần chứa dữ liệu của ứng dụng và nó được tách riêng với phần giao diện người
dùng (UI).
View: là phần được trình bày ra cho người dùng đầu cuối. Nó có nhiệm vụ hiển thị thông tin từ
model, người dùng có thể tương tác với view (nhấn nút login trên màn hình) để truyền mệnh
lệnh xuống cho view model để cập nhật model và view có thể được cập nhật thông tin khi trạng
thái thông tin trong model thay đổi (ta còn gọi là cơ chế binding 2 way). Binding 2 way không chỉ
diễn ra giữa view và model, nó còn diễn ra giữa các model với nhau.
View Model: là phần mô tả dữ liệu và các thao tác trên UI. Lưu ý rằng nó không phải là phần dữ
liệu trong Model và củng không phải là UI (Button, Checkbox, Label…) trong View, mà nó quản
lý phần dữ liệu mà người dùng đang tương tác.
Activating Knockout và Observables
Để hiểu về tính năng này mình sẽ trình bày một ví dụ đơn giản để các bạn dễ dàng hiểu được.
Giờ thì chúng ta bắt đầu nhé:
http://js/jquery-2.1.3.js
http://js/knockout-3.3.0.js
http://js/bootstrap.js
Chúng ta thêm các Script như trên để có thể sử dụng thư viên Knockout. Ở trên các bạn có thể thêm
hoăc bỏ qua thư viện Bootstrap (Bootstrap yêu cầu cần có thư viện jQuery), vì vậy các bạn nhớ
include luôn jQuery nhé.
Để activating Knockout và Web Browser có thể hiểu được cú pháp của nó, các bạn hãy chèn đoạn
script như bên dưới:
ko.applyBindings(viewModel);
Có thể để đoạn Script trên ở cuối trang HTML hoặc đầu trang và nằm trong DOM ready handler của
jQuery
$(function() {
// Document is ready
});
Cách thứ 2 để activate Knockout:
ko.applyBindings(<viewModel>, [DOM]);
Dòng lệnh trên gồm 2 tham số, tham số đầu tiên thể hiển View Model mà các bạn muốn thao tác trên
nó, với tham số thứ 2 là optional, các bạn có thể truyền vào hoặc không, tham số này thể hiện phần
DOM để Knockout tìm thuộc tính data-bind (thuộc tính dùng để binding trong Knockout), và View
Model tương ứng sẽ làm việc với phần DOM tương ứng mà chúng ta khai báo.
Ví dụ:
ko.applyBindings(viewModel, document.getElementById("elementID"));
Cách activate này được dùng khi bạn có nhu cầu dùng nhiều View Model trên nhiều phần DOM khác
nhau trên trang HTML.
Bắt đầu mình sẽ trình bày cách bind data đơn giản từ View Model lên View.
Đầu tiên chúng ta cần khai báo View Model, để khai báo View Model đơn giản trong Knockout, chúng
ta chỉ cần khai báo một object javascript.
var viewModel = {
name: ‘Truc Nguyen’,
age: 23
};
Sau đó khai báo một View đơn giản:
Name: <span data-bind="text: name"></span><br>
Age: <span data-bind="text: age"></span>
Sau đó activate Knockout bằng cách:
ko.applyBindings(viewModel);
Observable trong KnockoutJS
Một trong những tính năng quan trọng của Knockout là tự động cập nhật dữ liệu lên View khi các
thuộc tính trong View Model thay đổi. Chắc chắn các bạn đang thắc mắc làm sao View có thể biết mà
cập nhật lại dữ liệu khi View Model thay đổi, thì câu trả lời chính là Observables. Có nghĩa là chúng ta
cần khai báo thuộc tính mà chúng ta có nhu cầu tự động cập nhật dữ liệu lên View là observable, vì
observable là một đối tượng javascript đặc biệt nên các thuộc tính nào được khai báo là observable
đều sẽ thông báo cho các thuộc tính binding trên View về sự thay đổi đó và tự động cập nhật lại dữ
liệu lên View.
var viewModel = {
name: ko.observable('Truc Nguyen'),
age: ko.observable(23)
};
Trong View chúng ta không cần thay đổi gì, sự khác biệt là khi name và age thay đổi, thì dữ liệu trên
View sẽ được cập nhất tương ứng. Mình đã trình bày xong Knockout và Observables.
Tổng quan về Knockout js
Giới thiệu chung
Mô hình của Knockout js(MVVM)
Hướng dẫn cài đặt
Observables trong Knockout js
Giới thiệu chung
Knockout(KO) là một thư viện của Javascript, nó giúp bạn tạo, hiển thị
hay hiệu chỉnh User Interface(UI) với một data model được định nghĩa
sẵn. Bất cứ khi nào bạn có phần thay đổi(thay đổi về action của user
hay dữ liệu nội tại thay đổi) trong UI thì KO có thể giúp bạn thực hiện
nó một cách đơn giản, và dễ kiểm soát
Các tính năng nổi bật của KO
-Theo dõi tự động sự phụ thuộc trường này vào trường khác - Tự
động cập nhật đúng phần giao diện khi có sự thay đổi phần tử đang
được theo dõi. -Khai báo các ràng buộc với dữ liệu - một cách đơn
giản để kết nối các phần trong UI đến với dữ liệu trong model của bạn.
-Lập trình mở rộng - thực hiện các behavior tùy chọn cũng như việc
khai báo ràng buộc mới cho việc tái sử dụng trong một vài dòng code.
Một số lợi ích khác:
Thư viện thuần Javascript - Làm việc tốt với nhiều server hoặc.
Làm việc tốt với nhiều trình duyệt - (IE 6+, Firefox 2+,
Chrome, Safari, ...).
Thích ứng tốt - Có thể dễ dàng xác định được các chức năng của
nó trên các trình duyệt và các nền tảng mới.
Mô hình của knockout js
Developers thường quen với mô hình MVC rất điển hình trong các
framework điển hình của quá trình phát triển ứng dụng web. Tuy nhiên
KO sử dụng mô hình MVVM (Model-View-ViewModel), nó là một biến
thể của MVC. Mô hình MVVM gồm 3 phần chính là: Model, View,
ViewModel. View và Model có chức năng vai trò như trong mô hình
MVC. ViewModel trong MVVM như là một controller đặc biệt, nó cung
cấp các hoạt động, logic cần thiết để view có thể lấy được dữ liệu thuận
tiện. ViewModel được coi là một view trừu tượng, nó chứa trạng thái và
các bihavior của view. Tuy nhiên ViewModel không chứa các tham chiếu
đến thành phần của UI và không biết gì về các thành phần nhìn thấy
của View. Do đó có sự tách biệt rõ ràng giữa View và ViewModel. Hay
nói một cách khác là View layer là sự ánh xạ của ViewModel
Mô hình MVVM được mô tả đơn giản như sau:
Cụ thể tất cả các quá trình diễn ra qua các bước sau:
Mỗi user nhấn vào một nút trên màn hình (thực hiện một action).
Một sự kiện bắn ra chất kết dính (binder).
Chất kết dính tìm action logic tương ứng trong ViewModel và thực
thi nó.
Action logic đó truy cập dữ liệu trong Model layer và cập nhật tính
năng tương ứng của ViewModel đó.
ViewModel thông báo cho binder đó một vài tính năng đã được
thay đổi.
Các tính năng vừa được cập nhật là nhờ việc tải dữ liệu từ binder
trong ViewModel.
Binder sau đó cập nhật các thành phần UI tương ứng để cung cấp
các phản hồi trực quan cho user.
Hướng dẫn cài đặt
Trước tiên cài Bower package
sudo npm install -g bower
bower install knockout
Để sử dụng đơn giản chỉ cần nhúng vào thẻ ở một nơi nào đó trong
code HTML. Ví dụ như sau
<script type='text/javascript' src='knockout-3.2.0.js'></script>
Observables
Tạo view models với observables
Như vậy về cơ bản, knockout js là một mô hình thiết kế cho việc xây
dựng giao diện người dùng một cách đơn giản mà rất dễ dàng cho việc
chỉnh sửa, cập nhật dữ liệu ngay trên view. Để tạo một view model với
KO, bạn cần phải khai báo một JavaScript Object. Ví dụ (sử dụng
framework laravel 4x):
Kết quả output sẽ như
sau:
Trong view rõ ràng ta thấy rằng thuộc tính data-bind không có trong
HTML, nó chính là thuộc tính của KO, chính vì HTML không hiểu được
nó nên bạn cần phải active nó trong <script>
ko.applyBindings(myViewModel);
Tuy nhiên, đó mới chỉ là việc làm thế nào để bạn create một view
model cơ bản và hiển thị chúng bằng cách dùng binding, lợi ích lớn
nhất của KO là tự động cập nhật UI khi view model thay đổi. Và làm
thế nào mà KO có thể biết phần view model của bạn thay đổi. Câu trả
lời là bạn cần phải khai báo các thuộc tính của model bằng observabels,
bởi vì chỉ có Javascript object mới thông báo được cho người theo dõi
biết về những thay đổi đó, và có thể tự động tìm thấy sự phụ thuộc
Làm việc với observables arrays
Nếu bạn muốn phát hiện và phản hồi lại những thay đổi của một
object, thì bạn dùng observables. Còn nếu bạn muốn phát hiện và
phản hồi lại những thay đổi của tập hợp nhiều thứ thì bạn
dùng observableArray, nó được sử dụng khá phổ biến trong KO.
Thường thì khi put một object trong một observableArray thì sẽ
không tạo được toàn bộ các thuộc tính cho bản thân mỗi một
observable. Tất nhiên là bạn hoàn toàn có thể tạo ra nhiều thuộc tính
cho observable mà bạn mong muốn Nếu bạn muốn mảng observable
khởi tạo bằng rỗng, thì bạn khởi tạo nó theo cấu trúc như sau:
// This observable array initially contains three objects
var anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
alert('The length of the array is ' + myObservableArray().length);
alert('The first element is ' + myObservableArray()[0]);
Tuy nhiên observableArray có nhiều tiện ích hơn so với native
JavaScript array, bởi vì:
Làm việc tốt trên mọi trình duyệt. (Ví dụ, hàm của native
JavaScript indexOf không làm việc được với IE 8 trở về trước tuy
nhiên KO’s indexOf làm việc được tốt)
Hàm thay đổi nội dung của một array như push và splice, phương
thức của KO thì tự động trigger tất cả sự kiện trên UI và qua xử
lý sẽ tự động cập nhật lại UI.
Cú pháp của KO có rất nhiều convenient. Để gọi phương
thức push của KO, viếtmyObservableArray.push(...). Đây là cách hay
hơn 1 chút so với việc gọi ẩn array push method với việc
viếtmyObservableArray().push(...).
Các thao tác với observableArray
myObservableArray.push('Some new value') Thêm một item mới vào
cuối array
myObservableArray.pop() xóa bỏ giá trị cuối cùng của array và return
nó
myObservableArray.unshift('Some new value') inserts một new item ở
vị trí đầu tiên của array
myObservableArray.shift() xóa bỏ giá trị đầu tiên của array và
returns nó
myObservableArray.reverse() đảo thứ tự của array
myObservableArray.sort() sắp xếp nội dung của array.
o mặc định là sắp xếp theo alphabetical, tuy nhiên bạn có thể
thêm vào các tùy chọn để sắp xếp. Ví dụ, để sắp xếp một
mảng ‘person’ objects theo last name, bạn có thể viết như
saumyObservableArray.sort(function(left, right) { return
left.lastName == right.lastName ? 0 : (left.lastName <
right.lastName ? -1 : 1) })
myObservableArray.splice() xóa và return lại số của thành phần bắt
đầu từ vị trí đánh index. Ví dụ,myObservableArray.splice(1, 3) xóa 3
thành phần bắt đầu từ vị trí index số 1 (tức là xóa thành phần 2,
3, 4) and và return chúng là một mảng.
Một số tiện ích khác mà Javascript array không có như sau:
myObservableArray.remove(someItem) xóa toàn bộ giá trị bằng
với someItem and returns chúng về một array
myObservableArray.remove(function(item) { return item.age < 18
}) xóa toàn bộ giá trị củaage mà nhỏ hơn 18, và returns chúng là
một array
myObservableArray.removeAll(['Chad', 132, undefined]) xóa toàn bộ
giá trị 'Chad', 123, or undefined và returns chúng là một array
myObservableArray.removeAll() xóa toàn bộ giá trị và returns chúng
là một array
Ở phần một chúng ta đã biết tổng quan về knockout js (KO), cách tạo
viewModel với observables và làm việc với observable arrays. Phần này
chúng ta tiếp tục tìm hiểu về một trong những thành phần khá quan
trọng của KO đó là Biding.
Binding trong KO có một số điểm đáng chú ý như sau:
1. Controlling text và appearance
2. Control flow
Phần 1: Controlling text và Appearance
a. The visible binding
Thuộc tính visible binding là nguyên nhân làm cho các thành phần kết
hợp của DOM trở nên ẩn đi hoặc có thể nhìn thấy được thông qua giá
trị mà bạn pass trong binding. Ví dụ:
PHP
<div data-bind="visible: shouldShowMessage">
You will see this message only when "shouldShowMessage" holds a true value.
</div>
<script type="text/javascript">
var viewModel = {
shouldShowMessage: ko.observable(true) // Message initially visible
};
viewModel.shouldShowMessage(false); // ... now it's hidden
viewModel.shouldShowMessage(true); // ... now it's visible again
</script>
Khi observable parameter nhận giá trị boolean là false, hoặc giá trị kiểu
số là 0, hoặc null hoặc undefined thì binding sẽ
set yourElement.style.display là none tức là nó sẽ bị ẩn và nó được ưu
tiên hơn bất kì style display nào mà bạn dùng css để định nghĩa.
Khi observaale parameter nhận giá trị boolean là true, hoặc một object,
array không null thì binding sẽ khửyourElement.style.display bởi vì giá trị
của nó trở nên có thể nhìn thấy được.
b. The text binding
Dùng để hiển thị text của biến hay một trường nào đó trong database,
text binding sử dụng tiện lợi với rất nhiều loại thẻ của HTML như
thẻ <div>, <i>, <span>, ... Một lợi thế khác được xét trong ví dụ như sau:
PHP
Today's message is: <span data-bind="text: myMessage"></span>
<script type="text/javascript">
var viewModel = {
myMessage: ko.observable() // Initially blank
};
viewModel.myMessage("Hello, world!"); // Text appears </script>
Nếu parameter là một giá trị observablue thì binding sẽ update giá trị
của text ở bất kì nơi nào khi mà giá trị của text đó được thay đổi
c. The "css" binding
Sử dụng css binding người dùng có thể add hoặc remove một hoặc
nhiều class static hoặc dynamic. Ví dụ về static classes
PHP
<div data-bind="css: { profitWarning: currentProfit() < 0 }">
Profit Information
</div>
<script type="text/javascript">
var viewModel = {
currentProfit: ko.observable(150000) // Positive value, so initially we don't apply the "profitWarning" class
};
viewModel.currentProfit(-50); // Causes the "profitWarning" class to be applied </script>
Bằng cách này CSS class profitWarning sẽ active khi giá
trị currentProfit nhỏ hơn 0 và khi giá trị biến này bằng hoặc lớn hơn 0
thì class profitWarning sẽ được tự động remove .
d. The style binding
Sử dụng style binding trong KO rất tiện dụng, nó có thể add hoặc
remove một hay nhiều giá trị style kết hợp với thành phần của DOM
Bạn cũng có thể pass một JavaScript object trong thuộc tính tên tương
ứng với tên của style và giá trị cũng tương ứng với giá trị của style mà
bạn đã định nghĩa. Ví dụ:
PHP
bind="style: { color: currentProfit() < 0 ? 'red' : 'black' }">
Profit Information
</div>
<script type="text/javascript">
var viewModel = {
currentProfit: ko.observable(150000) // Positive value, so initially black
};
viewModel.currentProfit(-50); // Causes the DIV's contents to go red
</script>
style.color nhận giá trị red ở bất cứ nơi nào khi currentProfit có giá trị
nhỏ hơn 0 và nhận giá trị là blackkhi currentProfit có giá trị lớn hơn 0.
Ngoài ra bạn cũng có thể đặt được nhiều style trong cùng một thẻ. Ví
dụ
PHP
<div data-bind="style: { color: currentProfit() < 0 ? 'red' : 'black', fontWeight: isSevere() ? 'bold' : '' }" >...</div>
Nếu parameter của bạn tham chiếu đến một giá trị observable thì
binding sẽ update style ở bất cứ nơi nào mà observable có giá trị thay
đổi. Một lưu ý: khi đặt style name của bạn cần chú ý một số style bị
trùng với JavaScript định danh và bạn phải dùng JavaScript name cho
những style đó:
margin-bottom => marginBottom
margin-left => marginLeft
margin-right => marginRight
margin-top => marginTop
color => backgroundColor
list-style => listStyle
font-family => fontFamily
font-style => fontStyle
font-variant => fontVariant
font-weight => fontWeight
line-height => lineHeight
text-align => textAlign
text-decoration => textDecoration
text-indent => textIndent
text-transform => textTransform
vertical-align => verticalAlign
e. The "attr" binding
"attr" binding cung cấp một cách chung nhất về tập các giá trị của rất
nhiều thuộc tính kết hợp với các thành phần của DOM. Điều này rất tiện
lợi cho việc bạn sử dụng các thuộc tính title, img, href, ... trong giá trị
view model mà bạn đã định nghĩa. Và cũng giống như bất kì binding
nào khác thì sử dụng "attr" giá trị của thuộc tính cũng sẽ update một
cách tự động ở bất cứ đâu khi thuộc tính model tương ứng thay dổi. Ví
dụ:
PHP
<a data-bind="attr: { href: url, title: details }">
Report
</a>
<script type="text/javascript">
var viewModel = {
url: ko.observable("year-end.html"),
details: ko.observable("Report including final year-end statistics")
};
</script>
Ví dụ trên đặt thuộc tính href trên đường dẫn year-end.html và
với title là Report including final year-end statistics.
Phần 2: Control Flow
foreach binding
foreach binding đánh dấu lặp lại số lần tương đương với số phần tử
trong mảng. Nó cũng liên kêts với mỗi sự lặp lại của một mark-up đến
các mục tương ứng của
mảng.
Khởi tạo một viewModel và khởi tạo dữ liệu sẵn như hình dưới
đây:
Kết quả của dữ liệu sẽ pass qua vòng foreach và lấy lần lượt hiển thị
trên browser. Như vậy ta có thể hiểu foreach trong KO về cơ chế cũng
lấy giá trị của object như là foreach giá trị của mảng.
Ngoài ra một số binding rẽ nhánh if, ifnot của KO về cơ bản cấu trúc và
luồng thực thi của nó c cũng như bao câu lệnh rẽ nhánh của các ngôn
ngữ khác.
Phần 3: Tài liệu tham khảo
visible binding
text binding
html binding
css binding
style bindind
attr binding
foreach binding