vue實現 移動端touch--點擊、雙指與拖拽指令

前言

用vue作移動端開發過程當中,須要手勢操做。由於vue-touch目前不支持vue2.0,因此本身寫了幾個手勢。html

實現功能

  • 點擊
  • 雙指縮放圖片
  • 移動

指令代碼

myTouch.js >>
export default(Vue) => {
    Vue.directive('touch', {
        bind: function (el, binding, vnode) {
            let type = binding.arg; // 傳入點擊的類型
            let coordinate = {} // 記錄座標點的對象
            let timeOutTap;
            let timeOutLong;
            let scaleSize; // 縮放尺寸
            let displacement = {}; //移動的位移
            // 勾股定理計算距離
            function getDistance(bg, end){
                return Math.sqrt(Math.pow((end.x - bg.x),2 ) + Math.pow((end.y - bg.y),2 ));
            }
            // 點擊開始的時候
            el.addEventListener('touchstart', function(e){
                // 獲取第一個手指點擊的座標
                let x = e.touches[0].pageX;
                let y = e.touches[0].pageY; 
                // 若是點擊的時間很長,那麼點擊的類型就是長按 --- longTouch
                timeOutLong = setTimeout(() => {
                    timeOutLong = 0;
                    if(type === 'longTouch'){
                         binding.value.func(binding.value.param)
                    }
                }, 2000)
                timeOutTap = setTimeout(() => {
                    timeOutTap = 0;
                    if(type === 'tap' && e.touches.length === 1){
                         binding.value.func(binding.value.param)
                    }
                }, 200)
                // 若是是兩個手指,並且類型是縮放 --- scaleTocuh
                if(e.touches.length > 1 && type === 'scaleTouch'){
                    // 記錄雙指的間距長度
                    coordinate.start =  getDistance({
                        x: e.touches[0].pageX, 
                        y: e.touches[0].pageY,
                    },{
                        x: e.touches[1].pageX, 
                        y: e.touches[1].pageY,
                    })

                }
                // 若是是移動的話,還要記錄下來最開始的位置,只能一個手指位移
                if(type === 'slideTouch' && e.touches.length == 1){
                    // debugger
                    displacement.start = {
                        x: e.touches[0].pageX,
                        y: e.touches[0].pageY,
                    }
                }
            }, false)
            el.addEventListener('touchmove', function(e){
                clearTimeout(timeOutTap)
                clearTimeout(timeOutLong)
                timeOutTap = 0; timeOutLong = 0;
                // 若是是縮放類型
                if(type == 'scaleTouch' && e.touches.length === 2){
                    // 計算移動過程當中的兩個手指的距離
                    coordinate.stop = getDistance({
                        x: e.touches[0].pageX, 
                        y: e.touches[0].pageY,
                    },{
                        x: e.touches[1].pageX, 
                        y: e.touches[1].pageY,
                    })
                    // 設置縮放尺寸
                    scaleSize = (coordinate.stop / coordinate.start)  - 1;
                    // 這裏設置圖片不能無限放大與縮小
                    // 這裏設置放大縮小速度慢一點,因此 /4一下
                    binding.value.func(scaleSize / 2, false)
                }
                // 若是是移動類型
                if(type == 'slideTouch' && e.touches.length === 1 ){
                    displacement.end = {
                        x: e.changedTouches[0].pageX,
                        y: e.changedTouches[0].pageY,
                    }
                    binding.value.func({x:displacement.end.x - displacement.start.x, y: displacement.end.y - displacement.start.y, is_endMove : false})
                }
            }, false)
            el.addEventListener('touchend', function(e){
                if(type === 'scaleTouch'){
                    binding.value.func(0, true)
                }
                if(type === 'slideTouch'){
                    binding.value.func({x:0, y: 0, is_endMove : true})
                }
            }, false)
        }
    })
}

使用方法

html:
 <img :src="picUrl" class="modal_content"
            v-touch:scaleTouch = "{func: scalePic, param: ''}"
            v-touch:slideTouch = "{func: movePic, param: ''}"
/>

vue:
main.js >>
import myTouch from './myTouch'
myTouch(Vue)

app.vue >>
     data:function () {
      return{
          baseLeft : 0,
          baseTop: 0,
          bodyWidth: document.body.clientWidth,
          ele: null, // 不能在這裏設置, dom尚未生成
      }
  },

放大功能實現

scalePic: function(param, is_endScale){
      this.ele =document.getElementsByClassName('modal_content')[0]; // 這個應該在圖片顯示的時候設置
      let nodeStyle = this.ele.style.transform;
      let changeSize = nodeStyle ?  parseFloat(nodeStyle.slice(nodeStyle.indexOf('scale')+6)) : 0;
      if(is_endScale){
        // 縮放圖片結束,要從新計算定位
        this.setMaxdisp(changeSize,parseInt(this.ele.style.marginLeft), parseInt(this.ele.style.marginTop), 'scale')
        return 
      }
      if(nodeStyle){
        // 若是存在的話,就說明已經設置了,scale已經改變了
        let currScaleSize = changeSize + param; 
        currScaleSize > 3 ? currScaleSize = 3 : null
        currScaleSize < 1 ? currScaleSize = 1 : null
        this.ele.style.transform = 'translate(-50%, -50%) scale('+currScaleSize+','+currScaleSize+')';
      }else{ // 若是不存在,就說明是第一次設置
          let scale = param + 1 
          this.ele.style.marginLeft =  '0px';
          this.ele.style.marginTop  = '0px';
          this.ele.style.transform = 'translate(-50%, -50%) scale('+scale+','+scale+')';
      }
    }

移動功能

movePic: function(param){
     if(param.is_endMove){ // 每次移動鬆開手指的時候要下次移動的基礎座標
        this.baseLeft = parseInt(this.ele.style.marginLeft.slice(0, -2));
        this.baseTop = parseInt(this.ele.style.marginTop.slice(0, -2));
      }else{
        let nodeStyle = this.ele.style.transform 
        if(nodeStyle){ // 有這個就表示應該是移動
          let currScaleSize = parseFloat(nodeStyle.slice(nodeStyle.indexOf('scale')+6))
          this.setMaxdisp(currScaleSize,this.baseLeft+ param.x, this.baseTop + param.y, 'move')
        }
      }
    }

計算最大位移

setMaxdisp:function(changeSize, changeX, changeY, type){
      // 計算最大位移
      // naturalWidth : 是圖片原始的寬度,經過比例能夠計算出當前圖片在頁面的高度
      let picHeight =  this.bodyWidth  / (this.ele.naturalWidth / this.ele.naturalHeight); 
      let maxTop = ( picHeight * changeSize - window.innerHeight) /2 
      let maxLeft = this.bodyWidth / 2 * (changeSize - 1) 
      if(changeX >= maxLeft){
        this.ele.style.marginLeft = maxLeft + 'px'
      }else if(changeX < -maxLeft){
        this.ele.style.marginLeft = -maxLeft + 'px'
      }else if(type==='move'){
        this.ele.style.marginLeft =changeX +'px'; 
      }
      // 若是圖片當前尺寸大於屏幕尺寸,能夠移動
      if(maxTop > 0){
        if(changeY >= maxTop){
          this.ele.style.marginTop = maxTop + 'px';
        }else if(changeY < -maxTop){
          this.ele.style.marginTop = -maxTop + 'px'
        }else if(type==='move'){
          this.ele.style.marginTop = changeY+'px';
        }
      }else if(type==='move'){
        this.ele.style.marginTop = 0 +'px'; 
      }
    }

遇到的問題

雙指與單指容易混淆

在雙指放大縮小的時候,兩個手指鬆開時間不一樣,頁面就會在兩個手指鬆開的時候判斷爲點擊事件。 這個尚未解決vue

計算圖片位移程度

圖片不能隨意的位移。應該是在必定範圍內去位移的,因此寫了一個計算最大位移的函數,圖片位移距離應該是圖片恰好能看到的程度。經過圖片原始的寬高,以及頁面當前的寬度比例能夠計算出當前圖片在頁面的高度。而後計算出最大位移node

每次移動的基礎位置

圖片移動或者縮小懂應該是在一個基礎數據上去增長減小,若是沒有設置這個基礎數據,會致使每次都是從1的比例來移動以及縮小,因此每次移動以及放大縮小圖片以後,都要記錄下來改變以後圖片的參數,下次改變圖片的時候都是在這個參數基礎上去改變的。bash

相關文章
相關標籤/搜索