ในบทเรียนนี้จะเป็นการใช้ Ionic Framework สร้างและออกแบบแอพพลิเคชันประเภท EBook หรือ Book Store ผ่านสมาร์ทโฟน หรือแท็บเล็ตด้วย AngularJS และ JSONแนวทางตัวอย่างนี้ได้ไอเดียของการออกแบบ Bookstore จากแอพพลิเคชัน AIS Bookstore บน Android
เพียงแค่เราจะใช้ Ionic Framework ในการพัฒนาในรูปแบบ HTML5 ดังนั้นให้สร้างโปรเจ็คใหม่ของเราทันทีด้วยการเปิด Command หรือ Terminal ดังนี้
อัพเด็ต Cordova ก่อน ด้วย
npm install -g cordova
อัพเด็ต ionic framework อีกทีด้วย
npm install -g ionic
จากนั้นให้ Run คำสั่งต่อไปนี้
ionic start bookstore blank -a BookStore -i com.daydev.bookstore
ซึ่ง -a คือชื่อแอพพลิเคชัน, -i คือชื่อ Package Name หรือ Bundle ID ส่วน blank คือรูปแบบเริ่มต้นของแอพพลิเคชันของเราว่าจะเป็นแบบไหนผมเลือก Blank
เมื่อสร้างเสร็จแล้วก็ให้ทำการ Run คำสั่ง
cd bookstore ionic serve --lab
ระบบจะเปิด Browser ขึ้นมาให้เราทดสอบว่าทำงานดีอยู่หรือไม่ดังภาพประกอบ
ส่วนของ API แล้วล่ะทีนี้ไม่ว่าจะเขียนด้วยอะไร ผมจะทำ API ของผมออกมาในรูปแบบนี้
Code หน้า JSON ทั้งหมดคือ
{ status_code: 200, banner: [ { id: 0, image: "http://www.ais.co.th/bookstore/gallery/34.png" }, { id: 1, image: "http://www.ais.co.th/bookstore/gallery/33.png" }, { id: 2, image: "http://www.ais.co.th/bookstore/gallery/35.png" }, { id: 3, image: "http://www.ais.co.th/bookstore/gallery/3.png" } ], book: [ { id: 0, title: "เพชรไร้กะรัต", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215094904.jpg" }, { id: 1, title: "ข้ามภพมาหารัก", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215094519.jpg" }, { id: 2, title: "สาวใช้เดลิเวรี่", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215093346.jpg" }, { id: 3, title: "Legend Online เล่ม 5", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215092915.jpg" }, { id: 4, title: "เพชรไร้กะรัต", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215094904.jpg" }, { id: 5, title: "ข้ามภพมาหารัก", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215094519.jpg" }, { id: 6, title: "สาวใช้เดลิเวรี่", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215093346.jpg" }, { id: 7, title: "Legend Online เล่ม 5", image: "http://www.satapornbooks.co.th/imgadmins/product_large/CoverBook_20160215092915.jpg" } ], magazine: [ { id: 0, title: "Playboy", image: "http://cdn-shop.ookbee.com/Books/Playboy/2016/20161038/Thumbnails/Cover.jpg" }, { id: 1, title: "Hello!", image: "http://cdn-shop.ookbee.com/Books/Hello!/2016/201611004/Thumbnails/Cover.jpg" }, { id: 2, title: "MBA Magazine", image: "http://cdn-shop.ookbee.com/Books/MBAMagazine/2016/201617194/Thumbnails/Cover.jpg" }, { id: 3, title: "Honeymoon Travel", image: "http://cdn-shop.ookbee.com/Books/HoneymoonTravel/2016/20163165/Thumbnails/Cover.jpg" }, { id: 4, title: "ชีวจิต", image: "http://cdn-shop.ookbee.com/Books/SGMensHealth/2016/20163002/Thumbnails/Cover.jpg" }, { id: 5, title: "GM Car", image: "http://cdn-shop.ookbee.com/Books/GMCar/2016/201621271/Thumbnails/Cover.jpg" }, { id: 6, title: "Playboy", image: "http://cdn-shop.ookbee.com/Books/Playboy/2016/20161038/Thumbnails/Cover.jpg" }, { id: 7, title: "Hello!", image: "http://cdn-shop.ookbee.com/Books/Hello!/2016/201611004/Thumbnails/Cover.jpg" } ] }
เรามาเริ่มที่การออกแบบเมน Sidemenu กันครับ ให้เราเปิดที่ไฟล์ index.html แก้ไข HTML ทั้งหมดเป็นดังนี้ (ยืม Path รูปภาพมาหน่อยแล้วกัน)
<!DOCTYPE html> <html > <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> <title></title> <link href="lib/ionic/css/ionic.css" rel="stylesheet"> <link href="css/style.css" rel="stylesheet"> <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above <link href="css/ionic.app.css" rel="stylesheet"> --> <!-- ionic/angularjs js --> <script src="lib/ionic/js/ionic.bundle.js"></script> <script src="lib/ngstorage/ngStorage.min.js"></script> <!-- cordova script (this will be a 404 during development) --> <script src="cordova.js"></script> <!-- your app's js --> <script src="js/app.js"></script> <!--Slider--> <script src="js/services/ngImgCache.js"></script> <link href="css/hscrollcards.min.css" rel="stylesheet"> <script src="js/ionic.hscrollcards.js"></script> </head> <body ng-app="myApp"> <ion-nav-view animation="slide-left-right"> </ion-nav-view> </body> </html>
เป็นการสร้าง Template Navigation หลังจากนั้นก็เราไปแก้ไขเพิ่ม $statParams ใน js/app.js
var app=angular.module('myApp', ['ionic']); app.run(function($ionicPlatform) { $ionicPlatform.ready(function() { if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); cordova.plugins.Keyboard.disableScroll(true); } if(window.StatusBar) { StatusBar.styleDefault(); } }); }) app.config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('main', { url: '/main', templateUrl: 'views/main.html', controller:'mainController' }) $urlRouterProvider.otherwise('/main'); });
กำหนด $state ใหม่ชื่อว่า “main” ให้เป็นหน้าเริ่มต้นที่
$urlRouterProvider.otherwise('/main');
โดยมีการเรียก View ที่ไฟล์ ‘view/main.html’
templateUrl: 'views/main.html', controller:'mainController'
และกำหนด controller ของ State นี้ว่า “mainController”
ดังนั้นเราต้องไปสร้าง โฟลเดอร์ว่า “views” ใน www ก่อนแล้วสร้างไฟล์ชื่อว่า main.html ใส่ code ดังต่อไปนี้
<div ng-controller="mainController"> <ion-view> <ion-side-menus> <ion-pane ion-side-menu-content> <ion-nav-bar class="bar-dark nav-title-slide-ios7"> <ion-nav-buttons side="left"> <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> </ion-nav-buttons> </ion-nav-bar> <ion-nav-view> <!--Content--> <ion-content> </ion-content> <!--Content--> </ion-nav-view> </ion-pane> <ion-side-menu side="left"> <ion-header-bar class="bar bar-header bar-dark" > <div class="white hil" ng-bind-html="dataMember"></div> </ion-header-bar> <ion-content has-header="true"> <div class="list" style="padding-top: 47px;"> <a class="item item-icon-left" href="#"> <i class="icon ion-home"></i> Home </a> <a class="item item-icon-left" href="#"> <i class="icon ion-star"></i> Favorite </a> </div> </ion-content> </ion-side-menu> </ion-side-menus> </ion-view> </div>
ทดสอบจะได้หน้าจอเมนู sidemenu ดังนี้
ต่อมาเราจะทำหน้าจอ Slide Banner ให้จัดการแก้ไขแค่ส่วนของ mainController ใน app.js และ main.html ใน views เท่านั้น โดยให้เราเริ่มที่ app.js ในส่วนของ mainController ก่อนให้เราสร้างขึ้นมาดังนี้ผ่านการเรียกใช้ $http เพิ่มดึงเว็บ service
app.controller('mainController', function($scope, $ionicSideMenuDelegate, $http, $stateParams) { $scope.contents = []; $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); }; $scope.greaterThan = function(fieldName){ return function(item){ return item[fieldName] > $scope.selected.score; } } $http.get("http://localhost/apibook/") .success(function (response) { $scope.banners = response.banner; }); });
แก้ไขเพิ่ม HTML ต่อไปนี้ในการดึงค่า ng-repeat ในส่วนของ <ion-content> ในไฟล์ main.html
<!--Content--> <ion-content> <!--Cover--> <!--start--> <ion-slide-box on-slide-changed="slideHasChanged($index)" does-continue="true" auto-play="true"> <ion-slide ng-repeat="banner in banners"> <img ng-cache ng-src="{{banner.image}}" onerror="this.src ='http://placehold.it/350x150';" class="covers"> </ion-slide> </ion-slide-box> <!--end--> <!--Cover--> </ion-content> <!--Content-->
ไปที่ไฟล์ css/style.css เพิ่ม class ต่อไปนี้เข้าไป
/* Empty. Add your own CSS if you like */ .covers{width:100vw; height:160px;}
ลองแสดงผลดูจะได้ดังนี้ เป็นตัวอย่างการใช้งาน ion-slide-box หรือ Banners Slider บนหน้าจอแอพพลิเคชัน
ต่อมาก็จัดการในส่วนของ BookShelf หรือชั้นวางหนังสือ ซึ่งต้องไปเพิ่ม ส่วนของ books และ magazines ใน mainController แก้ไข app.js ดังนี้ครับ
app.controller('mainController', function($scope, $ionicSideMenuDelegate, $http, $stateParams) { $scope.contents = []; $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); }; $scope.greaterThan = function(fieldName){ return function(item){ return item[fieldName] > $scope.selected.score; } } $http.get("http://localhost/apibook/") .success(function (response) { $scope.banners = response.banner; $scope.books = response.book; $scope.magazines = response.magazine; }); });
ให้มาแก้ไขที่ไฟล์ main.html เพิ่ม ng-repeat ไปดังนี้ครับ
<!--Book--> <ion-list> <ion-item> <div class="cateheader">BOOK</div> <ion-scroll direction = "x" class = "ionsclr"> <div class="paneview_item"> <div class="square_box" ng-repeat="item in books"> <div id="book{{item.id}}"> <a href="#"> <img ng-cache ng-src="{{item.image}}" onerror="this.src = 'http://placehold.it/350x150';" class="square"/> </a></div> <div class="title_small"> <a href="#">{{item.title}}</a> </div> </div> </div> </ion-scroll> </ion-item> </ion-list> <!--Book-->
เพิ่ม css ใน css/style.css ดังนี้
/* Empty. Add your own CSS if you like */ .covers{width:100vw; height:160px;} .ionsclr{width:100vw; height:150px;} .divleft{float:left;} .square_box{width:100px; height:155px; color:#FFF; float:left; margin-right: 8px; background-color:#ACC32A;} .square{width:100px !important; height:130px !important; } .title_small{color:#fff; font-size:10px;} .title_small a{color:#fff; font-size:10px; text-decoration:none;} .paneview_item{width: 160vw; height: 120px;}
แสดงผลจะเป็นดังนี้
ทดสอบในการเลื่อน Swipe ส่วนของ Gallery หนังสือจากซ้ายไปขวาได้ คราวนี้ก็ลองทำส่วนของ Magazine อีกครั้ง ปรับ Style Sheet ดีๆ ใกล้เคียงกัน ดังนั้นไฟล์ views/main.html จะเป็นดังนี้
<div ng-controller="mainController"> <ion-view> <ion-side-menus> <ion-pane ion-side-menu-content> <ion-nav-bar class="bar-dark nav-title-slide-ios7"> <ion-nav-buttons side="left"> <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> </ion-nav-buttons> </ion-nav-bar> <ion-nav-view> <!--Content--> <ion-content> <!--Cover--> <!--start--> <ion-slide-box on-slide-changed="slideHasChanged($index)" does-continue="true" auto-play="true"> <ion-slide ng-repeat="banner in banners"> <img ng-cache ng-src="{{banner.image}}" onerror="this.src ='http://placehold.it/350x150';" class="covers"> </ion-slide> </ion-slide-box> <!--end--> <!--Cover--> <!--Book--> <ion-list> <ion-item> <div class="cateheader">BOOK</div> <ion-scroll direction = "x" class = "ionsclr"> <div class="paneview_item"> <div class="square_box" ng-repeat="item in books"> <div id="book{{item.id}}"> <a href="#"> <img ng-cache ng-src="{{item.image}}" onerror="this.src = 'http://placehold.it/350x150';" class="square"/> </a></div> <div class="title_small"> <a href="#">{{item.title}}</a> </div> </div> </div> </ion-scroll> </ion-item> </ion-list> <!--Book--> <!--Magazine--> <ion-list> <ion-item> <div class="cateheader">MAGAZINE</div> <ion-scroll direction = "x" class = "ionsclr"> <div class="paneview_item"> <div class="square_box" ng-repeat="item in magazines"> <div id="mag{{item.id}}"> <a href="#"> <img ng-cache ng-src="{{item.image}}" onerror="this.src = 'http://placehold.it/350x150';" class="square"/> </a></div> <div class="title_small"> <a href="#">{{item.title}}</a> </div> </div> </div> </ion-scroll> </ion-item> </ion-list> <!--Magazine--> </ion-content> <!--Content--> </ion-nav-view> </ion-pane> <ion-side-menu side="left"> <ion-header-bar class="bar bar-header bar-dark" > <div class="white hil" ng-bind-html="dataMember"></div> </ion-header-bar> <ion-content has-header="true"> <div class="list" style="padding-top: 47px;"> <a class="item item-icon-left" href="#"> <i class="icon ion-home"></i> Home </a> <a class="item item-icon-left" href="#"> <i class="icon ion-star"></i> Favorite </a> </div> </ion-content> </ion-side-menu> </ion-side-menus> </ion-view> </div>
ไฟล์ js/app.js เป็นดังนี้
var app=angular.module('myApp', ['ionic']); app.run(function($ionicPlatform) { $ionicPlatform.ready(function() { if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); cordova.plugins.Keyboard.disableScroll(true); } if(window.StatusBar) { StatusBar.styleDefault(); } }); }) app.config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('main', { url: '/main', templateUrl: 'views/main.html', controller:'mainController' }) $urlRouterProvider.otherwise('/main'); }); app.controller('mainController', function($scope, $ionicSideMenuDelegate, $http, $stateParams) { $scope.contents = []; $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); }; $scope.greaterThan = function(fieldName){ return function(item){ return item[fieldName] > $scope.selected.score; } } $http.get("http://localhost/apibook/") .success(function (response) { $scope.banners = response.banner; $scope.books = response.book; $scope.magazines = response.magazine; }); });
และไฟล์ css/style.css จะเป็นดังนี้
/* Empty. Add your own CSS if you like */ .covers{width:100vw; height:160px;} .ionsclr{width:100vw; height:150px;} .divleft{float:left;} .square_box{width:100px; height:155px; color:#FFF; float:left; margin-right: 8px; background-color:#ACC32A;} .square{width:100px !important; height:130px !important; } .title_small{color:#fff; font-size:10px;} .title_small a{color:#fff; font-size:10px; text-decoration:none;} .paneview_item{width: 160vw; height: 120px;}
แอพพลิเคชันของเราจะมีหน้าจอแบบนี้
ไม่น่าจะยากนะครับการออกแบบ Layout แล้วใช้ Web Service ในการช่วยทำแอพพลิเคชัน Book Store ในบทเรียนต่อไปอาจจะต่อยอดทำส่วนหน้าด้านในที่มีการเรียกไฟล์ pdf จาก Service กลับมา เพื่อต่อยอดระบบสมาชิกเก็บค่า DRM ของ EBook ครับ
ถามว่าประสิทธิภาพของการเรียก Layout เท่ากับ Native ไหม ตอนนี้ทำแอพ Native ตัวหนึ่งที่ดูทีวีออนไลน์ครับ ก็จะแพ้ทางกันเวลาที่ข้อมูล Web Service ดึงมาเยอะเพราะ HTML5 จะเสียเรื่องของ RAM สูงกว่าอยู่แล้ว แต่ไม่เป็นไรครับเป็นแค่ทางเลือกให้ลองฝึกพัฒนา AnglarJS และ ionic framework ก็ยังดี
บทความอื่นๆ ที่น่าสนใจ ionic framework