Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 指针事件API和拖动_Javascript_Vue.js_Google Chrome_Drag_Touch Event - Fatal编程技术网

Javascript 指针事件API和拖动

Javascript 指针事件API和拖动,javascript,vue.js,google-chrome,drag,touch-event,Javascript,Vue.js,Google Chrome,Drag,Touch Event,我正在尝试使用实现仅限移动的触摸UI,但这不起作用: 目标是允许在同一UI中滚动卡片并在展开和折叠状态之间拖动卡片。在Chrome emulator和iOS Safari中,我只能通过拖动手柄来工作。通过卡片内容拖动在任何地方都不起作用 在Android上,拖动Chrome根本不起作用 最奇怪的是,使用touchstart、touchmove和touchmendevents(),同一个用户界面无处不在,但在Android上的Chrome上,在滚动条的存在下,touchmove的性能是如此糟糕,

我正在尝试使用实现仅限移动的触摸UI,但这不起作用:

目标是允许在同一UI中滚动卡片并在展开和折叠状态之间拖动卡片。在Chrome emulator和iOS Safari中,我只能通过拖动手柄来工作。通过卡片内容拖动在任何地方都不起作用

在Android上,拖动Chrome根本不起作用

最奇怪的是,使用
touchstart
touchmove
touchmend
events(),同一个用户界面无处不在,但在Android上的Chrome上,在滚动条的存在下,
touchmove
的性能是如此糟糕,以至于我试图用指针事件来重新实现它

Vue组件代码:

<template>
  <div class="container">
    <div
      :class="containerClass"
      :style="containerStyle"
      @pointerdown="pointerDownHandler"
      @pointermove="pointerMoveHandler"
      @pointerup="pointerUpHandler"
      @pointerover="reportEvent"
      @pointerenter="reportEvent"
      @pointercancel="reportEvent"
      @pointerout="reportEvent"
      @pointerleave="reportEvent"
      @gotpointercapture="reportEvent"
      @lostpointercapture="reportEvent"
      @transitionend="transitionEndHandler"
      class="card"
    >
      <svg viewBox="0 0 100 20" always-swipeable="true" class="drag-handle">
        <polyline points="27,10 73,10" stroke-linecap="round"></polyline>
      </svg>
      <div class="scrollbox" ref="scrollbox">
        <div :key="item" class="item" v-for="item in items">
          {{ item }}
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      deltaY: 0,
      isDraggingByHandle: false,
      isTransitioning: false,
      items: [
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11,
        12,
        13,
        14,
        15,
        16,
        17,
        18,
        19,
        20,
      ],
      offsetHeight: 0,
      scrollboxHeight: 0,
      scrollTop: 0,
      touchAction: null,
      verticalStates: [
        {
          translateY: 0,
        },
        {
          translateY: window.innerHeight - 200,
        },
      ],
      verticalStateIndex: 0,
    };
  },

  computed: {
    activeVerticalState() {
      return this.verticalStates[this.verticalStateIndex];
    },
    containerClass() {
      return {
        "show-scrollbar": this.isScrollable,
        transition: this.isTransitioning,
      };
    },
    containerStyle() {
      return {
        transform: `translateY(${this.translateY}px)`,
      };
    },
    isAnySwipeAllowed() {
      return this.isDraggingByHandle || !this.isScrollable;
    },
    isExpanded() {
      return this.verticalStateIndex === 0;
    },
    isScrollable() {
      return this.isExpanded && this.scrollHeight > this.offsetHeight;
    },
    isSwipeDown() {
      return (
        this.deltaY > 0 && (this.isAnySwipeAllowed || this.scrollTop === 0)
      );
    },
    isSwipeUp() {
      return (
        this.deltaY < 0 &&
        (this.isAnySwipeAllowed ||
          this.offsetHeight + this.scrollTop === this.scrollHeight)
      );
    },
    scrollbox() {
      return this.$refs.scrollbox;
    },
    translateY() {
      let translateY = this.activeVerticalState.translateY;
      if (
        this.touchAction === "verticalSwipe" &&
        (this.isSwipeDown || this.isSwipeUp)
      ) {
        translateY = translateY + this.deltaY;
      }
      return translateY;
    },
  },

  mounted() {
    this.updateScrollboxData();
  },

  methods: {
    pointerDownHandler: function ({ clientY, target, pointerId }) {
      console.log("pointerdown", target, pointerId);
      target.setPointerCapture(pointerId);
      this.updateScrollboxData();
      this.isDraggingByHandle = Boolean(
        target.getAttribute("always-swipeable")
      );
      this.touchStartClientY = clientY;
      this.touchAction = "tap";
    },
    pointerMoveHandler: function ({ clientY, target, pointerId }) {
      console.log("pointermove", target, pointerId, this.deltaY);
      this.deltaY = clientY - this.touchStartClientY;
      // promote touchAction to swipe or scroll depending on deltas and other variables
      if (this.touchAction === "tap") {
        if (this.isSwipeDown || this.isSwipeUp) {
          this.touchAction = "verticalSwipe";
        } else {
          this.touchAction = "scroll";
          this.updateScrollboxData();
        }
      }
    },
    pointerUpHandler: function ({ target, pointerId }) {
      console.log("pointerup", target, pointerId);
      target.releasePointerCapture(pointerId);
      switch (this.touchAction) {
        case "tap":
          if (!this.isExpanded) {
            this.verticalStateIndex = Math.max(this.verticalStateIndex - 1, 0);
            this.isTransitioning = true;
          }
          break;
        case "verticalSwipe":
          if (this.isSwipeDown) {
            this.verticalStateIndex = Math.min(
              this.verticalStateIndex + 1,
              this.verticalStates.length - 1
            );
          } else if (this.isSwipeUp) {
            this.verticalStateIndex = Math.max(this.verticalStateIndex - 1, 0);
          }
          this.isTransitioning = true;
          this.deltaY = 0;
          break;
      }
    },
    reportEvent({ type, target, pointerId }) {
      console.log(type, target, pointerId);
    },
    transitionEndHandler() {
      this.touchAction = null;
      this.isTransitioning = false;
      this.updateScrollboxData();
    },
    updateScrollboxData() {
      const { scrollHeight, offsetHeight, scrollTop } = this.scrollbox;
      this.offsetHeight = offsetHeight;
      this.scrollHeight = scrollHeight;
      this.scrollTop = scrollTop;
    },
  },
};
</script>

<style lang="scss" scoped>
.container {
  display: flex;
  justify-content: center;
  margin-top: 5vh;
  overflow: hidden;
  touch-action: none;

  .card {
    pointer-events: all;
    width: 90vw;
    height: 100%;
    touch-action: none;

    &.transition {
      transition: transform 0.15s ease-out;
    }

    .drag-handle {
      stroke-width: 5px;
      stroke: #bfbfc0;
      width: 100%;
      height: 30px;
      background: pink;
    }

    .scrollbox {
      overflow-y: hidden;
      pointer-events: none;
      background: green;
      height: 85vh;

      .item {
        margin-bottom: 20px;
        height: 150px;
        font-size: 36px;
        background: yellow;
      }
    }

    &.show-scrollbar .scrollbox {
      overflow-y: scroll;
      pointer-events: all;
    }
  }
}
</style>

{{item}}
导出默认值{
数据(){
返回{
德尔泰:0,
IsDragingByHandle:false,
isTransitioning:false,
项目:[
1.
2.
3.
4.
5.
6.
7.
8.
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
],
离地:0,
scrollboxHeight:0,
滚动顶端:0,
touchAction:null,
垂直状态:[
{
translateY:0,
},
{
translateY:window.innerHeight-200,
},
],
垂直状态索引:0,
};
},
计算:{
activeVerticalState(){
返回this.verticalStates[this.verticalStateIndex];
},
集装箱类(){
返回{
“显示滚动条”:this.iscrowllable,
转变:这是转变,
};
},
集装箱运输方式(){
返回{
transform:`translateY(${this.translateY}px)`,
};
},
IsAnysis(允许){
返回此.isDragingByHandle | | |!此.isCrollable;
},
isExpanded(){
返回此值。verticalStateIndex==0;
},
可转换的{
返回this.isExpanded&&this.scrollHeight>this.offsetHeight;
},
IsSweepDown(){
返回(
this.deltaY>0&(this.isAnySwipeAllowed | | this.scrollTop==0)
);
},
Isswipup(){
返回(
这是德尔泰<0&&
(这是允许的||
this.offsetHeight+this.scrollTop==this.scrollHeight)
);
},
滚动框(){
返回此。$refs.scrollbox;
},
translateY(){
让translateY=this.activeVerticalState.translateY;
如果(
this.touchAction==“垂直滑动”&&
(this.isSwipeDown | this.isSwipeUp)
) {
translateY=translateY+this.deltaY;
}
返回translateY;
},
},
安装的(){
this.updateScrollboxData();
},
方法:{
pointerDownHandler:函数({clientY,target,pointerId}){
log(“pointerdown”、target、pointerId);
target.setPointerCapture(指针ID);
this.updateScrollboxData();
this.isDragingByHandle=布尔值(
target.getAttribute(“始终可切换”)
);
this.touchStartClientY=clientY;
this.touchAction=“点击”;
},
pointerMoveHandler:函数({clientY,target,pointerId}){
log(“pointermove”,target,pointerId,this.deltaY);
this.deltaY=clientY-this.touchStartClientY;
//根据增量和其他变量,将touchAction升级为滑动或滚动
如果(this.touchAction==“点击”){
如果(this.isSwipeDown | this.isSwipeUp){
this.touchAction=“垂直滑动”;
}否则{
this.touchAction=“滚动”;
this.updateScrollboxData();
}
}
},
pointerUpHandler:函数({target,pointerId}){
log(“pointerup”、target、pointerId);
target.releasePointerCapture(指针ID);
开关(此.touchAction){
案例“tap”:
如果(!this.isExpanded){
this.verticalStateIndex=Math.max(this.verticalStateIndex-1,0);
this.isTransitioning=true;
}
打破
案例“垂直滑动”:
如果(此.isSwipeDown){
this.verticalStateIndex=Math.min(
此.verticalStateIndex+1,
此.verticalStates.length-1
);
}否则,如果(此.isswipup){
this.verticalStateIndex=Math.max(this.verticalStateIndex-1,0);
}
this.isTransitioning=true;
此值为0.deltaY=0;
打破
}
},
reportEvent({type,target,pointerId}){
日志(类型、目标、指针ID);
},
transitionEndHandler(){
this.touchAction=null;
this.isTransitioning=false;
this.updateScrollboxData();
},
updateScrollboxData(){
const{scrollHeight,offsetHeight,scrollTop}=this.scrollbox;
this.offsetHeight=offsetHeight;
this.scrollHeight=滚动高度;
this.scrollTop=scrollTop;
},
},
};
.集装箱{
显示器:flex;
证明内容:中心;
边缘顶部:5vh;
溢出:隐藏;
触摸动作:无;
.卡片{
指针事件:全部;
宽度:90vw;
身高:100%;
触摸动作:无;
&.过渡{
转换:转换0.15秒缓解;
}
.拖动手柄{
笔画宽度:5px;
行程:#bfc0;
宽度:100%;
高度:30px;
背景:粉红色;
}
.滚动框{
溢出y:隐藏;
指针事件:无;
背景:绿色;
高度:85vh;
.项目{
边缘底部:20px;
高度:150像素;
字体大小:36px;
背景:黄色;
}
}
&.显示滚动条.滚动框{
溢出y:滚动;
指针事件:全部;
}
}
}
Minimal示例,请输入Minimal。即使我没有检查这堵代码墙,为什么指针事件而不是简单的触摸事件呢?@kaido