如何在Android/Chrome上提高touchmove性能?
我正在开发一个使用触摸事件的自定义拖动UI。当页面上有滚动条时,ChromeAndroid如何在Android/Chrome上提高touchmove性能?,android,performance,vue.js,google-chrome,touch-event,Android,Performance,Vue.js,Google Chrome,Touch Event,我正在开发一个使用触摸事件的自定义拖动UI。当页面上有滚动条时,ChromeAndroidtouchmove性能糟糕,事件每秒只会触发几次,导致极为剧烈的拖动。当没有滚动条或使用ChromeDevToolsEmulator进行测试时,问题不会重现 添加触摸事件:无CSS属性有助于解决这个问题,但也可以防止容器内部发生本机滚动,因此使用这种方法需要我重新实现像JS滚动一样的本机滚动 演示: Vue组件代码: <template> <div class="cont
touchmove
性能糟糕,事件每秒只会触发几次,导致极为剧烈的拖动。当没有滚动条或使用ChromeDevToolsEmulator进行测试时,问题不会重现
添加触摸事件:无
CSS属性有助于解决这个问题,但也可以防止容器内部发生本机滚动,因此使用这种方法需要我重新实现像JS滚动一样的本机滚动
演示:
Vue组件代码:
<template>
<div class="container">
<div
:class="containerClass"
:style="containerStyle"
@touchend="touchEndHandler"
@touchmove="touchMoveHandler"
@touchstart="touchStartHandler"
@transitionend="transitionEndHandler"
class="scroller-container"
>
<svg viewBox="0 0 100 20" always-swipeable="true" class="drag-handle">
<polyline points="27,10 73,10" stroke-linecap="round"></polyline>
</svg>
<div class="scrollbox" ref="scrollbox">
<div :key="item" class="item" v-for="item in items">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
deltaY: 0,
isDraggingByHandle: false,
isTransitioning: false,
items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
offsetHeight: 0,
scrollboxHeight: 0,
scrollTop: 0,
touchAction: null,
verticalStates: [
{
translateY: 0,
},
{
translateY: window.innerHeight - 200,
},
],
verticalStateIndex: 0,
}
},
computed: {
activeVerticalState() {
return this.verticalStates[this.verticalStateIndex]
},
containerClass() {
return {
'show-scrollbar': this.isScrollable,
transition: this.isTransitioning,
}
},
containerStyle() {
return {
transform: `translateY(${this.translateY}px)`,
}
},
isAnySwipe() {
return this.isDraggingByHandle || !this.isScrollable
},
isExpanded() {
return this.verticalStateIndex === 0
},
isScrollable() {
return this.isExpanded && this.scrollHeight > this.offsetHeight
},
isSwipeDown() {
return this.deltaY > 0 && (this.isAnySwipe || this.scrollTop === 0)
},
isSwipeUp() {
return (
this.deltaY < 0 &&
(this.isAnySwipe || this.offsetHeight + this.scrollTop === this.scrollHeight)
)
},
scrollbox() {
return this.$refs.scrollbox
},
translateY() {
let translateY = this.activeVerticalState.translateY
if (this.touchAction === 'verticalSwipe' && (this.isSwipeDown || this.isSwipeUp)) {
translateY = translateY + this.deltaY
}
return translateY
},
},
mounted() {
this.updateScrollboxData()
},
methods: {
touchStartHandler: function({touches, target}) {
this.updateScrollboxData()
this.isDraggingByHandle = Boolean(target.getAttribute('always-swipeable'))
this.touchStartCoordinates = touches[0]
this.touchAction = 'tap'
},
touchMoveHandler: function(event) {
this.updateScrollboxData()
this.deltaY = event.touches[0].clientY - this.touchStartCoordinates.clientY
// promote touchAction to swipe or scroll depending on deltas and other variables
if (this.touchAction === 'tap') {
if (this.isSwipeDown || this.isSwipeUp) {
this.touchAction = 'verticalSwipe'
} else {
this.touchAction = 'scroll'
}
}
},
touchEndHandler: function() {
switch (this.touchAction) {
case 'tap':
if (!this.isExpanded) {
this.verticalStateIndex = Math.max(this.verticalStateIndex - 1, 0)
this.isTransitioning = true
}
break
case 'verticalSwipe':
if (this.isSwipeDown) {
this.verticalStateIndex = Math.min(
this.verticalStateIndex + 1,
this.verticalStates.length - 1
)
} else if (this.isSwipeUp) {
this.verticalStateIndex = Math.max(this.verticalStateIndex - 1, 0)
}
this.isTransitioning = true
this.deltaY = 0
break
}
},
transitionEndHandler() {
this.touchAction = null
this.isTransitioning = false
this.updateScrollboxData()
},
updateScrollboxData() {
const {scrollHeight, offsetHeight, scrollTop} = this.scrollbox
this.offsetHeight = offsetHeight
this.scrollHeight = scrollHeight
this.scrollTop = scrollTop
},
},
}
</script>
<style lang="scss" scoped>
.container {
display: flex;
justify-content: center;
margin-top: 5vh;
overflow: hidden;
.scroller-container {
pointer-events: all;
width: 90vw;
height: 100%;
&.transition {
transition: transform 0.15s ease-out;
}
.drag-handle {
stroke-width: 5px;
stroke: #bfbfc0;
width: 100%;
height: 30px;
background: pink;
}
.scrollbox {
overflow-y: hidden;
pointer-events: none;
background: green;
height: 85vh;
.item {
margin-bottom: 20px;
height: 150px;
font-size: 36px;
background: yellow;
}
}
&.show-scrollbar .scrollbox {
overflow-y: scroll;
pointer-events: all;
}
}
}
</style>
{{item}}
导出默认值{
数据(){
返回{
德尔泰:0,
IsDragingByHandle:false,
isTransitioning:false,
项目:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
离地:0,
scrollboxHeight:0,
滚动顶端:0,
touchAction:null,
垂直状态:[
{
translateY:0,
},
{
translateY:window.innerHeight-200,
},
],
垂直状态索引:0,
}
},
计算:{
activeVerticalState(){
返回此.verticalStates[此.verticalStateIndex]
},
集装箱类(){
返回{
“显示滚动条”:this.iscrowllable,
转变:这是转变,
}
},
集装箱运输方式(){
返回{
transform:`translateY(${this.translateY}px)`,
}
},
isAnySwipe(){
返回此.IsDragingByHandle | | |!此.IsCrollable
},
isExpanded(){
返回此值。verticalStateIndex==0
},
可转换的{
返回this.isExpanded&&this.scrollHeight>this.offsetHeight
},
IsSweepDown(){
返回this.deltaY>0&(this.isAnySwipe | | this.scrollTop==0)
},
Isswipup(){
返回(
这是德尔泰<0&&
(this.isAnySwipe | | this.offsetHeight+this.scrollTop==this.scrollHeight)
)
},
滚动框(){
返回此。$refs.scrollbox
},
translateY(){
让translateY=this.activeVerticalState.translateY
if(this.touchAction==='verticalSwipe'&&(this.isSwipeDown | | this.isSwipeUp)){
translateY=translateY+this.deltaY
}
返回平移
},
},
安装的(){
this.updateScrollboxData()
},
方法:{
touchStartHandler:函数({touchs,target}){
this.updateScrollboxData()
this.isDragingByHandle=Boolean(target.getAttribute('always-swipeable'))
this.touchStartCoordinates=触摸[0]
this.touchAction='tap'
},
touchMoveHandler:函数(事件){
this.updateScrollboxData()
this.deltaY=event.touchs[0].clientY-this.touchStartCoordinates.clientY
//根据增量和其他变量,将touchAction升级为滑动或滚动
如果(this.touchAction==='tap'){
如果(this.isSwipeDown | this.isSwipeUp){
this.touchAction='verticalSwipe'
}否则{
this.touchAction='scroll'
}
}
},
touchEndHandler:函数(){
开关(此.touchAction){
案例“tap”:
如果(!this.isExpanded){
this.verticalStateIndex=Math.max(this.verticalStateIndex-1,0)
this.isTransitioning=true
}
打破
“垂直滑动”案例:
如果(此.isSwipeDown){
this.verticalStateIndex=Math.min(
此.verticalStateIndex+1,
此.verticalStates.length-1
)
}否则,如果(此.isswipup){
this.verticalStateIndex=Math.max(this.verticalStateIndex-1,0)
}
this.isTransitioning=true
此值为0.deltaY=0
打破
}
},
transitionEndHandler(){
this.touchAction=null
this.isTransitioning=false
this.updateScrollboxData()
},
updateScrollboxData(){
const{scrollHeight,offsetHeight,scrollTop}=this.scrollbox
this.offsetHeight=offsetHeight
this.scrollHeight=滚动高度
this.scrollTop=scrollTop
},
},
}
.集装箱{
显示器:flex;
证明内容:中心;
边缘顶部:5vh;
溢出:隐藏;
.滚动条容器{
指针事件:全部;
宽度:90vw;
身高:100%;
&.过渡{
转换:转换0.15秒缓解;
}
.拖动手柄{
笔画宽度:5px;
行程:#bfc0;
宽度:100%;
高度:30px;
背景:粉红色;
}
.滚动框{
溢出y:隐藏;
指针事件:无;
背景:绿色;
高度:85vh;
.项目{
边缘底部:20px;
高度:150像素;
字体大小:36px;
背景:黄色;
}
}
&.显示滚动条.滚动框{
溢出y:滚动;
指针事件