touch端的手勢庫封裝

因爲第一次做封裝所以感覺在代碼易用性和可複用性方面都有待提高,會在後續不斷完善和改進。目前支持的手勢包括長按,雙擊、滑動(四個方向的滑動)、縮放(放大、縮小)、旋轉,使用方法爲:
將代碼加載後使用gesture()函數來進行事件的綁定和監聽。以下爲使用方法示例

let target = document.getElementById('test')
//綁定並監聽目標target的左滑事件,並傳入回調函數
gesture('slideLeft', target, (e) => {
    console.log(e)
})
//綁定並監聽目標target的所有已支持的手勢事件,並傳入回調函數
gesture('all', target, (e) => {
    console.log(e)
})
//輸出錯誤提示:undefined eventName a, Please input correct eventName
gesture('a', target, (e) => {
    console.log(e)
})

目前支持的手勢名爲:
slideLeft:左滑
slideRight:右滑
slideTop:上滑
slideBottom:下滑
longTouch:長按 (時長認定爲350ms)
dbTouch:連點(手機不支持原生的dblclick)
largeScale:放大
smallScale:縮小
rotate:旋轉

代碼實現如下:

let dbTime = 200
let longTime = 350
let slideDistance = 10
let start = []
let end = []
let startCount = 0
let finger =    null
let startStamp = null
let endStamp = null
let info = {
    //save what you want to get
    timeStart: null,
    timeEnd: null,
    rotate: false,
    scale: false
}
let slideLeft = new CustomEvent('slideLeft', {
    detail: info
})
let slideRight = new CustomEvent('slideRight', {
    detail: info
})
let slideTop = new CustomEvent('slideTop', {
    detail: info
})
let slideBottom = new CustomEvent('slideBottom', {
    detail: info
})
let longTouch = new CustomEvent('longTouch', {
    detail: info
})
let dbTouch = new CustomEvent('dbTouch', {
    detail: info
})
let largeScale = new CustomEvent('largeScale', {
    detail: info
})
let smallScale = new CustomEvent('smallScale', {
    detail: info
})
let rotate = new CustomEvent('rotate', {
    detail: info
})
function gestureDefine(target) {
    target.addEventListener('touchstart', e => {
        let tempStart = [...e.changedTouches]
        //timeStamp
        startStamp = e.timeStamp
        if(!info.timeStart) {
            info.timeStart = Date.now()
        }
        if(info.timeEnd && startStamp - endStamp < dbTime) {
            target.dispatchEvent(dbTouch)
        }
        //init start
        let temps = {}
        temps.x = tempStart[0].screenX
        temps.y = tempStart[0].screenY
        temps.id = tempStart[0].identifier
        start.push(temps)
        //init end
        end = []
        startCount++
    })
    target.addEventListener('touchend', e => {
        startCount--
        endStamp = e.timeStamp
        //get event information
        info.timeEnd = Date.now()
        //static valuation
        let tempEnd = [...e.changedTouches]
        let tempe = {}
        tempe.x = tempEnd[0].screenX
        tempe.y = tempEnd[0].screenY
        tempe.id = tempEnd[0].identifier
        end.push(tempe)
        if(end.length == start.length && end.length == 2) {
            let arrStart = []
            let arrEnd = []
            for(let i = 0; i < end.length; i++) {
                arrStart[start[i].id] = start[i]
                arrEnd[end[i].id] = end[i]
            }
            let startDistance = getDistance(arrStart[0], arrStart[1])
            let endDistance = getDistance(arrEnd[0], arrEnd[1])
            info.scale = endDistance / startDistance
            info.rotate = getRotate(arrStart, arrEnd)
            //judge rotate
            if(info.rotate) {
                target.dispatchEvent(rotate)
            } 
            if(info.scale > 1.15) {
                target.dispatchEvent(largeScale)
            } else if(info.scale < 0.95) {
                target.dispatchEvent(smallScale)
            }
            if(startCount == 0) {
                start = []
            }
            return
        }
        if(startCount !== 0) {
            return 
        }    
        //slideEvent
        info.rotate = false
        info.scale = false
        if(tempEnd.length === 1) {
            let x = tempEnd[0].screenX
            let y = tempEnd[0].screenY
            let direction = Math.abs(x - start[0].x) > Math.abs(y - start[0].y) ? 'x' : 'y'
            if(Math.abs(x - start[0].x) < 5 && Math.abs(y - start[0].y) < 5) {
                if(endStamp - startStamp > longTime) {
                    target.dispatchEvent(longTouch)
                }
                return
            }
            if (direction == 'x') {
                if(x > start[0].x) {
                    target.dispatchEvent(slideRight)
                } else {
                    target.dispatchEvent(slideLeft)
                }
            } else if (direction == 'y') {
                if(y > start[0].y) {
                    target.dispatchEvent(slideBottom)
                } else {
                    target.dispatchEvent(slideTop)
                }
            }
        } 
        if(startCount == 0) {
            start = []
        }
    })

} )
}
function getRotate(start, end) {
    let core = getCore(start, end)
    if(!core.contain){
        return false
    }
    return core.rotate

}

function getCore(start, end) {
    let trans = 180 / Math.PI
    let k1 = (start[0].y - start[1].y) / (start[0].x - start[1].x)
    let b1 = start[0].y - k1 * start[0].x
    let k2 = (end[0].y - end[1].y) / (end[0].x - end[1].x)
    let b2 = end[0].y - k2 * end[0].x
    let a = Math.atan(-k1) * trans
    let b = Math.atan(-k2) * trans
    let core = {}
    core.x = (b2 - b1) / (k1 - k2)
    core.y = (k2 * b1 - k2 * b2) / (k2 - k1)
    core.rotate = Math.round(a - b)
    let direct = (start[0].x - core.x) / (core.x - start[1].x)
    if(direct > 0) {
        core.contain = true
    } else {
        core.contain = false
    }
    return core
}

function getDistance(start, end) {
    return Math.pow(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2), 1/2)
}

function gesture(name, target, callback) {
    let eventList = [
        'slideLeft',
        'slideRight',
        'slideTop',
        'slideBottom',
        'longTouch',
        'dbTouch',
        'largeScale',
        'smallScale',
        'rotate',
        'all'
    ]
    if(eventList.indexOf(name) === -1) {
        console.log('undefined eventName "' + name + '", Please input correct eventName')
        return
    }
    gestureDefine(target)
    if(name == 'all') {
        target.addEventListener('slideLeft', callback)
        target.addEventListener('slideRight',callback)
        target.addEventListener('slideTop', callback)
        target.addEventListener('slideBottom', callback)
        target.addEventListener('longTouch', callback)
        target.addEventListener('dbTouch', callback)
        target.addEventListener('largeScale', callback)
        target.addEventListener('smallScale', callback)
        target.addEventListener('rotate', callback)
    } else {
        target.addEventListener(name, callback)
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章