【问题标题】:Adding a simple left/right swipe gesture添加一个简单的左/右滑动手势
【发布时间】:2021-10-18 22:23:04
【问题描述】:

我需要添加一个简单的左/右滑动手势,以便在移动设备上滑动时“选定”图像循环,类似于单击 hero 组件中的按钮,也类似于按左/键盘上的右箭头键

我没有最丰富的 JavaScript 经验,所以如果有人能告诉我具体要写什么以及在哪里写,以便我可以完全结束这个项目。

这是一个演示:http://nufaith.ca/justinatkins/

代码:

Vue.component('hero-bg', {
  template: `
    <div class="hero-bg">
      <div class="hero">
        <img id="pushed" :src="selected"/>
      </div>
    </div>
    `,
  props: ['selected']
});

Vue.component('hero-bg-empty', {
  template: `
    <div class="hero-bg">
      <div class="hero">
      <span style="display:block;height:100px;"></span>
      </div>
    </div>
    `
});

Vue.component('hero', {
  template: `
    <div>
      <topbar v-if="!gridEnabled"></topbar>
      <topbar2 v-if="gridEnabled"></topbar2>
      <hero-bg :selected="selectedItem.img" v-if="!gridEnabled"></hero-bg>
      <hero-bg-empty v-if="gridEnabled"></hero-bg-empty>
      <div class="hero-container" v-if="!gridEnabled">
        <div class="hero">
          <img :src="selectedItem.img" v-if="thing" alt=""/>
        </div>

        <div class="hero-desc">
          <button class="control left" @click="previous">
            <i class="zmdi zmdi-chevron-left"></i>
          </button>
          <span class="hero-desc-title" v-html="title"></span>
          <button class="control right" @click="next">
            <i class="zmdi zmdi-chevron-right"></i>
          </button>
          <br/>
          <button class="view-all-button" @click="enableGrid">OVERVIEW</button>
        </div>
      </div>
    </div>
    `,
  data() {
    return {
      gridEnabled: false,
      selected: 0,
      thing: true
    };
  },
  computed: {
    selectedItem() {
      return info[this.selected];
    },
    title() {
      const comma = this.selectedItem.title.indexOf(',');
      const len = this.selectedItem.title.length;
      const strBeginning = this.selectedItem.title.substring(comma, 0);
      const strEnd = this.selectedItem.title.substring(comma, len);
      if (this.selectedItem.title.includes(',')) {
        return `<span>${strBeginning}<span class="font-regular font-muted">${strEnd}</span></span>`;
      }
      return this.selectedItem.title;
    },
    maxImages() {
      return info.length - 1;
    }
  },
  created() {
    window.addEventListener('keydown', e => {
      if (e.keyCode === 37) {
        this.previous();
        return;
      }

      if (e.keyCode === 39) {
        this.next();
        return;
      }
    });
    Event.$on('updateImg', index => {
      this.selected = index;
      this.gridEnabled = !this.gridEnabled;
    });
  },
  methods: {
    next() {
      this.selected === this.maxImages ? (this.selected = 0) : (this.selected += 1);
    },
    previous() {
      this.selected === 0 ? (this.selected = this.maxImages) : (this.selected -= 1);
    },
    enableGrid() {
      this.gridEnabled = !this.gridEnabled;
      window.scroll(0, 0);
      Event.$emit('enableGrid');
    }
  }
});

【问题讨论】:

    标签: javascript vue.js swipe


    【解决方案1】:

    这就是我在我的一个项目中实现简单的滑动手势的方式。你可以看看这个。

    代码:

    touchableElement.addEventListener('touchstart', function (event) {
        touchstartX = event.changedTouches[0].screenX;
        touchstartY = event.changedTouches[0].screenY;
    }, false);
    
    touchableElement.addEventListener('touchend', function (event) {
        touchendX = event.changedTouches[0].screenX;
        touchendY = event.changedTouches[0].screenY;
        handleGesture();
    }, false);
    
    
    function handleGesture() {
        if (touchendX < touchstartX) {
            console.log('Swiped Left');
        }
    
        if (touchendX > touchstartX) {
            console.log('Swiped Right');
        }
    
        if (touchendY < touchstartY) {
            console.log('Swiped Up');
        }
    
        if (touchendY > touchstartY) {
            console.log('Swiped Down');
        }
    
        if (touchendY === touchstartY) {
            console.log('Tap');
        }
    }
    

    这里提到的touchableElement基本上是指将接收触摸事件的DOM Element。如果您想在整个屏幕上激活滑动选项,那么您可以使用您的body 标签作为可触摸元素。或者,您可以将任何特定的 div 元素配置为可触摸元素,以防您只想在特定的 div 上使用滑动手势。

    touchableElement 上,我们在此处添加 2 个事件侦听器:

    1. touchstart: 这是用户开始滑动的时候。我们采用初始坐标 (x,y) 和 分别存储到 touchstartX、touchstartY 中。
    2. touchend:这是用户停止滑动的时候。我们获取最终坐标 (x, y) 并将它们分别存储到 touchendX、touchendY 中。

    请记住,这些坐标的原点是屏幕的左上角。 x 坐标随着您从从左到右而增加,而 y 坐标随着您从 从上到下而增加>.

    然后,在handleGesture() 中,我们只需比较这 2 对坐标 (touchstartX, touchstartY) 和 (touchendX, touchendY),以检测不同类型的滑动手势(上、下、左、右):

    • touchendX &lt; touchstartX: 表示用户开始较高的 X 值 &停止较低的 X 值滑动。也就是说,从右向左滑动(向左滑动)。

    • touchendX &gt; touchstartX: 表示用户开始X 值较低处滑动,停止X 值较高处滑动。也就是说,从左向右滑动(向右滑动)。

    • touchendY &lt; touchstartY: 表示用户开始较高的 Y 值 & 停止较低的 Y 值滑动。也就是说,从下向上滑动(向上滑动)。

    • touchendY &gt; touchstartY: 表示用户开始较低的 Y 值 & 停止较高的 Y 值滑动。也就是说,从上向下滑动(向下滑动)。

    您可以在相应的if 块上添加这 4 个不同事件的代码(向上/向下/向左/向右滑动),如代码所示。

    【讨论】:

    • 您能否详细说明一下如何将其应用于我的代码?我不是 100% 精通 javascript,所以当我尝试时,我总是犯错误,破坏我的代码
    • 请告诉我!
    • 更新了答案。希望对您有所帮助。
    【解决方案2】:

    我接受了 smmehrab 的回答,添加了一些阈值以避免意外滑动,并将其变成了一个小库。可能会派上用场,所以这里是:

    export default class TouchEvent
    {
        static SWPIE_THRESHOLD = 50 // Minumum difference in pixels at which a swipe gesture is detected
    
        static SWIPE_LEFT   = 1
        static SWIPE_RIGHT  = 2
        static SWIPE_UP     = 3
        static SWIPE_DOWN   = 4
    
        constructor(startEvent, endEvent)
        {
            this.startEvent = startEvent
            this.endEvent = endEvent || null
        }
    
        isSwipeLeft()
        {
            return this.getSwipeDirection() == TouchEvent.SWIPE_LEFT
        }
    
        isSwipeRight()
        {
            return this.getSwipeDirection() == TouchEvent.SWIPE_RIGHT
        }
    
        isSwipeUp()
        {
            return this.getSwipeDirection() == TouchEvent.SWIPE_UP
        }
    
        isSwipeDown()
        {
            return this.getSwipeDirection() == TouchEvent.SWIPE_DOWN
        }
    
        getSwipeDirection()
        {
            let start = this.startEvent.changedTouches[0]
            let end = this.endEvent.changedTouches[0]
    
            if (!start || !end) {
                return null
            }
    
            let horizontalDifference = start.screenX - end.screenX
            let verticalDifference = start.screenY - end.screenY
    
            // Horizontal difference dominates
            if (Math.abs(horizontalDifference) > Math.abs(verticalDifference)) {
                if (horizontalDifference >= TouchEvent.SWPIE_THRESHOLD) {
                    return TouchEvent.SWIPE_LEFT
                } else if (horizontalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
                    return TouchEvent.SWIPE_RIGHT
                }
    
            // Verical or no difference dominates
            } else {
                if (verticalDifference >= TouchEvent.SWPIE_THRESHOLD) {
                    return TouchEvent.SWIPE_UP
                } else if (verticalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
                    return TouchEvent.SWIPE_DOWN
                }
            }
    
            return null
        }
    
        setEndEvent(endEvent)
        {
            this.endEvent = endEvent
        }
    }
    

    如何使用

    只需将来自touchstarttouchend 的事件提供给它:

    import TouchEvent from '@/TouchEvent'
    
    let touchEvent = null;
    
    document.addEventListener('touchstart', (event) => {
        touchEvent = new TouchEvent(event);
    });
    
    document.addEventListener('touchend', handleSwipe);
    
    function handleSwipe(event)
    {
        if (!touchEvent) {
             return;
        }
    
        touchEvent.setEndEvent(event);
    
        if (touchEvent.isSwipeRight()) {
            // Do something
        } else if (touchEvent.isSwipeLeft()) {
            // Do something different
        }
    
        // Reset event for next touch
        touchEvent = null;
    }
    

    【讨论】:

      【解决方案3】:

      这听起来像是Hammer.JS 的工作,除非你想避免依赖。他们为getting started提供了很好的文档和示例

      我的 Vue 知识几乎一无所有,所以我担心这会成为盲人主导的盲人场景,但您要做的第一件事是使用 npm 或 yarn 添加依赖项 - 然后将其添加到使用文件的顶部

      import Hammer from 'hammerjs'

      尝试在这一行的正上方添加以下代码:Event.$on('updateImg', index =&gt; {

      const swipeableEl = document.getElementsByClassName('.hero')[0];
      this.hammer = Hammer(swipeableEl)
      this.hammer.on('swipeleft', () => this.next())
      this.hammer.on('swiperight', () => this.previous())

      如果它不起作用,您必须检查您的开发者工具/控制台日志,看看它是否记录了任何有用的错误。

      这个codepen 也可能是一个有用的资源:

      祝你好运。

      【讨论】:

      • 有没有机会告诉我如何在我的代码中直接应用它?
      • 我不确定我会得到多少帮助,但已经扩展了答案。
      • 感谢兄弟的帮助!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      相关资源
      最近更新 更多