答案 0 :(得分:0)
虽然这是一个老问题, Ionic v2 + 目前可用于此原生导航抽屉功能(<ion-menu>
)。我只想分享一些代码,展示如何在 Ionic v1 应用中实现此功能。我认为这对那些仍然在移动应用中使用 Ionic v1 的人有所帮助。此帖还可以找到 Ionic v2 + 实现。
我刚刚使用他们现成的sidemenu
应用模板创建了一个示例 Ionic v1 应用。
ionic start myApp sidemenu --type ionic1
然后我在 nativeSideMenu.js
文件夹中创建了以下 js
文件。
(function () {
'use strict';
angular.module('ionic.contrib.NativeDrawer', ['ionic'])
.controller('drawerCtrl', ['$rootScope', '$scope', '$element', '$attrs', '$ionicGesture', '$ionicBody', '$document', function ($rootScope, $scope, $element, $attr, $ionicGesture, $ionicBody, $document) {
var el = document.querySelectorAll("drawer")[0];
var mainContent = angular.element(document.querySelectorAll("ion-pane")[0]);
var dragging = false;
var startX, lastX, offsetX, newX, startY, lastY, offsetY, newY;
var side;
var isOpen = false;
var primaryScrollAxis = null;
mainContent.addClass('drawer-content');
// How far to drag before triggering
var thresholdX = 10;
// How far from edge before triggering
var edgeX = 40;
// Width of drawer set in css
var drawerWidth = 270;
var LEFT = 0;
var RIGHT = 1;
var isTargetDrag = false;
var isContentDrag = false;
var width = $element[0].clientWidth;
var height = $element[0].clientHeight;
var enableAnimation = function () {
angular.element(el).addClass('animate');
};
var disableAnimation = function () {
angular.element(el).removeClass('animate');
};
// Check if this is on target or not
var isTarget = function (el) {
while (el) {
if (el === $element[0]) {
return true;
}
el = el.parentNode;
}
};
var startDrag = function (e) {
disableAnimation();
dragging = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
$ionicBody.addClass('drawer-open');
};
var startTargetDrag = function (e) {
disableAnimation();
dragging = true;
isTargetDrag = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
};
var doEndDrag = function (e) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
if (isOpen && newX < (-width / 3)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else if (newX < (-width / 1.5)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(0px, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
}
};
var doEndContentDrag = function (e) {
if (startX > lastX) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
isContentDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
}
else {
el.style.transform = el.style.webkitTransform = 'translate3d(0 0, 0)';
}
};
var doDrag = function (e) {
if (e.defaultPrevented) {
return;
}
if (!lastX) {
startX = e.gesture.touches[0].pageX;
}
if (!lastY) {
startY = e.gesture.touches[0].pageY;
}
lastX = e.gesture.touches[0].pageX;
lastY = e.gesture.touches[0].pageY;
if (!dragging) {
// Dragged 15 pixels and finger is by edge
if (Math.abs(lastX - startX) > thresholdX) {
if (isTarget(e.target)) {
startTargetDrag(e);
} else if (startX < edgeX) {
startDrag(e);
}
}
// Closing from outside of drawer
else if (isOpen && startX > width) {
disableAnimation();
dragging = true;
isContentDrag = true;
}
} else {
newX = Math.min(0, (-width + (lastX - offsetX)));
newY = Math.min(0, (-height + (lastY - offsetY)));
var absX = Math.abs(lastX - startX);
var absY = Math.abs(lastY - startY);
if (isContentDrag && lastX < startX) {
var drawerOffsetX = lastX - drawerWidth;
el.style.transform = el.style.webkitTransform = 'translate3d(' + -absX + 'px, 0, 0)';
}
else if (isTargetDrag && absX > absY + 5) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
}
}
if (dragging) {
e.gesture.srcEvent.preventDefault();
}
};
side = $attr.side == 'left' ? LEFT : RIGHT;
var dragFunction = function (e) {
if (el.attributes.candrag) {
doDrag(e);
}
};
var dragEndFunction = function (e) {
if (el.attributes.candrag) {
doEndDrag(e);
}
};
var onContentDrag = function (e) {
if (isOpen) {
doDrag(e);
}
};
var onContentTap = function (e) {
if (isOpen) {
closeDrawer();
e.gesture.srcEvent.preventDefault();
}
};
var contentDragEndFunction = function (e) {
if (isOpen) {
doEndContentDrag(e);
e.gesture.srcEvent.preventDefault();
}
};
var openDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
};
var closeDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
};
var toggleDrawer = function () {
if (isOpen) {
closeDrawer();
} else {
openDrawer();
}
};
this.close = function () {
closeDrawer();
};
$rootScope.toggleDrawerRoot = function () {
toggleDrawer();
};
this.open = function () {
openDrawer();
};
this.toggle = function () {
toggleDrawer();
};
$ionicGesture.on('drag', function (e) {
doDrag(e);
}, $document);
$ionicGesture.on('dragend', function (e) {
doEndDrag(e);
}, $document);
var dragGesture = $ionicGesture.on('drag', dragFunction, $document);
var dragEndGesture = $ionicGesture.on('dragend', dragEndFunction, $document);
var contentTapGesture = $ionicGesture.on('tap', onContentTap, mainContent);
var contentDragGesture = $ionicGesture.on('drag', onContentDrag, mainContent);
var contentDragEndGesture = $ionicGesture.on('dragend', contentDragEndFunction, mainContent);
$scope.$on('$destroy', function () {
$ionicGesture.off(dragGesture, 'drag', dragFunction);
$ionicGesture.off(dragEndGesture, 'dragend', dragEndFunction);
$ionicGesture.off(contentTapGesture, 'tap', onContentTap);
$ionicGesture.off(contentDragGesture, 'drag', onContentDrag);
$ionicGesture.off(contentDragEndGesture, 'dragend', contentDragEndFunction);
});
}])
.directive('drawer', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
restrict: 'E',
controller: 'drawerCtrl',
link: function ($scope, $element, $attr, ctrl) {
$element.addClass($attr.side);
$scope.openDrawer = function () {
ctrl.open();
};
$scope.closeDrawer = function () {
ctrl.close();
};
$scope.toggleDrawer = function () {
ctrl.toggle();
};
}
}
}])
.directive('menuAndDrawerToggle', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
controller: '',
link: function ($scope, $element, $attr) {
$element.bind('click', function () {
$rootScope.toggleDrawerRoot();
});
}
};
}])
.directive('menuAndDrawerClose', ['$ionicViewService', function ($ionicViewService) {
return {
restrict: 'AC',
require: '^drawer',
link: function ($scope, $element, $attr, ctrl) {
$element.bind('click', function () {
ctrl.close();
});
}
};
}]);
})();
并在 nativeSideMenu.css
文件夹中创建了以下 css
文件
drawer {
display: block;
position: fixed;
width: 270px;
height: 100%;
z-index: 100;
background-color:white;
}
drawer .header-menu{
margin-top:0px;
padding-top:0px;
}
drawer .header-menu ion-list .list{
padding-top:0px;
}
drawer.animate {
-webkit-transition: all ease-in-out 400ms;
transition: all ease-in-out 400ms;
}
drawer.left {
-webkit-transform: translate3d(-101%, 0, 0);
transform: translate3d(-101%, 0, 0);
box-shadow: 1px 5px 10px rgba(0,0,0,0.3);
}
drawer.right {
right: 0;
top: 0;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
.drawer-open .drawer-content .pane, .drawer-open .drawer-content .scroll-content {
pointer-events: none;
opacity:0.2;
}
drawer .item-icon-left .icon{
font-size: 24px;
padding-bottom: 2px;
}
ion-side-menu .current a.item-content,ion-side-menu .clickable.current, drawer .current a.item-content, drawer .clickable.current {
color:#343434 !important;
}
drawer a.item-content, drawer .clickable{
color: #858585;
font-size:20px;
}
drawer .item-complex .item-content{
padding-top:16px;
padding-bottom:16px;
font-size:20px;
}
/*This section would normally have .platform-android at the front */
.platform-android4_0 drawer.left{
box-shadow: none;
border-left:0px;
border-right:0px;
}
.header-menu{
top:0px;
bottom:44px;
}
.menu .scroll-content {
top: 42px;
}
.menu-content{
box-shadow: none;
}
.drawer-open ion-pane.pane{
background-color: rgb(0,0,0);
}
.drawer-open view{
background-color: rgb(0,0,0);
}
.ion-view.pane{
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.menu-open ion-view.pane, .drawer-open ion-view.pane{
/* opacity:0.4;
*/
}
.bar .title.no-nav{
text-align: left;
left: 0px !important;
}
.bar .button-icon.ion-navicon{
margin-left: -20px;
padding-right: 20px;
}
.bar .title{
text-align: left;
left: 16px !important;
}
.modal-wrapper .bar .title{
text-align: center;
left: 0px !important;
}
.bar .title.title-center{
text-align: center;
left: 0px !important;
right: 0px !important;
}
.ion-ios7-arrow-back:before{
content:"\f2ca";
}
.bar .button.button-icon.ion-ios7-arrow-back:before{
font-size: 17px;
line-height: 32px;
padding-right: 100px;
}
之后我添加了 index.html
文件
<!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 rel="manifest" href="manifest.json">
<!-- un-comment this code to enable service worker
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.log('Error', err));
}
</script>-->
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<link href="css/nativeSideMenu.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>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/nativeSideMenu.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
</body>
</html>
然后我在{strong> ionic.contrib.NativeDrawer
文件的angular.module
中加入了app.js
。
angular.module('starter', ['ionic', 'starter.controllers','ionic.contrib.NativeDrawer'])
之后我更新了模板文件夹中 menu.html
文件的代码,如下所示。
<ion-side-menus>
<ion-side-menu-content>
<ion-nav-bar class="bar-stable bar-positive-900">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-and-drawer-toggle>
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-pane drawer-menu-content>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-pane>
</ion-side-menu-content>
<drawer side="left">
<ion-content>
<ion-list>
<ion-item menu-and-drawer-close ng-click="login()">
Login
</ion-item>
<ion-item menu-and-drawer-close href="#/app/search">
Search
</ion-item>
<ion-item menu-and-drawer-close href="#/app/browse">
Browse
</ion-item>
<ion-item menu-and-drawer-close href="#/app/playlists">
Playlists
</ion-item>
</ion-list>
</ion-content>
</drawer>
</ion-side-menus>
现在只需运行ionic serve
并在导航抽屉中有原生感。
使用以下参考链接了解更多详情
我们在 Ionic v2 + 中没有那么多工作要做,因为默认情况下它给出了导航抽屉的原生感觉。但我们可以通过将值传递到<ion-menu>
type
来改变这种行为
<ion-menu type="overlay" [content]="mycontent">...</ion-menu>
根据 DOC type
详情,如下所示。
菜单的显示类型。默认值因模式而异,请参阅 config中的menuType。可用选项:“叠加”,“显示”, “推”。
希望这对其他人有帮助!