Làm việc ngoại tuyến với tính năng web storage của HTML5

Sử dụng tính năng web storage để tăng thêm các khả năng làm việc ngoại tuyến

HTML5 là một chuẩn HTML mới, hỗ trợ một loạt các chức năng và các kỹ thuật bố cục mới. Nó hỗ trợ đầy đủ các tính năng đa phương tiện, CSS3 và các khả năng vẽ với canvas (Khung nền ảnh) và Scalable Vector Graphics (SVG – Đồ họa vectơ có thể co giãn). HTML5 đưa ra các phần tử ngữ nghĩa mới và cũng cung cấp một cách hợp pháp để tạo ra các ứng dụng web HTML bằng cách sử dụng bộ nhớ đệm của ứng dụng, các mã JavaScript, một phiên bản mới của XMLHttpRequest và một tính năng được gọi là web storage (ND.: web storage là các phương thức và các giao thức của phần mềm ứng dụng web dùng để web storage). Bài này thảo luận về sức mạnh của web storage và tại sao nó lại là một phương thức lưu trữ tốt hơn so với các cookie. Hãy tìm hiểu về các khái niệm cơ bản, sự hỗ trợ của trình duyệt và các đối tượng web storage của HTML5.

Kris Hadlock, Nhà phát triển và nhà thiết kế web, Studio Sedition

Ảnh của Kris HadlockKris Hadlock là nhà phát triển và thiết kế trang web theo hợp đồng từ năm 1996. Ông đã làm về các dự án cho các công ty như SPIN Magazine, IKEA, United Airlines, JP Morgan Chase, Le Cordon Bleu và Canon. Ông là tác giả của jQuery Mobile: Develop and Design - jQuery Mobile: Xây dựng và Thiết Kế (Peachpit), Ajax for Web Application Developers - Ajax dành cho các nhà phát triển ứng dụng Web (Sams) và The ActionScript Migration Guide - Hướng dẫn di trú ActionScript (New Riders). Kris là một nhà báo được đánh giá cao, ông phụ trách các chuyên mục và đã có nhiều bài viết cho các trang web và các tạp chí thiết kế, gồm IBM developerWorks, Peachpit.com, InformIT.com và Practical Web Design - Thực hành thiết kế web. Ông cũng là người sáng lập của trang www.studiosedition.com, một xưởng phát triển phần mềm và thiết kế web chuyên về tổng hợp biểu mẫu và chức năng.



12 03 2013

Tổng quan

Ngay khi JavaScript ra đời thì cookies cũng bắt đầu được biết đến, do đó việc lưu trữ dữ liệu trên web không phải là một khái niệm mới. Tuy nhiên, web storage là một phiên bản lưu trữ dữ liệu mạnh hơn rất nhiều mang lại tính bảo mật cao hơn, tốc độ cao hơn và dễ sử dụng hơn. Bạn cũng có thể lưu trữ một lượng lớn dữ liệu trong web storage. Dung lượng lưu trữ chính xác phải dựa trên trình duyệt web, nhưng nó thường từ 5 đến 10MB, đó là một dung lượng lưu trữ lớn cho một ứng dụng HTML. Một lợi ích khác là không phải mọi máy chủ đều yêu cầu tải dữ liệu này. Hạn chế duy nhất là ở chỗ bạn không thể chia sẻ web storage giữa các trình duyệt; nếu bạn lưu trữ dữ liệu trong trình duyệt Safari, bạn không thể truy cập dữ liệu đó trong trình duyệt Mozilla Firefox.

Người ta dựng sẵn hai kiểu đối tượng web storage trong HTML5:

  • Đối tượng sessionStorage lưu trữ dữ liệu cho một phiên làm việc duy nhất. Nếu người dùng đóng trang hoặc trình duyệt, dữ liệu bị xóa hết.
  • Đối tượng localStorage lưu trữ dữ liệu không thời hạn. Dữ liệu vẫn còn được lưu trữ khi đóng trang web hoặc trình duyệt, tùy thuộc vào giá trị thiết lập dung lượng lưu trữ cho trình duyệt của người dùng.

Các từ viết tắt thông dụng

  • API: Application Programming Interface (Giao diện lập trình ứng dụng)
  • CSS: Cascading Style Sheets (Các bản định kiểu xếp chồng)
  • HTML: HyperText Markup Language (Ngôn ngữ đánh dấu siêu văn bản)
  • JSON: JavaScript Serialized Object Notation (Ký pháp đối tượng JavaScript)

Cả hai đối tượng lưu trữ đều có cùng các phương thức và các thuộc tính. Để thống nhất, bài này sử dụng đối tượng localStorage trong suốt các ví dụ.

Trong bài này, hãy tìm hiểu về sức mạnh của web storate và tại sao nó là một phương thức lưu trữ tốt hơn so với cookie. Hãy khám phá các khái niệm cơ sở về web storage, các phương thức của web storage trong HTML5 và sự hỗ trợ của trình duyệt.

Bạn có thể tải về mã nguồn các ví dụ được dùng trong bài này.


Các trình duyệt hỗ trợ

Tất cả các phiên bản mới của các trình duyệt mới nhất, bao gồm Firefox, Google Chrome, Safari, Opera và Microsoft® Windows® Internet Explorer® 8+. Thật không may, phiên bản Internet Explorer 7 và trước đó không hỗ trợ tính năng web storage. Bảng 1 cho thấy các phiên bản của từng trình duyệt máy tính có hỗ trợ tính năng web storage của HTML5.

Bảng 1. Các trình duyệt máy tính hỗ trợ web storage trên HTML5
ChromeFirefoxSafariOperaInternet Explorer
Trình duyệt ChromeTrình duyệt FirefoxTrình duyệt SafariTrình duyệt OperaTrình duyệt Internet Explorer
4+4+4+11+8+

Các trình duyệt di động, ngoài Opera Mini, cũng hỗ trợ tính năng web storage của HTML5. Bảng 2 cho thấy các phiên bản của từng trình duyệt di động có hỗ trợ tính năng web storage của HTML5.

Bảng 2. Các trinh duyệt di động hỗ trợ web storate trên HTML5
iOSAndroidOpera MiniOpera Mobile
Trình duyệt trên iOSTrình duyệt trên AndroidTrình duyệt Opera MiniTrình duyệt Opera Mobile
5+3+NA11+

Việc các trình duyệt hỗ trợ web storage của HTML5 là khá ấn tượng. Tuy nhiên, các trình duyệt cũ hơn cần có một kiểu kiểm tra trình duyệt nào đó về hỗ trợ tính năng web storage trước khi bạn định sử dụng nó. Việc kiểm tra một trình duyệt có hỗ trợ tính năng web storage hay không rất dễ dàng. Bạn có thể sử dụng một câu lệnh có điều kiện đơn giản để xem liệu đối tượng lưu trữ dữ liệu của HTML5 đã được định nghĩa chưa. Nếu nó đã được định nghĩa thì việc tiếp tục viết kịch bản lệnh với web storage là an toàn. Nếu nó vẫn chưa được định nghĩa, bạn phải sử dụng một phương pháp thay thế khác, chẳng hạn như các cookie của JavaScript, nếu việc lưu trữ dữ liệu là cần thiết. Liệt kê 1 cho thấy ví dụ về một cách kiểm tra trình duyệt đơn giản để tìm đối tượng Storage (lưu trữ).

Liệt kê 1. Kiểm tra trình duyệt để tìm sự hỗ trợ cho tính năng web storage
if(typeof(Storage)!== "undefined") {
  // Web storage is supported
}
else {
  // Web storage is NOT supported
}

Nếu một trình duyệt không hỗ trợ tính năng web storage, bạn có thể tạo ra một đối tượng web storage tùy chỉnh bằng cách sử dụng các cookie của JavaScript hay một thư viện hiện có như là AmplifyJS. AmplifyJS là một tập hợp các thành phần được thiết kế để giải quyết các vấn đề ứng dụng web phổ biến, bao gồm sự hỗ trợ tính năng web storage trong các trình duyệt cụ thể, với một API đơn giản. AmplifyJS giải quyết vấn đề bằng trình bao bọc (wrapper) amplify.store để xử lý lưu trữ tồn tại lâu bền phía máy khách, có hỗ trợ Internet Explorer 5+, Firefox 2+, Safari 4+, Chrome, Opera 10.5+, iOS 2+ và Android 2+. Thư viện này cũng cung cấp một API thống nhất để xử lý lưu trữ với nhiều trình duyệt; bạn không phải viết mã khác nhau dựa theo các trình duyệt đang xét. Nếu trình duyệt hỗ trợ tính năng web storage của HTML5 thì AmplifyJS sẽ sử dụng các kỹ thuật lưu trữ mới nhất. Nếu trình duyệt không hỗ trợ tính năng web storage của HTML5 thì AmplifyJS sẽ hạ cấp để hỗ trợ nó mà không cần chức năng đó. Xem phần Tài nguyên để tìm hiểu thêm về AmplifyJS và API cho trình bao bọc lưu trữ của nó.


Bắt đầu

Có một vài phương thức dễ sử dụng cung cấp các chức năng web storage của HTML5. Những phương thức này hỗ trợ thiết lập một cặp khóa/giá trị, hai tùy chọn để lấy ra một giá trị dựa trên một khóa, xóa tất cả các cặp khóa/giá trị cùng một lúc và loại bỏ một cặp khóa/giá trị cụ thể. Bảng 3 cho thấy các phương thức web storage của HTML5 có sẵn.

Bảng 3. Các phương thức web storage của HTML5
Phương thứcMô tả
setItem(key, value)Thêm một cặp khóa/giá trị vào đối tượng web storage để sử dụng sau này. Giá trị này có thể là bất kỳ kiểu dữ liệu nào: một chuỗi ký tự, số, mảng và v.v.
getItem(key)Lấy ra một giá trị dựa trên khóa đã được sử dụng để lưu trữ nó ở vị trí đầu tiên.
clear()Xóa tất cả các cặp khóa/giá trị khỏi đối tượng web storage.
removeItem(key)Loại bỏ một cặp khóa/giá trị cụ thể khỏi đối tượng web storage dựa trên một khóa.
key(n)Lấy ra giá trị cho key[n].

Khi tạo và thêm các cặp khóa/giá trị cho đối tượng web storage, bạn có thể sử dụng bất kỳ kiểu dữ liệu nào làm giá trị trong cặp đó (một chuỗi ký tự, số, mảng, đối tượng và v.v). Để lưu trữ một mảng hoặc một đối tượng, bạn phải sử dụng đối tượng JSON để chuyển đổi dữ liệu thành một chuỗi ký tự bằng cách sử dụng phương thức JSON.stringify. Khi lấy ra dữ liệu, bạn có thể phân tích cú pháp nó bằng cách sử dụng JSON.parse, để trả về đối tượng hoặc mảng của bạn theo trạng thái ban đầu của nó. Ngoài ra còn có hai cách khác để thêm một cặp khóa/giá trị vào đối tượng web storage. Cách đầu tiên là sử dụng phương thức setItem, như trong Liệt kê 2.

Liệt kê 2. Thêm một cặp khóa/giá trị vào đối tượng web storage khi sử dụng setItem
localStorage.setItem('myKey', 'myValue');

Tùy chọn thứ hai để thêm một cặp khóa/giá trị vào đối tượng web storage là thiết lập trực tiếp giá trị của khóa bằng cách sử dụng đối tượng web storage với cú pháp dấu chấm, như trong Liệt kê 3.

Liệt kê 3. Thêm trực tiếp một cặp khóa/giá trị vào đối tượng web storage
localStorage.myKey = 'myValue';

Lấy ra các giá trị đã lưu cũng dễ dàng như thế. Một lần nữa, lại có hai tùy chọn. Tùy chọn đầu tiên là sử dụng phương thức getItem, để nhận một khóa làm một đối số và trả về giá trị tương ứng nếu có một giá trị đã lưu. Liệt kê 4 hiển thị ví dụ.

Liệt kê 4. Lấy ra một cặp khóa/giá trị từ đối tượng web storage bằng cách sử dụng getItem
localStorage.getItem('myKey');

Tùy chọn thứ hai để lấy ra một cặp khóa/giá trị từ đối tượng web storage là truy cập trực tiếp vào cặp giá trị khóa đó bằng cách sử dụng cú pháp dấu chấm, như trong Liệt kê 5. Ví dụ này trả về giá trị chuỗi 'myValue' đã được thiết lập trong các ví dụ trước.

Liệt kê 5. Lấy ra trực tiếp một cặp khóa/giá trị từ đối tượng web storage
localStorage.myKey;

Ngoài ra cũng có hai cách để loại bỏ dữ liệu đã lưu trữ. Bạn có thể loại bỏ tất cả các mục cùng một lúc hoặc bạn có thể loại bỏ riêng từng mục mỗi lần một mục. Để loại bỏ tất cả các mục khỏi đối tượng web storage cùng một lúc, hãy sử dụng phương thức clear, như thể hiện trong Liệt kê 6.

Liệt kê 6. Loại bỏ tất cả các cặp khóa/giá trị khỏi đối tượng web storage
localStorage.clear();

Để loại bỏ một cặp khóa/giá trị riêng lẻ khỏi một đối tượng web storage, bạn cần phải sử dụng phương thức removeItem. Liệt kê 7 cho thấy một ví dụ về phương thức removeItem để nhận một khóa làm đối số để nhận biết cặp khóa/giá trị nào cần loại bỏ khỏi đối tượng lưu trữ.

Liệt kê 7. Loại bỏ một cặp khóa/giá trị riêng lẻ khỏi đối tượng web storage
localStorage.removeItem('myKey');

Liệt kê 8 cho thấy một ví dụ về cách sử dụng đối tượng JSON để lưu trữ một mảng dưới dạng một chuỗi ký tự bằng cách sử dụng JSON.stringify. Bạn xử lý các đối tượng theo cùng cách.

Liệt kê 8. Lưu trữ một mảng như là một chuỗi ký tự trong web storage của HTML5
var myArray = new Array('First Name', 'Last Name', 'Email Address');
localStorage.formData = JSON.stringify(myArray);

Để lấy ra phiên bản chuỗi ký tự của mảng này từ đối tượng web storage và chuyển đổi nó trở lại thành một mảng tiện lợi trong JavaScript, chỉ cần sử dụng phương thức JSON.parse, như thể hiện trong Liệt kê 9.

Liệt kê 9. Lấy ra phiên bản chuỗi ký tự của một mảng từ web storage của HTML5 và chuyển nó thành một mảng JavaScript tiện lợi
var myArray = JSON.parse(localStorage.formData);

Tất cả các trình duyệt Internet Explorer 8+, Opera 10.5+, Firefox 3.5+, Safari 4+ và Chrome đều có một đối tượng JSON nguyên gốc để hỗ trợ mã trong các ví dụ trước. Nếu bạn sử dụng một phiên bản trình duyệt cũ hơn, bạn có thể tải về tệp json2.js (xem phần Tài nguyên).

Đến lúc này bạn đã thấy là rất dễ sử dụng web storage. Tuy nhiên, trước khi bắt tay vào làm thì bạn nên hiểu rằng bảo đảm an toàn có thể là một mối quan tâm trên các máy tính chia sẻ chung. web storage không hề an toàn hơn so với các cookie. Đừng lưu trữ thông tin nhạy cảm như mật khẩu và các số thẻ tín dụng, bên phía trình máy khách.


Thực hành web storage

Bây giờ khi đã trình bày xong những điều cơ bản, đây là lúc đưa web storage của HTML5 vào sử dụng. Giả sử, trên trang web của mình, bạn muốn cung cấp sự hỗ trợ trong lúc tắt mạng cho một biểu mẫu web. Sẽ thật là tuyệt nếu một người dùng có thể gửi biểu mẫu đó lên và nó sẽ được đồng bộ hóa với máy chủ khi trang web được kết nối trở lại. Điều này có thể thực hiện được với HTML5.

Hãy tạo một biểu mẫu web đơn giản gồm có một họ và tên, địa chỉ email và nút gửi đi, như trong Liệt kê 10.

Liệt kê 10. Biểu mẫu web đơn giản để lưu trữ dữ liệu khi sử dụng web storage của HTML5
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>HTML5 Web Storage</title>
<style type="text/css">
label, 
input {
  display: block;
}
input {
  margin-bottom: 10px;
}
</style>
</head>

<body>

<form action="post.php" method="post" id="web-storage-form">
  <label for="first-name">First name:</label>
  <input type="text" name="first-name" id="first-name">

  <label for="last-name">Last name:</label>
  <input type="text" name="last-name" id="last-name">

  <label for="email-address">Email Address:</label>
  <input type="text" name="email-address" id="email-address">

  <input type="submit" value="Submit">
</form>

</body>
</html>

Biểu mẫu này gồm có một ID (mã định danh) để lấy ra biểu mẫu và các giá trị gửi lên bằng cách sử dụng JavaScript. Nó cũng có CSS để tạo ra một bố cục cơ bản với các phần tử của biểu mẫu. Thuộc tính display:block của các label và các đầu vào sẽ đặt mỗi phần tử trên một dòng mới. Thuộc tính margin-bottom tạo ra khoảng trống giữa các mục để cho trang web này dễ nhìn.

Khi người dùng gửi biểu mẫu lên, đầu tiên mã ngăn không cho việc gửi lên mặc định xảy ra bằng cách lấy ra ID của web-storage-form và thu thập dữ liệu gửi lên bằng cách sử dụng jQuery. Khi biểu mẫu này gửi lên, bạn có thể thu thập các giá trị của biểu mẫu và URL của hành động xử lý biểu mẫu để lưu trữ vào các biến. Bạn phải tuần tự hóa các giá trị của biểu mẫu web khi gửi các giá trị dưới dạng dữ liệu gửi lên của Ajax (JavaScript không đồng bộ + XML) hoặc lưu trữ chúng trong đối tượng web storage. Trước khi gửi đi biểu mẫu, hãy sử dụng thuộc tính navigator.onLine để xem liệu người dùng có đang nối mạng hay không.

Nếu người dùng đang nối mạng, hãy sử dụng hàm jQuery.post, là một hàm Ajax tốc ký để gửi và nhận dữ liệu từ máy chủ. Hàm này nhận bốn đối số: url để gửi dữ liệu tới, data mà bạn đang gửi đi (các giá trị biểu mẫu đã tuần tự hóa), một hàm callback được kích hoạt khi một yêu cầu thành công và một dataType. Trong ví dụ này, không có dataType nào vì nó sử dụng giá trị mặc định.

Nếu người dùng đang ở chế độ ngoại tuyến (offline), bạn sẽ cần đến web storage. Trước tiên, điều quan trọng là phải xem liệu trình duyệt có hỗ trợ tính năng web storage hay không bằng cách sử dụng câu lệnh điều kiện mà bạn đã tạo ra trong Liệt kê 1. Nếu trình duyệt có hỗ trợ tính năng web storage, bạn có thể lưu các giá trị biểu mẫu trực tiếp vào đối tượng localStorage bằng cách sử dụng một khóa tùy chỉnh. Ví dụ này sử dụng khóa tùy chỉnh formValues. Bây giờ việc lưu các giá trị localStorage đã sẵn sàng, hãy kiểm tra xem liệu chúng có tồn tại hay không khi người dùng quay lại nối mạng bằng cách thêm một câu lệnh if để kiểm tra xem localStorage.formValues có giá trị nào không. Nếu có, bạn biết rằng biểu mẫu này trước đó đã được gửi tới đối tượng localStorage và có thể gửi một cách an toàn dữ liệu đến máy chủ bằng cách sử dụng phương thức jQuery.post do bạn thiết lập trước đó. Sau khi gửi đi các giá trị này, bạn nên loại bỏ chúng khỏi đối tượng web storage để chúng không bị vô tình gửi đi lần nữa. Liệt kê 11 cho thấy mã nguồn, từ việc gửi đi biểu mẫu bằng cách sử dụng Ajax đến đối tượng localStorage.

Liệt kê 11. Lưu trữ dữ liệu biểu mẫu vào đối tượng localStorage khi tắt mạng và sẽ gửi dữ liệu đến máy chủ khi nối mạng
<script type="text/javascript" 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready(function() {
  // Check for web storage values from a previous offline session
  if(localStorage.formValues) {
    console.log("localStorage.formValues: "+ localStorage.formValues);
    postForm($("#web-storage-form").attr('action'), localStorage.formValues);
    localStorage.removeItem("formValues");
  }

  $("#web-storage-form").submit(function(event) {
    // Prevent the form from posting
    event.preventDefault(); 

    // Gather values
    var formValues = $(this).serialize();
    var url = $(this).attr('action');
    postForm(url, formValues);
  });
 });

function postForm(url, formValues) {
  // Post to server or post to web storage
  if(navigator.onLine) {
    console.log("Online");
    $.post(url, formValues, function(data) {
      console.log("Success: "+ data);
    });
  }
  else {
    console.log("Offline");
    if(typeof(Storage) !== "undefined") {
      console.log("Storage supported");
      localStorage.formValues = formValues;
    }
  }
}
</script>

Để tạo một ví dụ hoàn chỉnh, một tệp post.php hoạt động như điểm cuối của biểu mẫu gửi đến để nhận và đáp ứng với yêu cầu của biểu mẫu. Tệp này chỉ đơn giản nhận dữ liệu biểu mẫu gửi đi và đáp ứng bằng cách in mảng các cặp khóa/giá trị, như trong Liệt kê 12. Khi jQuery.post nhận được đáp ứng, dữ liệu của đáp ứng viết ra giao diện bàn điều khiển.

Liệt kê 12. Tệp PHP đáp ứng các yêu cầu của biểu mẫu
<?php print_r($_POST); ?>

Tất nhiên, bạn có thể tạo ra ví dụ mạnh mẽ hơn rất nhiều. Ví dụ, bạn có thể đưa việc lưu trữ cơ sở dữ liệu vào phía máy chủ và kiểm tra đối tượng localStorage bằng cách sử dụng một khoảng thời gian để thường xuyên theo dõi xem máy tính của người dùng đã trở lại nối mạng chưa để gửi đi dữ liệu biểu mẫu.


Tóm tắt

HTML5 đưa ra một tập hợp các chức năng mới mạnh mẽ, đang nhanh chóng chọn sự hỗ trợ từ các phiên bản mới nhất của các trình duyệt web chủ yếu. Web storage là một trong những tính năng hấp dẫn của HTML5. Tuy nhiên, hãy sử dụng nó một cách khôn ngoan. Cũng giống như với các cookie, người dùng có thể tắt tính năng web storage. Hãy luôn có sẵn phương án dự phòng để hỗ trợ những ai không thích dùng tính năng mới này.


Tải về

Mô tảTênKích thước
Work offline with web storagehtml5-web-storage.zip2KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

  • Cộng đồng developerWorks: Kết nối với những người dùng developerWorks khác trong khi khám phá các blog, các diễn đàn, các nhóm và các wiki theo hướng nhà phát triển.

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=861159
ArticleTitle=Làm việc ngoại tuyến với tính năng web storage của HTML5
publish-date=03122013