摘要
上一篇文章主要介紹了一個ionic項目的標准目錄結構,header標簽的使用,以及頁面之間的切換。這篇文章實現的功能有: 消息數據的獲取, 消息列表的展示, 消息標為已讀/未讀, 主要涉及的到的知識點有:
- ion-list的使用
- ion-popup的使用
- 通過sass自定義樣式
- localStorage的使用
- 自定義指令和服務
先看效果圖:
功能分析
在開始之前, 最好先思考一下消息頁面的主要功能, 和大概如何實現. 這樣后面寫程序才不會亂. 我大體列了一下
消息的數據暫時用localStorage存儲, 但這不是好的方式, localStorage可能會被文件清理掉, 后面會換sqlite存儲
頁面布局
首先在'tab-message.html'中添加聊天消息的布局
<ion-view>
<ion-content on-swipe-left="onSwipeLeft()">
<!--這里的rj-close-back-drop是自定義指令, 后面會講是干嘛的-->
<ion-list rj-close-back-drop>
<ion-item class="item-avatar" on-hold="popupMessageOpthins($index)" rj-hold-active ng-repeat="message in messages">
<img ng-src="{{message.pic}}">
<!--這個就是來了新消息, 頭像上的小紅數字-->
<span class="rj-sm-red-icon" ng-show="message.showHints"><p ng-bind="message.noReadMessages"></p></span>
<h2 ng-bind="message.name"></h2>
<p class="rj-list-p" ng-bind="message.lastMessage.content"></p>
<span class="rj-push-right" ng-bind="message.lastMessage.time"></span>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
大家在試這個的時候, 由於'messages'還未定義, 先不綁定, 用實際的值代替,像這樣
<img src="img/ben.png">
<span class="rj-sm-red-icon"><p>1</p></span>
<h2>小王</h2>
<p class="rj-list-p">你在干什么?</p>
<span class="rj-push-right">12:30</span>
這樣就能看到效果了
自定義樣式
可以看到上圖有點丑, 需要我們自己修改樣式, 可以自己添加css文件link進來, 但官方推薦使用sass的方式修改, 關於sass的語法, 可以看這個, 看完就差不多可以了.
首先在項目目錄下,運行命令
$ionic setup sass
$ionic serve
運行以后, 就會對scss/ionic.app.scss
文件監控, 有修改, 會自動編譯該文件, 輸出到css/ionic.app.css
所以你每次修改保存scss文件后, 瀏覽器會看到實時的效果, 非常方便.
打開scss/ionic.app.scss
文件, 如下
/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.
For example, you might change some of the default colors:
$light: #fff !default;
$stable: #f8f8f8 !default;
$positive: #387ef5 !default;
$calm: #11c1f3 !default;
$balanced: #33cd5f !default;
$energized: #ffc900 !default;
$assertive: #ef473a !default;
$royal: #886aea !default;
$dark: #444 !default;
*/
// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;
可以看到官方預定義的顏色幾個顏色, 如果要修改預定義的顏色, 直接修改這里就可以了.
我們自己的樣式, 直接在后面添加. 我們在后面添加
$item-avatar-border-radius: 0;
可以發現頭像變成方的了, 那怎么知道修改這個變量呢?
打開www/lib/ionic/scss/
目錄, 可以看到很多scss文件
├── _action-sheet.scss
├── _animations.scss
├── _backdrop.scss
├── _badge.scss
├── _bar.scss
├── _button-bar.scss
├── _button.scss
├── _checkbox.scss
├── _form.scss
├── _grid.scss
├── ionicons
├── ionic.scss
├── _items.scss
├── _list.scss
├── _loading.scss
├── _menu.scss
├── _mixins.scss
├── _modal.scss
...
這些都是官方的樣式文件, 找到items.scss
文件, 這個就是ion-item相關的樣式, 再搜border-radius
很快就能找到啦
具體的細節我就不說啦, 其它的修改都類似, 可以參考我的代碼
popup的使用
關於$ionicPopup的詳細使用, 可以參考官網
首先在controllers.js
文件中添加一個controller:
.controller('messageCtrl', function($scope, $state, $ionicPopup, localStorageService, messageService) {
$scope.popup = {
isPopup: false,
index: 0
};
$scope.onSwipeLeft = function() {
$state.go("tab.friends");
};
$scope.popupMessageOpthins = function($index) {
$scope.popup.index = $index;
//這里通過$ionicPopup.show()方法創建了一個自定義的popup
$scope.popup.optionsPopup = $ionicPopup.show({
templateUrl: "templates/popup.html",
scope: $scope,
});
$scope.popup.isPopup = true;
};
//實現標為已讀/未讀, 注意$scope.popup.optionsPopup.close()方法
//用來關閉彈窗, 我竟然找了很久才發現這個接口
$scope.markMessage = function() {
var index = $scope.popup.index;
var message = $scope.messages[index];
if (message.showHints) {
message.showHints = false;
message.noReadMessages = 0;
}else{
message.showHints = true;
message.noReadMessages = 1;
}
$scope.popup.optionsPopup.close();
$scope.popup.isPopup = false;
messageService.updateMessage(message);
};
這里要注意兩點
- 要在routes.js中將該controll傳進去
- 需要通過自定義樣式, 去掉自帶的標題和按鈕
//routes.js
.state('tab.message', {
url: '/message',
views: {
'tab-message': {
templateUrl: 'templates/tab-message.html',
controller: "messageCtrl"
}
}
})
自定義指令
細心的人會發現兩個問題:
- 彈出popup時, 聯系人列表沒有動畫效果
- 彈出popup后, 點擊popup以外的地方, popup不能消失, 這兩個問題, 就通過自定義指令來解決
首先在directives.js
文件中添加rjCloseBackDrop
指令, 用來解決上面第二個問題
.directive('rjCloseBackDrop', [function() {
return {
scope: false,//共享父scope
restrict: 'A',
replace: false,
link: function(scope, iElm, iAttrs, controller) {
//要在html上添加點擊事件, 試了很久- -!
var htmlEl = angular.element(document.querySelector('html'));
htmlEl.on("click", function(event) {
if (event.target.nodeName === "HTML" &&
scope.popup.optionsPopup &&
scope.popup.isPopup) {
scope.popup.optionsPopup.close();
scope.popup.isPopup = false;
}
});
}
};
}])
再創建rjHoldActive
指令, 用來解決第一個問題
.directive('rjHoldActive', ['$ionicGesture', '$timeout',
function($ionicGesture, $timeout, $ionicBackdrop) {
return {
scope: false,
restrict: 'A',
replace: false,
link: function(scope, iElm, iAttrs, controller) {
$ionicGesture.on("hold", function() {
iElm.addClass('active');
//300ms后恢復
$timeout(function() {
iElm.removeClass('active');
}, 300);
}, iElm);
}
};
}
])
最后分別在ion-list
和ion-item
上添加指令
<ion-list rj-close-back-drop>
<ion-item class="item-avatar"rj-hold-active ng-repeat="message in messages">
ok, 問題解決, 有點小激動~
自定義服務
前面講的都是界面的東西, 那聊天記錄的數據哪里來?
這里我們自定義一個假json數據, 用來模擬, 在www
目錄下創建文件data/json/messages.json
"messages": [{
"id": 0,
"name": "李明",
"pic": "img/adam.jpg",
"lastMessage": {
"time": "2015-10-12 15:34:55",
"content": "你在干什么?",
"isFromeMe": false
},
"noReadMessages": 2,
"showHints": true
},...
目前用到的數據都定義在這, 后面還需要什么數據再添加
我們把數據存到localstorage
中, 大家都知道localstorage
是基於key
和value
存儲的
總不能把所以人的消息都存在一條key中, 所以我定義兩個服務
- 把整個json數據拆成單獨的message, 把獨立的message合並成一個對象
- 封裝setItem, 基本數據的存儲獲取
具體我就不貼代碼了, 講下服務定義好了, 怎么使用, 比如定義了一個test
服務:
.factory('test', ['', function(){
return{
dosomething: function(){
return 0;
}
};
}])
用的時候直接把test
注入, test.dosomething()
調用:
.controller('someCtrl', function($scope, test) {
test.dosomething();
...
}
是不是很簡單?
最后
這篇寫的很長, 其實實現的功能很簡單, 主要是要學會如何定義樣式, 自定義指令, 自定義服務
這樣在后面實現更復雜的功能時, 不至於糾結這些細節.
我發現一個人自學, 確實有些困難, 一些小問題百度根本搜不到, google上才比較靠譜
所以小伙伴們遇到困難, 不妨google一下, 基本都有答案的哦
有問題歡迎大家評論, 我會的會及時回復~