enable swipe to open or close sidenav (#429)

* implement swipe on Sidenav

* update the docs

* prefix props with md- and update from destroyed to beforeDestroy

* refactor to clarify logic
This commit is contained in:
Igor Ribeiro 2017-02-07 00:37:47 -02:00 committed by Marcos Moura
parent add429966e
commit 65c1ff8453
2 changed files with 116 additions and 2 deletions

View file

@ -7,6 +7,36 @@
<div slot="api">
<api-table name="md-sidenav">
<md-table slot="properties">
<md-table-header>
<md-table-row>
<md-table-head>Name</md-table-head>
<md-table-head>Type</md-table-head>
<md-table-head>Description</md-table-head>
</md-table-row>
</md-table-header>
<md-table-body>
<md-table-row>
<md-table-cell>md-swipeable</md-table-cell>
<md-table-cell><code>Boolean</code></md-table-cell>
<md-table-cell>Enable the swipe functionality. Default <code>false</code></md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-swipe-threshold</md-table-cell>
<md-table-cell><code>Number</code></md-table-cell>
<md-table-cell>Set the initial threshold for the swipe when it's closed. Default <code>15</code></md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-swipe-distance</md-table-cell>
<md-table-cell><code>Number</code></md-table-cell>
<md-table-cell>Set the swipe distance needed to open/close the sidenav. Default <code>100</code></md-table-cell>
</md-table-row>
</md-table-body>
</md-table>
<md-table slot="classes">
<md-table-header>
<md-table-row>
@ -102,7 +132,7 @@
<p>Open console to see the events</p>
</div>
<md-sidenav class="md-left" ref="leftSidenav" @open="open('Left')" @close="close('Left')">
<md-sidenav class="md-left" ref="leftSidenav" @open="open('Left')" @close="close('Left')" md-swipeable>
<md-toolbar class="md-large">
<div class="md-toolbar-container">
<h3 class="md-title">Sidenav content</h3>

View file

@ -4,7 +4,7 @@
<slot></slot>
</div>
<md-backdrop class="md-sidenav-backdrop" @close="close"></md-backdrop>
<md-backdrop class="md-sidenav-backdrop" @close="close" ref="backdrop"></md-backdrop>
</div>
</template>
@ -20,6 +20,17 @@
};
},
mixins: [theme],
props: {
mdSwipeable: Boolean,
mdSwipeThreshold: {
type: Number,
default: 15
},
mdSwipeDistance: {
type: Number,
default: 100
}
},
computed: {
classes() {
return this.mdVisible && 'md-active';
@ -45,7 +56,80 @@
} else {
this.open();
}
},
isHorizontallyInside(positionX) {
return positionX > 0 && positionX < this.mountedRect.left + this.mountedRect.width;
},
isVerticallyInside(positionY) {
return positionY > 0 && positionY < this.mountedRect.top + this.mountedRect.height;
},
isFromStartWhenClosed(positionX) {
if (this.mdVisible) {
return true;
}
return positionX < this.mdSwipeThreshold;
},
handleTouchStart(event) {
const positionX = event.touches[0].clientX - this.mountedRect.left;
const positionY = event.touches[0].clientY - this.mountedRect.top;
if (
!this.isHorizontallyInside(positionX) ||
!this.isVerticallyInside(positionY) ||
!this.isFromStartWhenClosed(positionX)
) {
return;
}
this.initialTouchPosition = positionX;
this.canMove = true;
},
handleTouchEnd() {
this.canMove = false;
this.initialTouchPosition = null;
},
handleTouchMove(event) {
if (!this.canMove) {
return;
}
const positionX = event.touches[0].clientX;
const difference = this.mdVisible
? this.initialTouchPosition - positionX
: positionX - this.initialTouchPosition;
const action = this.mdVisible
? 'close'
: 'open';
if (difference > this.mdSwipeDistance) {
this[action]();
}
}
},
mounted() {
if (!this.mdSwipeable) {
return;
}
this.mountedRect = this.$refs.backdrop.$el.getBoundingClientRect();
this.initialTouchPosition = null;
this.canMove = false;
document.addEventListener('touchstart', this.handleTouchStart);
document.addEventListener('touchend', this.handleTouchEnd);
document.addEventListener('touchmove', this.handleTouchMove);
},
beforeDestroy() {
if (!this.mdSwipeable) {
return;
}
document.removeEventListener('touchstart', this.handleTouchStart);
document.removeEventListener('touchend', this.handleTouchEnd);
document.removeEventListener('touchmove', this.handleTouchMove);
}
};
</script>