上篇,我们实现在 Alphabet.vue 中实现了,点击、滑动右侧字母表,左边城市列表跟着滑动。但是,在touch 部分,性能比较低。
如下是上篇的除style 的代码,Alphabet.vue
<template>
<ul class="list">
<li
class="item"
v-for="item of letters"
:key="item"
:ref="item"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
{{item}}
</li>
</ul>
</template>
<script>
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
data () {
return {
touchStatus: false
}
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
methods: {
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
handleTouchStart () {
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
const startY = this.$refs['A'][0].offsetTop
const touchY = e.touches[0].clientY - 79
const index = Math.floor((touchY - startY) / 20)
if (index >= 0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script>
首先,我们不必每次touch 事件都计算startY,只需要在页面重新渲染的时候,计算即可。如下,updated 是vue 的一个生命周期钩子,当页面数据更新且页面完成了自己的渲染之后(也就是ajax 传数据之后),这个钩子函数就会被执行。
<template>
<ul class="list">
<li
class="item"
v-for="item of letters"
:key="item"
:ref="item"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
{{item}}
</li>
</ul>
</template>
<script>
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
data () {
return {
touchStatus: false,
startY: 0
}
},
updated () {
console.log('i am updated')
this.startY = this.$refs['A'][0].offsetTop
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
methods: {
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
handleTouchStart () {
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
const touchY = e.touches[0].clientY - 79
const index = Math.floor((touchY - this.startY) / 20)
if (index >= 0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script>
下一步,我们要做的性能优化,就是函数截流。当鼠标在字母表滑动的时候,这时候,函数执行的频率非常大,我们可以通过截流,限制函数执行的频率。
<template>
<ul class="list">
<li
class="item"
v-for="item of letters"
:key="item"
:ref="item"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
{{item}}
</li>
</ul>
</template>
<script>
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
data () {
return {
touchStatus: false,
startY: 0,
timmer: null
}
},
updated () {
console.log('i am updated')
this.startY = this.$refs['A'][0].offsetTop
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
methods: {
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
handleTouchStart () {
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timmer) {
clearTimeout(this.timmer)
}
this.timmer = setTimeout(() => {
const touchY = e.touches[0].clientY - 79
const index = Math.floor((touchY - this.startY) / 20)
if (index >= 0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}, 16)
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script>
Done!
可以提交合并啦。