#vue.js
#vue.js
Вопрос:
я изо всех сил пытаюсь понять, где мой скрипт замедляется на мобильных устройствах. Если щелкнуть и перетащить изображение, оно будет вращаться, сделайте то же самое на мобильных устройствах, и это действительно медленно!
Я переместил скрипт на его собственную страницу, но не могу добавить его сюда, поскольку запросы AJAX, похоже, не работают, и есть большой массив изображений, которые извлекаются.
Моя проблема просто в том, что перемещение не перемещается во времени с вашим пальцем…
http://click.martynleeball.co.uk/360/
Это сценарий:
Vue.component('viewer', {
data() {
return {
loading: false,
loop: true,
speed: 2,
reverse: true,
speedController: 0,
zoomEnabled: true,
zoomLevels: [1, 1.5, 2, 2.5, 3],
zoomLevel: 1,
frame: 1,
images: [],
imagesPreloaded: 0,
spinEnabled: true,
spinAuto: false,
viewportScale: 0.3,
viewportEnabled: true,
viewportOpacity: 0.8,
lastX: 0,
lastY: 0,
startX: 0,
startY: 0,
translateX: 0,
translateY: 0,
isMoving: false,
isDragging: false,
lastPinch: 0,
animationRequestID: 0,
spinStart: null,
spinThen: Date.now(),
fps: 1000 / 8,
$moveEvent: null
};
},
mounted() {
window.addEventListener('mouseup', this.handleEnd);
window.addEventListener('touchend', this.handleEnd);
window.addEventListener('orientationchange', this.fetch);
// iOS Specific
this.$el.addEventListener('gesturestart', function (e) {
e.preventDefault();
});
this.fetch();
},
beforeDestroy() {
window.removeEventListener('mouseup', this.handleEnd);
window.removeEventListener('touchend', this.handleEnd);
},
methods: {
fetch: function () {
const self = this;
// Reset the preload
this.imagesPreloaded = 0;
this.loading = true;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 amp;amp; this.status == 200) {
// All of the 360 images.
self.images = JSON.parse(this.responseText);
var images = [];
for (var i = 0; i < self.images.length; i ) {
images[i] = new Image();
images[i].src = self.images[i][1].url;
self.imagesPreloaded ;
}
// Some dealers spin the vehicle the wrong way...
if (self.reverse) {
self.images = self.images.reverse();
}
self.loading = false;
if (self.spinAuto amp;amp; self.spinEnabled) {
self.spinStart = self.spinThen;
self.spin(1);
}
}
};
xhttp.open("GET", "./images.php", true);
xhttp.send();
},
handleStart($event) {
if ($event.button amp;amp; $event.button !== 0) {
return;
}
if (this.animationRequestID !== 0) {
this.spinStop();
}
this.isMoving = true;
this.isDragging = true;
this.startX = $event.pageX || $event.touches[0].pageX;
this.startY = $event.pageY || $event.touches[0].pageY;
},
handleMove($event, viewport) {
if ($event.button amp;amp; $event.button !== 0) {
return;
}
if ($event.touches amp;amp; $event.touches.length > 1) {
this.zoomPinch($event);
return;
}
this.$moveEvent = $event;
if (this.isMoving amp;amp; this.isDragging) {
const positions = {
x: $event.pageX || $event.touches[0].pageX,
y: $event.pageY || $event.touches[0].pageY
}
if (this.zoomLevel !== 1) {
this.translate(positions, null, viewport);
}
if (this.zoomLevel === 1) {
this.changeFrame(positions, $event.touches amp;amp; $event.touches.length >= 1);
}
this.lastX = positions.x;
this.lastY = positions.y;
}
},
handleEnd: function () {
this.lastPinch = 0;
this.isMoving = false;
},
spin(index) {
let i = index;
if (i >= this.images.length) {
i = 1;
}
this.animationRequestID = window.requestAnimationFrame(() => this.spin(i));
let now = Date.now();
let elapsed = now - this.spinThen;
if (elapsed > this.fps) {
this.spinThen = now - (elapsed % this.fps);
this.frame = i;
i = 1;
}
},
spinToggle: function () {
if (this.animationRequestID === 0 amp;amp; this.zoomLevel === 1) {
this.spin(this.frame);
return;
}
this.spinStop();
},
spinStop: function () {
if (this.animationRequestID) {
window.cancelAnimationFrame(this.animationRequestID);
this.animationRequestID = 0;
}
},
translate(positions, zooming, viewport) {
if (this.$moveEvent) {
this.$moveEvent.preventDefault();
}
window.requestAnimationFrame(() => {
positions = positions || {
x: this.startX,
y: this.startY
};
if (viewport) {
this._translateFromViewport(positions);
} else {
this._translateFromImage(positions, zooming);
}
this.startX = positions.x;
this.startY = positions.y;
});
},
/**
* @param positions
* @private
*/
_translateFromViewport(positions) {
let move = {
x: Math.floor(positions.x - this.startX),
y: Math.floor(positions.y - this.startY)
};
let box = this.$refs.viewportBox.getBoundingClientRect();
let container = this.$refs.viewportContainer.getBoundingClientRect();
// Amount of pixels moved within animation frame, adjust based on viewport scale.
// Zoom level doesn't matter as image scale doesn't move, so box is moving same amount of pixels.
let moveAmountX = (move.x / this.viewportScale);
let moveAmountY = (move.y / this.viewportScale);
// Find the current offset of the container bounds, calculate new offset based on movement amount
let calculatedOffset = {
left: (container.left - box.left) - moveAmountX,
right: (container.right - box.right) - moveAmountX,
top: (container.top - box.top) - moveAmountY,
bottom: (container.bottom - box.bottom) - moveAmountY
};
// Only move if the calculated new offset is not out of container bounds
// Reverse the movement as moving box in same direction as cursor rather than the image.
if (calculatedOffset.left <= 0 amp;amp; calculatedOffset.right >= 0) {
this.translateX = -moveAmountX;
}
if (calculatedOffset.top <= 0 amp;amp; calculatedOffset.bottom >= 0) {
this.translateY = -moveAmountY;
}
},
_translateFromImage(positions, zooming) {
let move = {
x: Math.floor(positions.x - this.startX),
y: Math.floor(positions.y - this.startY)
};
let image = this.$refs.image.getBoundingClientRect();
let container = this.$refs.container.getBoundingClientRect();
let moveAmountX = move.x * this.zoomLevel;
let moveAmountY = move.y * this.zoomLevel;
let calculatedOffset = {
left: (container.left - image.left) - moveAmountX,
right: (container.right - image.right) - moveAmountX,
top: (container.top - image.top) - moveAmountY,
bottom: (container.bottom - image.bottom) - moveAmountY
};
if (zooming) {
if (calculatedOffset.left <= 0) {
this.translateX = calculatedOffset.left;
}
if (calculatedOffset.right >= 0) {
this.translateX = calculatedOffset.right;
}
if (calculatedOffset.top <= 0) {
this.translateY = calculatedOffset.top;
}
if (calculatedOffset.bottom >= 0) {
this.translateY = calculatedOffset.bottom;
}
}
if (calculatedOffset.left >= 0 amp;amp; calculatedOffset.right <= 0) {
this.translateX = move.x / this.zoomLevel;
}
if (calculatedOffset.top >= 0 amp;amp; calculatedOffset.bottom <= 0) {
this.translateY = move.y / this.zoomLevel;
}
},
changeFrame(positions, touch) {
this.speedController = 1;
if ((this.speedController < this.speed) amp;amp; !touch) {
return;
}
if (this.speedController > this.speed) {
this.speedController = 0;
}
if (positions.x > this.lastX) {
if (this.frame >= 0 amp;amp; this.frame < this.images.length) {
this.frame = 1;
} else if (this.loop) {
this.frame = 1;
}
} else if (positions.x < this.lastX) {
if (this.frame >= 0 amp;amp; this.frame - 1 > 0) {
this.frame -= 1;
} else if (this.loop) {
this.frame = this.images.length;
}
}
}
},
watch: {
zoomLevel: function () {
if (this.zoomLevel !== 1 amp;amp; this.animationRequestID !== 0) {
this.spinStop();
}
}
},
computed: {
closestZoom: function () {
return this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
},
imageSet: function () {
return this.images.map(image => {
return image[this.closestZoom].url;
});
},
preloadProgress: function () {
return Math.floor(this.imagesPreloaded / this.images.length * 100);
},
currentPath: function () {
return this.images[this.frame - 1][this.closestZoom].url;
},
nextZoomLevel: function () {
if (this.zoomLevels.indexOf(this.closestZoom) === this.zoomLevels.length - 1) {
return this.zoomLevels[0];
}
return this.zoomLevels[this.zoomLevels.indexOf(this.closestZoom) 1];
},
viewportTransform: function () {
if (this.viewportEnabled) {
let translateX = -((this.translateX * this.viewportScale) * this.zoomLevel);
let translateY = -((this.translateY * this.viewportScale) * this.zoomLevel);
return `scale(${1 / this.zoomLevel}) translateX(${translateX}px) translateY(${translateY}px)`;
}
},
transform: function () {
return `scale(${this.zoomLevel}) translateX(${this.translateX}px) translateY(${this.translateY}px)`;
},
canZoomIn: function () {
return this.zoomLevels[this.zoomLevels.indexOf(this.closestZoom) 1] === undefined
},
canZoomOut: function () {
return this.zoomLevels[this.zoomLevels.indexOf(this.closestZoom) -1] === undefined
}
},
template: '#template'
});
Ответ №1:
Удалось найти ответ, при включении обновления мобильного браузера прокрутка имеет более высокий приоритет, чем другие события касания, поэтому добавление touch-action: none;
к моему изображению устраняет эту проблему!