周末尝试用vue写了一个android版QQ客户端的Web App demo。暂时只写了首页消息这个界面,几个小图标是用sketch画的svg。侧滑栏的背景图终于祭出了个人ps。底部导航图标由于实在不太会用sketch,先放弃了。javascript
请使用最新版chrome + mobile emulator 访问vue
想来说下手势识别的实现的思路,代码在这里(目前还不完善)android
listen (type, $el, func) {
let rect
if (!$el) {
rect = null
} else {
let tmp = $el.getBoundingClientRect()
rect = {
x: tmp.left,
y: tmp.top,
width: tmp.width,
height: tmp.height
}
}
let token = Math.random() * 9999 + type
this.queue[type].push({
$el: $el,
token: token,
func: func,
rect: rect
})
}复制代码
首先个人思路是监听窗口的touch事件,以组件自身的像素区域来派发事件,调用listen的时候传入想要监听事件的类型和指望触发该事件的Element, 还有就是加上触发的函数回调。若是不传入Element的话,就会接收到所有的事件触发。git
这里首先是注册订阅该组件固然的像素区域,那么若是滑动页面以后改怎么办?github
update () {
let keys = Object.keys(this.queue)
let tmp
for (let key of keys) {
this.queue[key].forEach(item => {
if (item.$el) {
tmp = item.$el.getBoundingClientRect()
item.rect = {
x: tmp.left,
y: tmp.top,
width: tmp.width,
height: tmp.height
}
}
})
}
}复制代码
这里的update就须要在body 或者其上级节点 scroll的时候调用来更新组件的注册区域。chrome
init () {
if (this._hasTouch) {
window.document.body.addEventListener('touchstart', this.touchStart.bind(this), false)
window.document.body.addEventListener('touchmove', this.touchMove.bind(this), false)
window.document.body.addEventListener('touchend', this.touchEnd.bind(this), false)
window.document.body.addEventListener('touchcancel', this.touchCancel.bind(this), false)
}
}复制代码
这里是注册全局的touch监听dom
touchStart (e) {
this.state.swiping = true
this.touch.start = this.getPosition(e)[0]
}
touchMove (e) {
this.touch.end = this.getPosition(e)[0]
this.notice('swiping', this.getRect(this.touch.end, this.touch.start))
}复制代码
这里是对swiping 在touchmove时不断派发事件,可能须要优化一下加上节流。若是在加上滑动路径和趋势分析就更好了。svg
touchEnd (e) {
this.notice('swiped', this.getRect(this.touch.end, this.touch.start))
this.state.swiping = true
let angle = this.getAngle(this.touch.end, this.touch.start)
if (angle > -45 && angle < 45) {
this.notice('swipe-left', this.getRect(this.touch.end, this.touch.start))
}
if (angle < -135 || angle > 135) {
this.notice('swipe-right', this.getRect(this.touch.end, this.touch.start))
}
if (angle > 45 && angle < 135) {
this.notice('swipe-up', this.getRect(this.touch.end, this.touch.start))
}
if (angle < -45 && angle > -135) {
this.notice('swipe-down', this.getRect(this.touch.end, this.touch.start))
}
}
touchCancel (e) {
console.log(e)
}复制代码
这里就是对一次touch过程的方向判断,而后派发事件函数
notice (type, rect) {
let rectTmp = {}
let once = true
let tmpFunc = null
for (let i = 0, len = this.queue[type].length; i < len; i++) {
rectTmp = this.queue[type][i].rect
if (!rectTmp) {
tmpFunc = this.queue[type][i].func
} else {
if (this.rectIn(rect, rectTmp) && !this.state.global) {
this.queue[type][i].func(this.touch.start, this.touch.end)
once = false
}
}
}
if (once && tmpFunc) {
tmpFunc(this.touch.start, this.touch.end)
}
}复制代码
这里是派发的函数实现,为了此次demo的实现,我把全局手势优先级设置为低于指定区域的优先级。
export default {
props: {
message: Object
},
data () {
return {
closeToken: '',
swiping: 0,
menu: false
}
},
ready () {
this.add()
},
methods: {
add () {
this.$swipe.listen('swipe-left', this.$el, () => {
this.swiping = -160
this.menu = true
this.closeToken = this.$swipe.listen('swipe-right', this.$el, () => {
this.swiping = 0
this.menu = false
this.$swipe.leave('swipe-right', this.closeToken)
})
})
this.$swipe.listen('swiping', this.$el, (start, end) => {
if (start.x > end.x && this.swiping > -160) {
this.swiping = -(start.x - end.x)
}
})
this.$swipe.listen('swiped', this.$el, (start, end) => {
if (!this.menu) {
this.swiping = 0
}
})
}
}
}复制代码
这是在消息组件所有代码。 目前还没(bu)计(xiang)划(xie)整合为vue指令。