Ionic framework 在ionic 4上添加刷卡打火器

Ionic framework 在ionic 4上添加刷卡打火器,ionic-framework,ionic4,swipe,swipe-gesture,tinder,Ionic Framework,Ionic4,Swipe,Swipe Gesture,Tinder,我想问一下爱奥尼亚4的tinder swipeable卡。我找不到以下链接: “我想我已经实现了它,我希望您可以利用这段代码并提供反馈 组件模板由3部分组成: 用户选择的指示器,无论何时都可以获得可见性(不透明度) 用户将其选择拖入是/否方向 实际牌堆 用户可用于选择作为替代按钮的按钮 拖拉 模板代码+scss代码如下: //HTML: <div class="tinder" [hidden]="!cards.length"> <div class="tinder--

我想问一下爱奥尼亚4的tinder swipeable卡。我找不到以下链接:


我想我已经实现了它,我希望您可以利用这段代码并提供反馈

组件模板由3部分组成:

  • 用户选择的指示器,无论何时都可以获得可见性(不透明度) 用户将其选择拖入是/否方向

  • 实际牌堆

  • 用户可用于选择作为替代按钮的按钮
    拖拉

模板代码+scss代码如下:

//HTML:

<div class="tinder" [hidden]="!cards.length">

  <div class="tinder--status">

      <div [style.opacity]="crossVisible? '1':'0'">
          <svg width="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
              <svg:path
                  d="M405 136.798L375.202 107 256 226.202 136.798 107 107 136.798 226.202 256 107 375.202 136.798 405 256 285.798 375.202 405 405 375.202 285.798 256z"
                  fill="#CDD6DD" />
          </svg>
      </div>

      <div [style.opacity]="heartVisible? '1':'0'">
          <svg width="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
              <svg:path
                  d="M349.6 64c-36.4 0-70.7 16.7-93.6 43.9C233.1 80.7 198.8 64 162.4 64 97.9 64 48 114.2 48 179.1c0 79.5 70.7 143.3 177.8 241.7L256 448l30.2-27.2C393.3 322.4 464 258.6 464 179.1 464 114.2 414.1 64 349.6 64zm-80.8 329.3l-4.2 3.9-8.6 7.8-8.6-7.8-4.2-3.9c-50.4-46.3-94-86.3-122.7-122-28-34.7-40.4-63.1-40.4-92.2 0-22.9 8.4-43.9 23.7-59.3 15.2-15.4 36-23.8 58.6-23.8 26.1 0 52 12.2 69.1 32.5l24.5 29.1 24.5-29.1c17.1-20.4 43-32.5 69.1-32.5 22.6 0 43.4 8.4 58.7 23.8 15.3 15.4 23.7 36.5 23.7 59.3 0 29-12.5 57.5-40.4 92.2-28.8 35.7-72.3 75.7-122.8 122z"
                  fill="#FFACE4" />
          </svg>
      </div>

  </div>

  <div class="tinder--cards" (pan)="handlePan($event)" (panend)="handlePanEnd($event)">

      <div #tinderCard class="tinder--card" (transitionend)="handleShift()" *ngFor="let card of cards; let i = index"
          [ngStyle]="{ zIndex: cards.length - i, transform: 'scale(' + (20 - i) / 20 + ') translateY(-' + 20 * i + 'px)' }">

          <img #tinderCardImage [src]="card.img" (load)="tinderCardImage.style.opacity = 1">
          <h3>{{ card.title }}</h3>
          <p>{{ card.description }}</p>

      </div>

  </div>

  <div class="tinder--buttons">

    <button (click)="userClickedButton($event, false)">
        <svg width="30px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
            <svg:path
                d="M405 136.798L375.202 107 256 226.202 136.798 107 107 136.798 226.202 256 107 375.202 136.798 405 256 285.798 375.202 405 405 375.202 285.798 256z"
                fill="#CDD6DD" />
        </svg>
    </button>

    <button (click)="userClickedButton($event, true)">
        <svg width="30px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
            <svg:path
                d="M349.6 64c-36.4 0-70.7 16.7-93.6 43.9C233.1 80.7 198.8 64 162.4 64 97.9 64 48 114.2 48 179.1c0 79.5 70.7 143.3 177.8 241.7L256 448l30.2-27.2C393.3 322.4 464 258.6 464 179.1 464 114.2 414.1 64 349.6 64zm-80.8 329.3l-4.2 3.9-8.6 7.8-8.6-7.8-4.2-3.9c-50.4-46.3-94-86.3-122.7-122-28-34.7-40.4-63.1-40.4-92.2 0-22.9 8.4-43.9 23.7-59.3 15.2-15.4 36-23.8 58.6-23.8 26.1 0 52 12.2 69.1 32.5l24.5 29.1 24.5-29.1c17.1-20.4 43-32.5 69.1-32.5 22.6 0 43.4 8.4 58.7 23.8 15.3 15.4 23.7 36.5 23.7 59.3 0 29-12.5 57.5-40.4 92.2-28.8 35.7-72.3 75.7-122.8 122z"
                fill="#FFACE4" />
        </svg>
    </button>

  </div>

</div>
一些注意事项:

  • 该模板具有*ngFor功能,可复制每张卡和位置 它在堆栈中
  • 我们利用hammer.js的平移和平移结束手势事件来处理拖动
  • 我们正在监听转换结束事件,以便从堆栈中实际移除卡
//TS:

import { Component, Input, ViewChildren, QueryList, ElementRef, EventEmitter, Output, Renderer2 } from '@angular/core';

@Component({
  selector: 'tinder-ui',
  templateUrl: 'tinder-ui.component.html',
  styleUrls: ['tinder-ui.component.scss'],
})
export class TinderUIComponent {

  @Input('cards') cards: Array<{
    img: string,
    title: string,
    description: string
  }>;

  @ViewChildren('tinderCard') tinderCards: QueryList<ElementRef>;
  tinderCardsArray: Array<ElementRef>;

  @Output() choiceMade = new EventEmitter();

  moveOutWidth: number;
  shiftRequired: boolean;
  transitionInProgress: boolean;
  heartVisible: boolean;
  crossVisible: boolean;

  constructor(private renderer: Renderer2) { 
  }

  userClickedButton(event, heart) {
    event.preventDefault();
    if (!this.cards.length) return false;
    if (heart) {
      this.tinderCardsArray[0].nativeElement.style.transform = 'translate(' + this.moveOutWidth + 'px, -100px) rotate(-30deg)';
      this.toggleChoiceIndicator(false,true);
      this.emitChoice(heart, this.cards[0]);
    } else {
      this.tinderCardsArray[0].nativeElement.style.transform = 'translate(-' + this.moveOutWidth + 'px, -100px) rotate(30deg)';
      this.toggleChoiceIndicator(true,false);
      this.emitChoice(heart, this.cards[0]);
    };
    this.shiftRequired = true;
    this.transitionInProgress = true;
  };

  handlePan(event) {

    if (event.deltaX === 0 || (event.center.x === 0 && event.center.y === 0) || !this.cards.length) return;

    if (this.transitionInProgress) {
      this.handleShift();
    }

    this.renderer.addClass(this.tinderCardsArray[0].nativeElement, 'moving');

    if (event.deltaX > 0) { this.toggleChoiceIndicator(false,true) }
    if (event.deltaX < 0) { this.toggleChoiceIndicator(true,false) }

    let xMulti = event.deltaX * 0.03;
    let yMulti = event.deltaY / 80;
    let rotate = xMulti * yMulti;

    this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', 'translate(' + event.deltaX + 'px, ' + event.deltaY + 'px) rotate(' + rotate + 'deg)');

    this.shiftRequired = true;

  };

  handlePanEnd(event) {

    this.toggleChoiceIndicator(false,false);

    if (!this.cards.length) return;

    this.renderer.removeClass(this.tinderCardsArray[0].nativeElement, 'moving');

    let keep = Math.abs(event.deltaX) < 80 || Math.abs(event.velocityX) < 0.5;
    if (keep) {

      this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', '');
      this.shiftRequired = false;

    } else {

      let endX = Math.max(Math.abs(event.velocityX) * this.moveOutWidth, this.moveOutWidth);
      let toX = event.deltaX > 0 ? endX : -endX;
      let endY = Math.abs(event.velocityY) * this.moveOutWidth;
      let toY = event.deltaY > 0 ? endY : -endY;
      let xMulti = event.deltaX * 0.03;
      let yMulti = event.deltaY / 80;
      let rotate = xMulti * yMulti;

      this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', 'translate(' + toX + 'px, ' + (toY + event.deltaY) + 'px) rotate(' + rotate + 'deg)');

      this.shiftRequired = true;

      this.emitChoice(!!(event.deltaX > 0), this.cards[0]);
    }
    this.transitionInProgress = true;
  };

  toggleChoiceIndicator(cross, heart) {
    this.crossVisible = cross;
    this.heartVisible = heart;
  };

  handleShift() {
    this.transitionInProgress = false;
    this.toggleChoiceIndicator(false,false)
    if (this.shiftRequired) {
      this.shiftRequired = false;
      this.cards.shift();
    };
  };

  emitChoice(heart, card) {
    this.choiceMade.emit({
      choice: heart,
      payload: card
    })
  };

  ngAfterViewInit() {
    this.moveOutWidth = document.documentElement.clientWidth * 1.5;
    this.tinderCardsArray = this.tinderCards.toArray();
    this.tinderCards.changes.subscribe(()=>{
      this.tinderCardsArray = this.tinderCards.toArray();
    })
  };

}
import{Component,Input,ViewChildren,QueryList,ElementRef,EventEmitter,Output,Renderer2}来自'@angular/core';
@组成部分({
选择器:“tinder ui”,
templateUrl:'tinder ui.component.html',
样式URL:['tinder-ui.component.scss'],
})
导出类TinderUIComponent{
@输入(“卡片”)卡片:数组;
@ViewChildren('tinderCard')tinderCards:QueryList;
tinderCardsArray:数组;
@Output()choiceMade=neweventemitter();
moveOutWidth:数字;
移位要求:布尔值;
transitionInProgress:布尔值;
heartVisible:布尔值;
交叉可见:布尔;
构造函数(专用渲染器:渲染器2){
}
用户点击按钮(事件,心脏){
event.preventDefault();
如果(!this.cards.length)返回false;
如果(心){
this.tinderCardsArray[0].nativeElement.style.transform='translate('+this.moveOutWidth+'px,-100px)rotate(-30度)';
this.toggleChoiceIndicator(false,true);
this.emitChoice(heart,this.cards[0]);
}否则{
this.tinderCardsArray[0].nativeElement.style.transform='translate(-this.moveOutWidth+'px,-100px)rotate(30度)';
this.toggleChoiceIndicator(真、假);
this.emitChoice(heart,this.cards[0]);
};
this.shiftRequired=true;
this.transitionInProgress=true;
};
手板(活动){
如果(event.deltaX==0 | | |(event.center.x==0&&event.center.y==0)| |!this.cards.length)返回;
如果(此.转换进程){
此为.handleShift();
}
this.renderer.addClass(this.tinderCardsArray[0].nativeElement,“moving”);
如果(event.deltaX>0){this.toggleChoiceIndicator(false,true)}
if(event.deltaX<0){this.toggleChoiceIndicator(true,false)}
设xMulti=event.deltaX*0.03;
设yMulti=event.deltaY/80;
让旋转=xMulti*yMulti;
this.renderer.setStyle(this.tinderCardsArray[0].nativeElement,'transform','translate('+event.deltaX+'px',+event.deltaY+'px)rotate('+rotate+'deg');
this.shiftRequired=true;
};
handlePanEnd(事件){
this.toggleChoiceIndicator(false,false);
如果(!this.cards.length)返回;
this.renderer.removeClass(this.tinderCardsArray[0].nativeElement,'moving');
让keep=Math.abs(event.deltaX)<80 | | Math.abs(event.velocityX)<0.5;
如果(保留){
this.renderer.setStyle(this.tinderCardsArray[0].nativeElement,'transform','';
this.shiftRequired=false;
}否则{
设endX=Math.max(Math.abs(event.velocityX)*this.moveOutWidth,this.moveOutWidth);
设toX=event.deltaX>0?endX:-endX;
设endY=Math.abs(event.velocityY)*this.moveOutWidth;
让toY=event.deltaY>0?endY:-endY;
设xMulti=event.deltaX*0.03;
设yMulti=event.deltaY/80;
让旋转=xMulti*yMulti;
this.renderer.setStyle(this.tinderCardsArray[0].nativeElement,'transform','translate('+toX++'px',+(toY+event.deltaY)+'px)rotate('+rotate++'deg');
this.shiftRequired=true;
this.emitChoice(!!(event.deltaX>0),this.cards[0]);
}
this.transitionInProgress=true;
};
切换选择指示器(十字、心形){
this.crossVisible=cross;
this.heartVisible=心脏;
};
handleShift(){
this.transitionInProgress=false;
this.toggleChoiceIndicator(false,false)
如果(需要此移位){
this.shiftRequired=false;
这个.cards.shift();
};
};
选择(心、卡){
这个.choiceMade.emit({
选择:心,
有效载荷:卡
})
};
ngAfterViewInit(){
this.moveOutWidth=document.documentElement.clientWidth*1.5;
this.tinderCardsArray=this.tinderCards.toArray();
这个.tinderCards.changes.subscribe(()=>{
this.tinderCardsArray=this.tinderCards.toArray();
})
};
}
注:关于ts部分:

  • @输入用于获取卡片列表
  • 我们利用@Output发出用户的选择
  • 我们使用@ViewChildren来跟踪卡片堆栈
  • 转换完成时(转换结束事件),卡才被实际移除(array.shift())
  • 组件本身是隐藏的,以防它在堆栈中没有卡,其思想是我们从页面组件中显示该组件,例如通过引用可以包含卡的数组
希望这是如何实现此类组件的一个好例子

编辑器URL:

演示:


文章:

现在是老文章了,但我认为你可以从这篇文章开始——谢谢,但它不在ionic4上。虽然这个链接可以回答这个问题,但最好在这里包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,仅链接的答案可能无效。-知道了。是的,我会在这里添加代码和解释-谢谢你feedback@NicoHaase你能帮我检查一下我的附加组件,看看这是否更有帮助吗?非常感谢,我正在寻找一种添加自动装载推车的方法。你能提出一个新问题吗?会是
import { Component, Input, ViewChildren, QueryList, ElementRef, EventEmitter, Output, Renderer2 } from '@angular/core';

@Component({
  selector: 'tinder-ui',
  templateUrl: 'tinder-ui.component.html',
  styleUrls: ['tinder-ui.component.scss'],
})
export class TinderUIComponent {

  @Input('cards') cards: Array<{
    img: string,
    title: string,
    description: string
  }>;

  @ViewChildren('tinderCard') tinderCards: QueryList<ElementRef>;
  tinderCardsArray: Array<ElementRef>;

  @Output() choiceMade = new EventEmitter();

  moveOutWidth: number;
  shiftRequired: boolean;
  transitionInProgress: boolean;
  heartVisible: boolean;
  crossVisible: boolean;

  constructor(private renderer: Renderer2) { 
  }

  userClickedButton(event, heart) {
    event.preventDefault();
    if (!this.cards.length) return false;
    if (heart) {
      this.tinderCardsArray[0].nativeElement.style.transform = 'translate(' + this.moveOutWidth + 'px, -100px) rotate(-30deg)';
      this.toggleChoiceIndicator(false,true);
      this.emitChoice(heart, this.cards[0]);
    } else {
      this.tinderCardsArray[0].nativeElement.style.transform = 'translate(-' + this.moveOutWidth + 'px, -100px) rotate(30deg)';
      this.toggleChoiceIndicator(true,false);
      this.emitChoice(heart, this.cards[0]);
    };
    this.shiftRequired = true;
    this.transitionInProgress = true;
  };

  handlePan(event) {

    if (event.deltaX === 0 || (event.center.x === 0 && event.center.y === 0) || !this.cards.length) return;

    if (this.transitionInProgress) {
      this.handleShift();
    }

    this.renderer.addClass(this.tinderCardsArray[0].nativeElement, 'moving');

    if (event.deltaX > 0) { this.toggleChoiceIndicator(false,true) }
    if (event.deltaX < 0) { this.toggleChoiceIndicator(true,false) }

    let xMulti = event.deltaX * 0.03;
    let yMulti = event.deltaY / 80;
    let rotate = xMulti * yMulti;

    this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', 'translate(' + event.deltaX + 'px, ' + event.deltaY + 'px) rotate(' + rotate + 'deg)');

    this.shiftRequired = true;

  };

  handlePanEnd(event) {

    this.toggleChoiceIndicator(false,false);

    if (!this.cards.length) return;

    this.renderer.removeClass(this.tinderCardsArray[0].nativeElement, 'moving');

    let keep = Math.abs(event.deltaX) < 80 || Math.abs(event.velocityX) < 0.5;
    if (keep) {

      this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', '');
      this.shiftRequired = false;

    } else {

      let endX = Math.max(Math.abs(event.velocityX) * this.moveOutWidth, this.moveOutWidth);
      let toX = event.deltaX > 0 ? endX : -endX;
      let endY = Math.abs(event.velocityY) * this.moveOutWidth;
      let toY = event.deltaY > 0 ? endY : -endY;
      let xMulti = event.deltaX * 0.03;
      let yMulti = event.deltaY / 80;
      let rotate = xMulti * yMulti;

      this.renderer.setStyle(this.tinderCardsArray[0].nativeElement, 'transform', 'translate(' + toX + 'px, ' + (toY + event.deltaY) + 'px) rotate(' + rotate + 'deg)');

      this.shiftRequired = true;

      this.emitChoice(!!(event.deltaX > 0), this.cards[0]);
    }
    this.transitionInProgress = true;
  };

  toggleChoiceIndicator(cross, heart) {
    this.crossVisible = cross;
    this.heartVisible = heart;
  };

  handleShift() {
    this.transitionInProgress = false;
    this.toggleChoiceIndicator(false,false)
    if (this.shiftRequired) {
      this.shiftRequired = false;
      this.cards.shift();
    };
  };

  emitChoice(heart, card) {
    this.choiceMade.emit({
      choice: heart,
      payload: card
    })
  };

  ngAfterViewInit() {
    this.moveOutWidth = document.documentElement.clientWidth * 1.5;
    this.tinderCardsArray = this.tinderCards.toArray();
    this.tinderCards.changes.subscribe(()=>{
      this.tinderCardsArray = this.tinderCards.toArray();
    })
  };

}