Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Mobile App

Tạo một Ứng dụng về Thời tiết bằng TypeScript và NativeScript

by
Read Time:24 minsLanguages:

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)

Trong hướng dẫn này, tôi sẽ trình bày cho bạn cách xây dựng một ứng dụng thời tiết với NativeScript bằng ngôn ngữ TypeScript.

Trong bài trước của loạt bài này, chúng ta đã tạo ra một ứng dụng ghi chú bằng JavaScript thuần tuý. Lần này chúng ta sẽ sử dụng TypeScript. Trước tiên hãy cùng tìm hiểu xem tại sao TypeScript là một sự lựa chọn tốt để xây dựng các ứng dụng NativeScript.

1. Tại sao là TypeScript?

TypeScript là một công dân hạng nhất trong NativeScript. Nó được sử dụng bởi nhóm NativeScript cốt lõi để xây dựng chính framework NativeScript. Dưới đây là một vài lý do khiến bạn muốn sử dụng TypeScript để phát triển các ứng dụng NativeScript:

  • TypeScript được biên dịch thành JavaScript. Khi trình biên dịch chạy, nó bắt bất kỳ lỗi nào mà bạn có thể có trong code của bạn để bạn có thể khắc phục chúng ngay lập tức mà không cần chờ trình biên dịch NativeScript hoàn tất. Điều này có nghĩa là nâng cao hiệu suất cho bạn với vai trò là nhà phát triển.
  • TypeScript cho phép bạn sử dụng các tính năng của ES6 như lớp, mô-đun, hàm arrow, template literals, và còn nhiều nữa. Điều này có nghĩa là bạn sẽ có nhiều công cụ hơn để quản lý và viết code tốt hơn.

Nếu tôi không thể thuyết phục được bạn hoặc bạn muốn biết thêm về lý do tại sao TypeScript tốt cho việc phát triển với NativeScript, thì bạn có thể tham khảo bài viết Xây dựng Ứng dụng NativeScript tốt hơn với TypeScript.

2. Công cụ

Để tận dụng tối đa các tính năng mà TypeScript cung cấp, tôi khuyên bạn nên sử dụng trình soạn thảo Visual Studio Code. Nó có một tính năng IntelliSense cung cấp khả năng tự động hoàn tác thông minh khi bạn viết code TypeScript, nó tích hợp Git và nó còn có khả năng gỡ lỗi.

Hơn nữa, còn có một plugin NativeScript sẽ giúp cho bạn nâng cao hiệu suất khi phát triển các ứng dụng NativeScript. Một tính năng mà tôi thấy hữu ích đó là tích hợp emulator. Điều này cho phép bạn chạy emulator ngay từ trình soạn thảo và gỡ lỗi ứng dụng từ chính trình soạn thảo đó. Visual Studio Code thì miễn phí và có sẵn trên tất cả các nền tảng chính (Windows, Linux, OS X).

Tuy nhiên, nếu bạn không muốn rời xa trình soạn thảo yêu thích của mình, bạn cũng có thể cài đặt các extension sẽ giúp làm cho việc viết code bằng TypeScript trở nên tốt hơn. Đối với Atom, đó là plugin atom-typescript. Đối với Sublime, có plugin TypeScript Sublime.

3. Tổng quan về Ứng dụng

Ứng dụng mà chúng ta sẽ tạo ra là một ứng dụng về thời tiết. Nó sẽ có các trang sau:

  • Một trang chính hiển thị điều kiện thời tiết hiện tại cùng với một số thông tin liên quan như nhiệt độ, áp suất không khí và độ ẩm.
  • Một trang dự báo hiển thị dự báo 5 ngày về thời tiết sẽ diễn ra như thế nào trong năm ngày tiếp theo.

Trang chính sẽ trông như sau:

Main pageMain pageMain page

Và đây là trang dự báo:

forecast pageforecast pageforecast page

Bạn có thể tìm thấy mã nguồn hoàn chỉnh cho ứng dụng này trên repo GitHub của nó.

4. OpenWeatherMap

Dữ liệu về thời tiết sẽ lấy từ OpenWeatherMap API và giống như bất kỳ API nào khác, bạn cần phải đăng ký một khóa API để sử dụng nó. Hãy tiến hành đăng ký một tài khoản, tôi sẽ đợi bạn. Một khi bạn đăng nhập, hãy truy cập vào trang API keys, sao chép giá trị của trường key và lưu nó ở một nơi an toàn. Bạn sẽ cần nó sau này, khi bạn bắt đầu tạo ứng dụng.

OpenWeatherMap generate API keysOpenWeatherMap generate API keysOpenWeatherMap generate API keys

5. Tạo Ứng dụng

Bây giờ bạn đã biết ứng dụng sẽ trông như thế nào, bây giờ là lúc để thật sự bắt đầu tạo nó. Bắt đầu bằng cách tạo ra một dự án NativeScript mới sử dụng template TypeScript:

Sau khi xong, chuyển đến thư mục app và tạo ra các thư mục và tập tin sau đây. Để thuận tiện, bạn cũng có thể tải về hoặc nhân bản repo GitHub và sao chép các tập tin từ thư mục app.

Chúng ta sẽ chỉ làm việc bên trong thư mục app, vì vậy mỗi lần tôi tham chiếu đường dẫn một tập tin hoặc thư mục, giả định là thư mục app là thư mục gốc.

Cài đặt các Phụ thuộc

Ứng dụng yêu cầu một số phụ thuộc: Mô-đun NativeScript GeolocationMoment. Bạn có thể cài đặt mô đun Geolocation bằng lệnh sau:

Và cài đặt Moment bằng lệnh:

Mô-đun Geolocation được sử dụng để xác định vị trí hiện tại của người dùng. Moment cho phép định dạng thời gian Unix một cách dễ dàng, cái mà chúng ta sẽ lấy về từ API sau này.

Các Mô-đun Thông thường

Trước khi chúng ta tìm hiểu code cho mỗi trang của ứng dụng, trước tiên hãy xem xét các mô-đun tùy biến sẽ được sử dụng trong suốt ứng dụng.

Constants

Mô-đun constants (common/constants.ts) chứa tất cả các giá trị hằng số được sử dụng trong suốt ứng dụng: những thứ như URL cơ sở của OpenWeatherMap API, khóa API mà bạn đã có trước đó, các đường dẫn đến các endpoint mà chúng ta sẽ sử dụng, mã ký tự của các biểu tượng thời tiết và hướng gió.

Utilities

Mô-đun utilities bao gồm tất cả các loại hàm tiện ích: những thứ như chuyển đổi góc thành hướng, xác định một văn bản mô tả cho tốc độ gió, chuyển đổi Kelvin thành độ C, và chuyển đổi các mã ký tự thành một ký tự. Bạn sẽ thấy tất cả các hàm này được sử dụng sau này như thế nào trong các trang.

Navigation

Mô-đun navigation là một mô-đun trợ giúp tùy biến cho phép chúng ta dễ dàng điều hướng giữa tất cả các trang của ứng dụng. Mở tập tin common/navigation.ts và thêm những thứ sau đây:

Việc này sử dụng mô-đun Frame để điều hướng đến các trang khác của ứng dụng. Phương thức getStartPage() đơn giản là trả về vị trí của trang ứng dụng chính. goToForecastPage(), như tên gọi của nó, cho phép người dùng điều hướng đến trang dự báo.

Khi điều hướng trong NativeScript, bạn cần phải có một tham chiếu đến vị trí hiện tại của bạn. Đó là lý do tại sao trước tiên bạn cần phải gọi hàm topmost() để lấy trang hiện tại hoặc trang trên cùng, và sau đó gọi hàm navigate() để chuyển sang một trang khác. Hàm này nhận đường dẫn đến trang mà bạn muốn đi tới.

Requestor

Mô-đun Requestor gửi yêu cầu thật sự đến OpenWeatherMap API. Như đã đề cập trong bài Giới thiệu về NativeScript, NativeScript sử dụng một máy ảo JavaScript để chạy code JavaScript. Điều này có nghĩa là chúng ta cũng có thể sử dụng các hàm có sẵn trong trình duyệt.

Một hàm như vậy là fetch, nó cho phép chúng ta tạo các yêu cầu HTTP đến một máy chủ từ xa. Tham số là URL nơi mà bạn muốn thực hiện yêu cầu. Nó trả về một promise vì vậy chúng ta sử dụng then() để chờ dữ liệu phản hồi thô. Lưu ý việc sử dụng từ "thô"; hàm fetch trả về phản hồi với các header và các thông tin cấp thấp khác - đó là lý do tại sao chúng ta cần phải gọi hàm json() để lấy dữ liệu JSON thật sự. Hàm này sẽ trả về một promise khác vì thế chúng ta sử dụng then() một lần nữa để lấy ra đối tượng thực tế.

Ngoài ra, bạn có thể sử dụng mô-đun Http, là một cách mạnh mẽ hơn để thực hiện các yêu cầu HTTP trong NativeScript.

Location Store

Location store đóng vai trò như là bộ lưu trữ thông tin vị trí. Điều này cho phép chúng ta cập nhật và lấy vị trí hiện tại từ bất kỳ tập tin nào import cái mô-đun này.

Trang chính

Đã đến lúc để xem xét code cho từng trang của ứng dụng. Nhưng trước khi chúng ta làm điều đó, trước tiên hãy mở tập tin khởi điểm (app.ts). Tập tin này sử dụng mô-đun navigation để lấy trang bắt đầu của ứng dụng:

Tiếp theo, chúng ta hãy phân chia tập tin pages/main/main.xml.

Sự kiện navigatingTo được sử dụng để thực thi một hàm cùng tên trong tập tin TypeScript mỗi khi người dùng điều hướng đến trang cụ thể này. Lớp CSS cũng tự động được xác định từ tập tin TypeScript.

Thành phần ScrollView được sử dụng để bao quanh mọi thứ từ đó một thanh cuộn theo chiều dọc được tạo ra tự động khi nội dung vượt quá kích thước mà màn hình có thể hiển thị.

Và bởi vì chúng ta sẽ nạp dữ liệu từ một máy chủ từ xa, nên thành phần ActivityIndicator được sử dụng để hiển thị hiệu ứng đang nạp mặc định của nền tảng. Điều này đòi hỏi bạn phải cung cấp một thuộc tính busy, mà chấp nhận một giá trị boolean kiểm soát việc có bắt đầu hiệu ứng hay không. Mặc định, biến này được thiết lập thành true và chỉ được cập nhật là false khi ứng dụng đã hoàn tất yêu cầu đến máy chủ.

Thuộc tính visibility cũng được sử dụng để đảm bảo rằng thành phần này không chiếm bất kỳ khoảng trống nào khi nó không được kích hoạt.

Đối với nội dung chính, chúng ta có cái nhìn tổng quát về thời tiết hiện tại ở trên cùng, và các chi tiết ở bên dưới nó. Phần tổng quát hiển thị một biểu tượng đại diện cho thời tiết hiện tại, nhiệt độ hiện tại, mô tả thời tiết và địa điểm.

Đối với thông tin chi tiết, có một khối thông tin về thời tiết hiện tại mà bạn có thể dự đoán bằng cách nhìn vào thuộc tính text. Mỗi một cái còn kèm theo biểu tượng của riêng nó.

Trên ảnh minh hoạ mà tôi đã cho bạn thấy trước đó, bạn thấy rằng nó sử dụng bố cục hai cột cho cả hai trang. Đó là lý do tại sao chúng ta đang sử dụng GridLayout. Nhưng như bạn thấy từ đoạn code ở bên dưới, chúng ta cũng sử dụng một GridLayout cho cột đầu tiên của mỗi hàng.

Bạn có thể thắc mắc lý do tại sao chúng ta làm điều này thay vì chỉ cần tạo bố cục ba cột với biểu tượng ở trên cột đầu tiên, thuộc tính thời tiết ở cột thứ hai và giá trị ở cột thứ ba. Điều đó hoàn toàn dễ hiểu, và nó sẽ làm cho code trở nên ngắn gọn hơn.

Nhưng vấn đề là NativeScript phiên bản 2.1 hiện không chấp nhận đơn vị phần trăm cho GridLayout của nó. Điều này có nghĩa là chúng ta không thể sử dụng 10% cho biểu tượng trong khi hai cột kia chiếm 45% mỗi cái.

Bố cục mà chúng ta sử dụng bên dưới giải quyết dược vấn đề đó bằng cách sử dụng một GridLayout để bao quanh biểu tượng và thuộc tính thời tiết, với biểu tượng chiếm 30 pixel và thuộc tính thời tiết chiếm khoảng trống cần thiết để chứa văn bản. Cũng cần lưu ý việc sử dụng thuộc tính rowcol trên GridLayout.

Markup cuối cùng cho trang chính đó là cái nút dẫn đến trang dự báo:

JavaScript cho Trang chính

Mở tập tin pages/main/main.ts và thêm code sau đây:

Trong đoạn code ở trên, chúng ta import một vài mô-đun NativeScript được tích hợp sẵn, model-view chính, và navigation.

Đối tượng EventData được trích xuất bằng object destructuring, một tính năng của ES6 được cung cấp bởi TypeScript. EventData là những gì mà chúng ta truyền vào như một đối số cho hàm navigatingTo để nó có thể truy cập vào bất kỳ dữ liệu nào được truyền vào bởi bất kỳ trang nào điều hướng đến trang này.

Nó có một thuộc tính object, về cơ bản là bất cứ thành phần nào kích hoạt sự kiện. Trong trường hợp này, chúng ta biết rằng nó được kích hoạt trên thành phần Page, và đó là lý do chúng ta sử dụng <Page> như là một type-assertion. Sau đó, chúng ta ràng buộc model-view chính vào trang. Điều này sẽ cho phép chúng ta thêm hoặc cập nhật một thuộc tính trong lớp, và nó sẽ ngay lập tức được phản ánh trên trang.

Trong model-view chính (pages/main/main-view-model.ts), trước tiên hãy import tất cả các mô-đun mà chúng ta sẽ sử dụng:

Tạo model-view bằng cách mở rộng mô-đun Observable, cái mà làm cho tất cả các thuộc tính trong lớp này thành observable. Điều này có nghĩa là tất cả các tham chiếu của mỗi thuộc tính trong UI sẽ được cập nhật mỗi khi nó được thay đổi trong lớp này.

Bên trong hàm xây dựng, kiểm tra xem geolocation có được kích hoạt hay không. Nếu nó không được kích hoạt thì hãy thử kích hoạt nó bằng cách gọi hàm enableLocationRequest(). Hàm này kích hoạt ứng dụng để yêu cầu người dùng bật geolocation.

Tiếp theo, xác định xem nó là ngày hay đêm và thiết lập hình nền trang tuỳ theo kết quả. Sau đó thiết lập các biểu tượng trong trang.

Sau đó, hãy thử xác định vị trí hiện tại. Lưu ý rằng, nếu người dùng không kích hoạt geolocation thì ứng dụng sẽ không hoạt động vì thời tiết phụ thuộc vào vị trí của người dùng. Ứng dụng sẽ cố gắng xác định vị trí của người dùng trong 10 giây. Nếu không được, thì một thông báo lỗi được hiển thị cho người dùng.

Nếu đã xác định được vị trí, chúng ta sẽ lưu nó bằng locationStore. Việc này cho phép chúng ta truy cập vị trí trên các trang khác sau này mà không cần phải yêu cầu lại.

Để cho bạn tham khảo, ở đây là một phản hồi mẫu mà bạn có thể nhận được khi yêu cầu vị trí trong NativeScript. Bạn có thể tham khảo tài liệu hướng dẫn về Location trong NativeScript để tìm hiểu thêm về mỗi thuộc tính ở bên dưới.

Chúng ta có thể cấu trúc URL đầy đủ của yêu cầu đến API bằng template literals và thực hiện yêu cầu bằng mô-đun Requester.

Khi nhận được một phản hồi, hãy trích xuất và định dạng nó, và sau đó thiết lập giá trị kết quả như là một thuộc tính của lớp. Và bởi vì lớp là observable, nên điều này sẽ tự động cập nhật UI của ứng dụng.

Để bạn tham khảo, dưới đây là một phản hồi mẫu có thể được trả về bởi API:

Bạn có thể tìm thấy thông tin chi tiết về mỗi thuộc tính trong tài liệu hướng dẫn về dữ liệu thời tiết hiện tại.

Cuối cùng, hàm setIcons(), thiết lập tất cả các biểu tượng được sử dụng trong trang:

Phong cách và Biểu tượng cho Trang chính

Dưới đây là các phong cách cho trang chính:

Lưu ý việc sử dụng weathericons như là font-family cho các lớp iconsmall-icon. Đây là cách chúng ta sử dụng phông chữ biểu tượng trong NativeScript. Nếu bạn thích sử dụng Font Awesome trên các trang web của mình, bạn có thể sử dụng chúng tương tự trong các ứng dụng NativeScript.

Đầu tiên, tải về phông chữ biểu tượng mà bạn muốn sử dụng. Đối với ứng dụng này, Weather Icons Font được sử dụng. Trích xuất tập tin nén zip và bên trong thư mục được giải nén, truy cập vào thư mục font. Sao chép tập tin .ttf vào thư mục fonts trong ứng dụng của bạn và đổi tên nó thành weathericons.ttf. Tên tập tin là những gì bạn sử dụng làm giá trị cho font-family mỗi khi bạn muốn sử dụng phông chữ biểu tượng cụ thể đó. Bên cạnh đó, bạn cũng phải thêm font-size để kiểm soát kích thước của các biểu tượng.

Trang Dự báo

Bây giờ hãy xem markup cho trang dự báo (pages/forecast/forecast.xml). Trong phần header, có một nút back cho phép người dùng quay trở lại trang chính. Lưu ý rằng thay vì sử dụng thành phần Button chung, chúng ta sử dụng một NavigationButton, tương đương với nút back của iOS và nút điều hướng của Android.

Đối với nội dung chính, thành phần Repeater được sử dụng thay vì ListView thông thường. Cả hai thành phần này đều có thể được sử dụng để tạo ra một danh sách, nhưng ListView đi kèm với nhiều tính năng không cần thiết. Ví dụ, nó tự động tạo ra một thanh cuộn dọc khi danh sách vượt quá kích thước của màn hình. Chức năng cuộn vô hạn cũng được tích hợp sẵn.

Thành phần Repeater được sử dụng trong trường hợp này bởi vì không có nhu cầu thật sự đối với các tính năng mà tôi vừa mới đề cập đến. Tất cả những gì chúng ta cần là một danh sách cơ bản.

Bên trong mỗi Repeater.itemTemplate là một GridLayout với hai cột, một cột cho thông tin thời tiết chung chung và một cột cho thông tin chi tiết.

Cột đầu tiên là StackLayout có chứa ngày, biểu tượng thời tiết, và mô tả thời tiết. Cột thứ hai cũng là một StackLayout chứa bốn GridLayout mà sẽ chứa bốn thuộc tính thời tiết (nhiệt độ, tốc độ gió, lượng mây, và áp suất không khí).

GridLayout đầu tiên có ba cột để chứa biểu tượng, nhiệt độ ban ngày và nhiệt độ ban đêm. Ba hàng kia chỉ có hai cột - dành cho biểu tượng và giá trị của thuộc tính thời tiết.

Lưu ý việc sử dụng $parents['Page']. Khi sử dụng thành phần Repeater hoặc ListView, bạn không thể truy xuất dữ liệu bên ngoài mảng mà bạn đã chỉ định cho danh sách - ngoại trừ bạn chỉ định rõ thành phần cha nơi dữ liệu tồn tại. Đó là nơi $parents['Page'] xuất hiện. $parents là một biến đặc biệt trong NativeScript cho phép bạn truy xuất dữ liệu có trên một thành phần cụ thể. Trong trường hợp này, chúng ta chỉ định Page để truy xuất các biểu tượng cho mỗi thuộc tính thời tiết.

JavaScript cho Trang Dự báo

Code cho trang dự báo khá giống với code cho trang chính. Sự khác nhau duy nhất đó là chức năng điều hướng để quay trở lại trang chính, và chúng ta sử dụng ForecastViewModel làm model-view.

Đây là code cho model-view (pages/forecast/forecast-view-model.ts):

Bên trong hàm xây dựng, chúng ta lấy vị trí hiện tại từ Location Store và cấu trúc URL endpoint cho dự báo thời tiết trong 16 ngày. Nhưng thay vì 16, chúng ta chỉ muốn năm ngày, vì vậy chúng ta chỉ định 6 (cnt). Chúng ta sử dụng 6 bởi vì múi giờ phụ thuộc vào máy chủ và không dựa vào vị trí được chỉ định. Điều này có nghĩa là có một khả năng là API sẽ trả về thời tiết cho ngày hôm trước hoặc ngày hiện tại. Đó là lý do tại sao có thêm 1 ngày đóng vai trò như là phần đệm.

Tiếp theo, thực hiện yêu cầu và cập nhật UI bằng phản hồi từ API bằng cách gọi hàm getForecast():

Dưới đây là một phản hồi mẫu được trả về bởi endpoint dự báo cho 16 ngày. Lưu ý rằng, để làm cho dữ liệu mẫu này trở nên súc tích hơn, tôi đã thiết lập số đếm thành 1, đó là lý do tại sao thuộc tính list chỉ chứa một đối tượng.

Phong cách cho Trang Dự báo

Dưới đây là các phong cách cho trang dự báo (pages/forecast/forecast.css):

Phong cách Toàn cục cho Ứng dụng

Mở tập tin app.css và thêm các phong cách sau:

6. Thay đổi Biểu tượng Mặc định của Ứng dụng

Bạn có thể thay đổi biểu tượng mặc định của ứng dụng bằng cách vào thư mục App_Resources. Ở đó bạn có thể nhìn thấy một thư mục Android và iOS. Đối với Android, bạn có thể thay thế tập tin hình ảnh trong từng thư mục sau đây để thay đổi biểu tượng:

  • drawable-hdpi
  • drawable-ldpi
  • drawable-mdpi

Đối với iOS, nó là hình ảnh bên trong thư mục Assets.xcassets/AppIcon.appiconset cái mà bạn muốn thay thế.

Nếu bạn muốn dễ dàng tạo biểu tượng cho cả Android và iOS, hãy tham khảo MakeAppIcon. Chỉ cần chọn một tập tin hình ảnh để sử dụng làm biểu tượng, và nó sẽ tự động tạo ra các kích cỡ khác nhau cho cả Android và iOS. Sau đó, bạn có thể di chuyển chúng đến các thư mục được đề cập ở trên. Chỉ cần đảm bảo rằng bạn có các kích thước phù hợp, và tên giống với những hình ảnh mà chúng thay thế.

7. Chạy Ứng dụng

Bạn có thể chạy ứng dụng trên thiết bị hoặc emulator của mình như bình thường bằng cách chạy các lệnh tns sau:

Sự khác biệt hiện giờ đó là chúng ta đang sử dụng TypeScript đó là thêm một bước nữa khi bắt đầu mỗi tác vụ, để biên dịch các tập tin TypeScript thành JavaScript. Kiểm tra kiểu mạnh của TypeScript đóng vai trò là một safety net để bắt một số lỗi trước khi NativeScript biên dịch ứng dụng.

Tóm tắt

Trong hướng dẫn này, bạn đã được học cách xây dựng một ứng dụng với NativeScript bằng ngôn ngữ TypeScript. Cụ thể, bạn đã học được các khái niệm sau đây:

  • Cấu trúc ứng dụng bằng cách đặt các tập tin có liên quan vào trong thư mục của riêng chúng.
  • Viết code có thể tái sử dụng bằng mô-đun
  • Sử dụng model-view để cung cấp dữ liệu và tính năng cho các trang của ứng dụng.
  • Xác định vị trí bằng plugin geolocation.
  • Tạo các yêu cầu HTTP.
  • Sử dụng phông chữ biểu tượng.
  • Điều hướng qua lại giữa các trang.

Tôi sẽ cung cấp cho bạn một vài tài liệu để bạn tiếp tục hành trình phát triển ứng dụng tuyệt vời với NativeScript:

  • Đọc hướng dẫn về cách xuất bản ứng dụng NativeScript của bạn trên Google Play hoặc App Store.
  • Đăng ký Bản tin NativeScript và cập nhật những gì đang diễn ra trong cộng đồng NativeScript.
  • Tham khảo Awesome NativeScript, một bộ sưu tập các thư viện, công cụ, tài nguyên và ứng dụng NativeScript tuyệt vời.
  • Xem khoá học Làm quen với TypeScript của chúng tôi trên Envato Tuts+.
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.