ionic中的分類側邊欄ABC字母滑動特效
阿新 • • 發佈:2019-01-06
在對之前專案進行回顧整理的過程中,發現自己做過挺有意思的特效,今天重新來梳理一下。首先要說明一下的是,一些特效都要依賴合理的佈局和規範的資料以及相關資料格式的支撐,今天整理的這個,不是很完美,還有很大提升的空間,不過作為開發參考,確實有一定的幫助。技術棧範圍:ionic version 1,不管用的什麼技術,實現思路都是相通的。
效果預覽
備註:最後下拉動作的白條閃現不友好體驗是gif生成工具出現的問題,實際上並不存在,在其他部落格中出現的情況和這個相同。
github演示地址
View層佈局
關鍵程式碼:
<ion-view view-title="category" class="category">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<ion-content class="items-content" overflow-scroll="false" scrollbar-y="false" has-bouncing="true"
delegate-handle="cateContScroll">
<div repeat-finish ng-repeat="one in dataAll.abc" ng-if="dataAll.cate[one]" class="items-item-one">
<div class="items-title">{{one}}</div>
<div class="list">
<a class="item bd-b item-icon-left item-icon-right items-item" ng-repeat="item in dataAll.cate[one]">
{{item.name}}
</a>
</div>
</div>
</ion-content>
<category-touch-bar class="fixed-abc c-666" >
<ul>
<li ng-repeat="item in dataAll.abc">{{item}}</li>
</ul>
</category-touch-bar>
<!-- 展示字母 -->
<div class="letterShow center-center" ng-class="{cur:dataAll.letter}">{{dataAll.letter}}</div>
</ion-view>
Controller邏輯
關鍵程式碼:
angular.module('category.controller', ['categoryService'])
.controller('CategoryCtrl', [
'$scope',
'$rootScope',
'$timeout',
'$ionicScrollDelegate',
'appUtils',
'categoryData',
function ($scope, $rootScope, $timeout, $ionicScrollDelegate, appUtils, categoryData) {
/* 初始化資料模型 */
$scope.isLoading = false;
var fn = $scope.fn = {};
fn.go = appUtils.go;
var dataAll = $scope.dataAll = {};
dataAll.abc = [];
dataAll.cate = {};
dataAll.mapContainer = {}; // 初始化一個盛放各個標籤節點個數的物件
// 檢視事件
$scope.$on('$ionicView.beforeEnter', function () {
getAllCategory(); // 獲取資料,本地或者從網路獲取
});
// 得到所有分類資訊
function getAllCategory() {
// 此處只處理假資料,僅僅是個demo
// 如果是真實資料,那麼先判斷本地是否存在,如果不存在,那麼網路獲取,如果存在,直接使用。
angular.forEach(categoryData, function (item) {
if (item.firstletter) {
dataAll.cate[item.firstletter] = dataAll.cate[item.firstletter] || []; // 初始化單元
dataAll.cate[item.firstletter].push(item);
}
});
// 下面將是資料的格式轉換 將存在的ABC標籤存放到 dataAll.abc 中
for (var k in dataAll.cate) {
dataAll.abc.push(k);
dataAll.mapContainer[k] = dataAll.cate[k].length; // 儲存每個字母結點代表的分類的學科個數。
}
// 使用廣播方式, 想到以後這些資料有可能動態載入,存在非同步性
$rootScope.$broadcast("cate:boxCount", dataAll.abc.length);
dataAll.abc.sort(); // 從A到Z排序
}
// 接收廣播事件
$scope.$on('cate:touchMove', function (event, data) {
getScrollData(data);
});
// 隱藏懸浮的字母
$scope.$on('cate:touchEnd', function (event, data) {
if (!data) {
return;
}
// 0.3s之後隱藏
var t = $timeout(function () {
dataAll.letter = '';
$timeout.cancel(t);
}, 300);
});
// 接收click廣播
$scope.$on('cate:touchBarClick', function (event, data) {
getScrollData(data);
});
// 通用獲取滾動事件
function getScrollData(data) {
var distance = data.distance;
var unit = data.boxUnit;
var num = Math.ceil(distance / unit) - 1;
num = num < 0 ? 0 : num; // 對num進行過濾處理
dataAll.letter = dataAll.abc[num];
getScrollDistanceByLetter(dataAll.letter); // 根據字母開始滾動
$scope.$apply();
}
// 根據字母計算滾動的距離
function getScrollDistanceByLetter(letter) {
// 特殊情況 A
if (letter === 'A') {
return $ionicScrollDelegate.$getByHandle('cateContScroll').scrollTo(0, 0, false); // 滾動特效
}
var initHeight = 0; // 初始高度
// 迴圈累加,算出距離
for (var k in dataAll.abc) {
var item = dataAll.abc[k]; // 單項
// 直到和字母相同跳出迴圈
if (item === letter) {
break;
}
var count = dataAll.mapContainer[item];
initHeight += (22 + 61 * count);
}
$ionicScrollDelegate.$getByHandle('cateContScroll').scrollTo(0, initHeight, false); // 滾動特效
}
}])
Directive指令
關鍵程式碼:
.directive('categoryTouchBar', function ($rootScope) {
return {
restrict: 'EA',
replace: true,
link: function (scope, element) {
var ele = element[0]; // 獲取元素
var eleTop = 0; // touchBar元素距離瀏覽器頂部位置初始化
var eleClientRectTop = ele.getBoundingClientRect().top; // touchBar中心位置距離頂部的距離
var touchEnd = 0; // 移動結束的位置
var distance = 0; // 移動的距離
// 初始化其他用到的資料
var boxUnit = 16; // 此處是固定的單元字母高度
var boxHeight = 0; // 初始化盒子高度
/* 接收穫取的廣播資料 */
$rootScope.$on("cate:boxCount", function(e, data) {
if(!data) {
return ;
}
boxHeight = data * boxUnit; // 通過網路獲取,計算得出整體高度
});
// 滑動開始
ionic.EventController.on('touchstart', function (e) {
e.preventDefault();
eleTop = eleClientRectTop - boxHeight / 2; // 計算元素頂部距離瀏覽器頂部的位置
}, ele);
// 滑動中
ionic.EventController.on('touchmove', function (e) {
e.preventDefault();
touchEnd = e.touches[0].clientY;
distance = touchEnd - eleTop;
distance = distance > boxHeight ? boxHeight : (distance < 0 ? 0 : distance); // 超出過濾功能
// boxHeight是touchBar的高度, boxUnit是每個字元的高度, distance 是最後在touchBar上的位置距離touchBar頂部的位置。
var moveObj = {
boxHeight: boxHeight,
boxUnit: boxUnit,
distance: distance
};
scope.$emit('cate:touchMove', moveObj); // 傳送廣播
}, ele);
// 滑動結束隱藏
ionic.EventController.on('touchend', function () {
scope.$emit('cate:touchEnd', 1); // 傳送廣播
}, ele);
// 對單純點選的支援
ionic.EventController.on('click', function (e) {
var moveObj = {
boxHeight: boxHeight,
boxUnit: boxUnit,
distance: (e.pageY || e.y) - eleTop
};
scope.$emit('cate:touchBarClick', moveObj); // 傳送廣播
}, ele);
}
};
});
資料支撐
總結
很多技術細節的實現,都需要有相關知識的支撐,想要短時間做完一項你從來沒做過的任務,如果你有足夠的知識儲備,實際上你是有能力完成的,如果很多時候覺得任務對自己來說進展緩慢,那麼就是你缺乏相關的知識,所以說 積累 很重要。