因爲第一次做封裝所以感覺在代碼易用性和可複用性方面都有待提高,會在後續不斷完善和改進。目前支持的手勢包括長按,雙擊、滑動(四個方向的滑動)、縮放(放大、縮小)、旋轉,使用方法爲:
將代碼加載後使用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)
}
}