在 Angular 2 中实现滑动导航的最佳方式是什么?
What is the best way to implement swipe navigation in Angular 2?
我是 Angular 2 的新手,我正在寻找一种方法来为移动用户实现良好的标签触摸滑动导航,并通过滑动过渡到下一个标签视图。
到目前为止,我找到了一个名为 angular2-useful-swiper 的包,但我并不热衷于使用它,因为我最终会提前初始化我的组件,即使它们不在视图中。
有人知道为 Angular 2 实现基于标签滑动的导航的好方法吗?任何反馈将不胜感激。 :)
你可以使用HammerJS
来实现触摸动作,你可以按照这个plunker来举例。
包含hammer.js文件
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
或
npm install hammerjs --save
对于 hammerjs 的浏览器触摸支持,包括
<script src="http://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script>
<script>
导入 app.module.ts
import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
export class MyHammerConfig extends HammerGestureConfig {
overrides = <any>{
'swipe': {velocity: 0.4, threshold: 20} // override default settings
}
}
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [{
provide: HAMMER_GESTURE_CONFIG,
useClass: MyHammerConfig
}] // use our custom hammerjs config
})
要实现制表符 angular2-material
是一个很好的起点,请遵循 this link
对于滑动检测,这里是比添加 HammerJS 更简单的解决方案:
在app.component.html中:
<div (touchstart)="swipe($event, 'start')" (touchend)="swipe($event, 'end')">
App content here
</div>
在app.component.ts中:
private swipeCoord?: [number, number];
private swipeTime?: number;
swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
this.swipeCoord = coord;
this.swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipe = direction[0] < 0 ? 'next' : 'previous';
// Do whatever you want with swipe
}
}
}
注意:我尝试了 HammerJS 解决方案,但无法将其配置为忽略鼠标手势,因为您无法直接访问 Hammer 对象。所以选择一些文本会强制导航到下一页...
首先安装 hammerjs 和 action touch-action polyfill:
$ npm install hammerjs hammer-timejs
然后将导入添加到 'app.module.ts' 所以它们将是 used/bundled:
import 'hammerjs';
import 'hammer-timejs';
现在您可以处理以下操作的事件:
旋转
捏
按
潘
点击
滑动
例如你可以说:
<li *ngFor="let employee of employeesList;" (swiperight)="myswiperight(employee)" (swipeleft)="myswipeleft(employee)">
或者:
<div (panstart)="onPanStart($event)" (panmove)="onPan($event)">
我想出了一个 write-once-use-everywhere 类型的函数,我把它放在一个名为“gestures”的目录中,然后创建了一个名为“swipe.ts”的文件并将其放入其中。
let swipeCoord = [0, 0];
let swipeTime = new Date().getTime();
export function swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
swipeCoord = coord;
swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - swipeCoord[0], coord[1] - swipeCoord[1]];
const duration = time - swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipeDir = direction[0] < 0 ? 'next' : 'previous';
if (swipeDir === 'next') {
alert('swipe next');
} else {
alert('swipe prev');
}
}
}
}
然后导入到需要的组件中,像这样:
import {swipe} from '../../gestures/swipe';
并创建一个名为:
的函数
onSwipe(e: TouchEvent, when: string) {
swipe(e, when);
}
在所需组件的 HTML 中,使用以下内容:
<div (touchstart)="onSwipe($event, 'start')"
(touchend)="onSwipe($event, 'end')">
<!-- whatever content you have goes here -->
</div>
PS - 感谢@pikiou。我只是想到了更高层次的抽象,这对我来说更有意义。
我根据@Elvis Metodiev 的回答和@pikiou 创建了一个指令:
swipe.directive.ts
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({ selector: '[swipe]' })
export class SwipeDirective {
@Output() next = new EventEmitter<void>();
@Output() previous = new EventEmitter<void>();
swipeCoord = [0, 0];
swipeTime = new Date().getTime();
constructor() { }
@HostListener('touchstart', ['$event']) onSwipeStart($event) {
this.onSwipe($event, 'start');
}
@HostListener('touchend', ['$event']) onSwipeEnd($event) {
this.onSwipe($event, 'end');
}
onSwipe(e: TouchEvent, when: string) {
this.swipe(e, when);
}
swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
this.swipeCoord = coord;
this.swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipeDir = direction[0] < 0 ? 'next' : 'previous';
if (swipeDir === 'next') {
this.next.emit();
} else {
this.previous.emit();
}
}
}
}
}
tour.component.component.ts
<div
...
swipe
(next)="onRotateNext()"
(previous)="onRotatePrevious()"
>
...
</div>
我是 Angular 2 的新手,我正在寻找一种方法来为移动用户实现良好的标签触摸滑动导航,并通过滑动过渡到下一个标签视图。
到目前为止,我找到了一个名为 angular2-useful-swiper 的包,但我并不热衷于使用它,因为我最终会提前初始化我的组件,即使它们不在视图中。
有人知道为 Angular 2 实现基于标签滑动的导航的好方法吗?任何反馈将不胜感激。 :)
你可以使用HammerJS
来实现触摸动作,你可以按照这个plunker来举例。
包含hammer.js文件
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
或
npm install hammerjs --save
对于 hammerjs 的浏览器触摸支持,包括
<script src="http://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script>
<script>
导入 app.module.ts
import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
export class MyHammerConfig extends HammerGestureConfig {
overrides = <any>{
'swipe': {velocity: 0.4, threshold: 20} // override default settings
}
}
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [{
provide: HAMMER_GESTURE_CONFIG,
useClass: MyHammerConfig
}] // use our custom hammerjs config
})
要实现制表符 angular2-material
是一个很好的起点,请遵循 this link
对于滑动检测,这里是比添加 HammerJS 更简单的解决方案:
在app.component.html中:
<div (touchstart)="swipe($event, 'start')" (touchend)="swipe($event, 'end')">
App content here
</div>
在app.component.ts中:
private swipeCoord?: [number, number];
private swipeTime?: number;
swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
this.swipeCoord = coord;
this.swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipe = direction[0] < 0 ? 'next' : 'previous';
// Do whatever you want with swipe
}
}
}
注意:我尝试了 HammerJS 解决方案,但无法将其配置为忽略鼠标手势,因为您无法直接访问 Hammer 对象。所以选择一些文本会强制导航到下一页...
首先安装 hammerjs 和 action touch-action polyfill:
$ npm install hammerjs hammer-timejs
然后将导入添加到 'app.module.ts' 所以它们将是 used/bundled:
import 'hammerjs';
import 'hammer-timejs';
现在您可以处理以下操作的事件:
旋转
捏
按
潘
点击
滑动
例如你可以说:
<li *ngFor="let employee of employeesList;" (swiperight)="myswiperight(employee)" (swipeleft)="myswipeleft(employee)">
或者:
<div (panstart)="onPanStart($event)" (panmove)="onPan($event)">
我想出了一个 write-once-use-everywhere 类型的函数,我把它放在一个名为“gestures”的目录中,然后创建了一个名为“swipe.ts”的文件并将其放入其中。
let swipeCoord = [0, 0];
let swipeTime = new Date().getTime();
export function swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
swipeCoord = coord;
swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - swipeCoord[0], coord[1] - swipeCoord[1]];
const duration = time - swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipeDir = direction[0] < 0 ? 'next' : 'previous';
if (swipeDir === 'next') {
alert('swipe next');
} else {
alert('swipe prev');
}
}
}
}
然后导入到需要的组件中,像这样:
import {swipe} from '../../gestures/swipe';
并创建一个名为:
的函数onSwipe(e: TouchEvent, when: string) {
swipe(e, when);
}
在所需组件的 HTML 中,使用以下内容:
<div (touchstart)="onSwipe($event, 'start')"
(touchend)="onSwipe($event, 'end')">
<!-- whatever content you have goes here -->
</div>
PS - 感谢@pikiou。我只是想到了更高层次的抽象,这对我来说更有意义。
我根据@Elvis Metodiev 的回答和@pikiou 创建了一个指令:
swipe.directive.ts
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({ selector: '[swipe]' })
export class SwipeDirective {
@Output() next = new EventEmitter<void>();
@Output() previous = new EventEmitter<void>();
swipeCoord = [0, 0];
swipeTime = new Date().getTime();
constructor() { }
@HostListener('touchstart', ['$event']) onSwipeStart($event) {
this.onSwipe($event, 'start');
}
@HostListener('touchend', ['$event']) onSwipeEnd($event) {
this.onSwipe($event, 'end');
}
onSwipe(e: TouchEvent, when: string) {
this.swipe(e, when);
}
swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
const time = new Date().getTime();
if (when === 'start') {
this.swipeCoord = coord;
this.swipeTime = time;
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
const duration = time - this.swipeTime;
if (duration < 1000 //
&& Math.abs(direction[0]) > 30 // Long enough
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
const swipeDir = direction[0] < 0 ? 'next' : 'previous';
if (swipeDir === 'next') {
this.next.emit();
} else {
this.previous.emit();
}
}
}
}
}
tour.component.component.ts
<div
...
swipe
(next)="onRotateNext()"
(previous)="onRotatePrevious()"
>
...
</div>