optimize:web Optimize NestedSlider scrolling

This commit is contained in:
wangxiangyuan 2023-09-08 16:15:19 +08:00 committed by osborn
parent 0cf75592ae
commit b087730090
4 changed files with 146 additions and 80 deletions

View File

@ -8590,6 +8590,66 @@ var doric_web = (function (exports, axios, sandbox) {
} }
} }
function getX(ev) {
return ev instanceof MouseEvent ? ev.pageX : ev.touches[0].pageX;
}
function getY(ev) {
return ev instanceof MouseEvent ? ev.pageY : ev.touches[0].pageY;
}
function NestedSliderView(props) {
const ret = document.createElement("div");
ret.style.overflow = "hidden";
ret.style.display = "inline";
ret.style.whiteSpace = "nowrap";
let touch = {
touchStartX: 0,
touchStartY: 0,
currentIndex: 0,
isDragging: false,
horizontal: true
};
ret.ontouchstart = ret.onmousedown = (ev) => {
if (!props.scrollable())
return;
touch = Object.assign(Object.assign({}, touch), { currentIndex: Math.round(ret.scrollLeft / ret.offsetWidth), touchStartX: getX(ev), touchStartY: getY(ev), isDragging: true });
};
ret.ontouchmove = ret.onmousemove = (ev) => {
if (!props.scrollable() || !touch.isDragging)
return;
if (!touch.horizontal) {
return;
}
if (Math.abs(getX(ev) - touch.touchStartX) < Math.abs(getY(ev) - touch.touchStartY)) {
touch.horizontal = false;
return;
}
const offsetX = (touch.touchStartX - getX(ev)) * 1.2;
ret.scrollTo({
left: touch.currentIndex * ret.offsetWidth + offsetX,
});
};
ret.onmouseup = ret.ontouchcancel = ret.ontouchend = () => {
if (!props.scrollable())
return;
touch = Object.assign(Object.assign({}, touch), { isDragging: false, horizontal: true });
let originIndex = touch.currentIndex;
if (Math.abs(ret.scrollLeft - originIndex * ret.offsetWidth) > ret.offsetWidth / 5) {
const positionOffset = Math.abs(ret.scrollLeft) > originIndex * ret.offsetWidth ? 1 : -1;
touch.currentIndex += positionOffset;
}
ret.scrollTo({
left: touch.currentIndex * ret.offsetWidth,
behavior: "smooth",
});
if (originIndex !== touch.currentIndex) {
if (props.onPageSelected) {
props.onPageSelected(touch.currentIndex);
}
}
};
return ret;
}
class DoricNestedSliderNode extends DoricGroupViewNode { class DoricNestedSliderNode extends DoricGroupViewNode {
constructor() { constructor() {
super(...arguments); super(...arguments);
@ -8613,50 +8673,13 @@ var doric_web = (function (exports, axios, sandbox) {
} }
} }
build() { build() {
const ret = document.createElement("div"); return NestedSliderView({
ret.style.overflow = "hidden"; scrollable: () => this.scrollable, onPageSelected: index => {
ret.style.display = "inline";
ret.style.whiteSpace = "nowrap";
let touchStartX = 0;
let currentIndex = 0;
let isDragging = false;
const handleTouchStart = (x) => {
if (!this.scrollable)
return;
currentIndex = Math.round(ret.scrollLeft / ret.offsetWidth);
touchStartX = x;
isDragging = true;
};
ret.onmousedown = (ev) => handleTouchStart(ev.pageX);
ret.ontouchstart = (ev) => handleTouchStart(ev.touches[0].pageX);
const handleTouchMove = (x) => {
if (!this.scrollable || !isDragging)
return;
const offsetX = (touchStartX - x) * 3;
ret.scrollTo({
left: currentIndex * ret.offsetWidth + offsetX,
});
};
ret.onmousemove = (ev) => handleTouchMove(ev.pageX);
ret.ontouchmove = (ev) => handleTouchMove(ev.touches[0].pageX);
const handleTouchCancel = () => {
if (!this.scrollable)
return;
isDragging = false;
let originInndex = currentIndex;
currentIndex = Math.round(ret.scrollLeft / ret.offsetWidth);
ret.scrollTo({
left: currentIndex * ret.offsetWidth,
behavior: "smooth",
});
if (originInndex !== currentIndex) {
if (this.onPageSelectedFuncId.length > 0) { if (this.onPageSelectedFuncId.length > 0) {
this.callJSResponse(this.onPageSelectedFuncId, currentIndex); this.callJSResponse(this.onPageSelectedFuncId, index);
} }
} }
}; });
ret.onmouseup = ret.ontouchcancel = ret.ontouchend = handleTouchCancel;
return ret;
} }
layout() { layout() {
super.layout(); super.layout();

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,6 @@
import { horizontalList } from 'doric';
import { DoricGroupViewNode } from "./DoricViewNode"; import { DoricGroupViewNode } from "./DoricViewNode";
import { NestedSliderView } from '../widgets/NestedSliderView';
export class DoricNestedSliderNode extends DoricGroupViewNode { export class DoricNestedSliderNode extends DoricGroupViewNode {
onPageSelectedFuncId = ""; onPageSelectedFuncId = "";
@ -19,47 +21,13 @@ export class DoricNestedSliderNode extends DoricGroupViewNode {
} }
build() { build() {
const ret = document.createElement("div"); return NestedSliderView({
ret.style.overflow = "hidden"; scrollable: () => this.scrollable, onPageSelected: index => {
ret.style.display = "inline";
ret.style.whiteSpace = "nowrap";
let touchStartX = 0;
let currentIndex = 0;
let isDragging = false;
const handleTouchStart = (x: number) => {
if (!this.scrollable) return;
currentIndex = Math.round(ret.scrollLeft / ret.offsetWidth);
touchStartX = x;
isDragging = true;
};
ret.onmousedown = (ev) => handleTouchStart(ev.pageX);
ret.ontouchstart = (ev) => handleTouchStart(ev.touches[0].pageX);
const handleTouchMove = (x: number) => {
if (!this.scrollable || !isDragging) return;
const offsetX = (touchStartX - x) * 3;
ret.scrollTo({
left: currentIndex * ret.offsetWidth + offsetX,
});
};
ret.onmousemove = (ev) => handleTouchMove(ev.pageX);
ret.ontouchmove = (ev) => handleTouchMove(ev.touches[0].pageX);
const handleTouchCancel = () => {
if (!this.scrollable) return;
isDragging = false;
let originInndex = currentIndex;
currentIndex = Math.round(ret.scrollLeft / ret.offsetWidth);
ret.scrollTo({
left: currentIndex * ret.offsetWidth,
behavior: "smooth",
});
if (originInndex !== currentIndex) {
if (this.onPageSelectedFuncId.length > 0) { if (this.onPageSelectedFuncId.length > 0) {
this.callJSResponse(this.onPageSelectedFuncId, currentIndex); this.callJSResponse(this.onPageSelectedFuncId, index);
} }
} }
}; });
ret.onmouseup = ret.ontouchcancel = ret.ontouchend = handleTouchCancel;
return ret;
} }
layout(): void { layout(): void {

View File

@ -0,0 +1,75 @@
function getX(ev: MouseEvent | TouchEvent) {
return ev instanceof MouseEvent ? ev.pageX : ev.touches[0].pageX
}
function getY(ev: MouseEvent | TouchEvent) {
return ev instanceof MouseEvent ? ev.pageY : ev.touches[0].pageY
}
type Props = {
scrollable: () => boolean,
onPageSelected?: (index: number) => void
}
export function NestedSliderView(props: Props) {
const ret = document.createElement("div");
ret.style.overflow = "hidden";
ret.style.display = "inline";
ret.style.whiteSpace = "nowrap";
let touch = {
touchStartX: 0,
touchStartY: 0,
currentIndex: 0,
isDragging: false,
horizontal: true
}
ret.ontouchstart = ret.onmousedown = (ev: MouseEvent | TouchEvent) => {
if (!props.scrollable()) return;
touch = {
...touch,
currentIndex: Math.round(ret.scrollLeft / ret.offsetWidth),
touchStartX: getX(ev),
touchStartY: getY(ev),
isDragging: true
}
};
ret.ontouchmove = ret.onmousemove = (ev: MouseEvent | TouchEvent) => {
if (!props.scrollable() || !touch.isDragging) return;
if (!touch.horizontal) {
return
}
if (Math.abs(getX(ev) - touch.touchStartX) < Math.abs(getY(ev) - touch.touchStartY)) {
touch.horizontal = false
return
}
const offsetX = (touch.touchStartX - getX(ev)) * 1.2;
ret.scrollTo({
left: touch.currentIndex * ret.offsetWidth + offsetX,
});
};
ret.onmouseup = ret.ontouchcancel = ret.ontouchend = () => {
if (!props.scrollable()) return;
touch = {
...touch,
isDragging: false,
horizontal: true,
}
let originIndex = touch.currentIndex;
if (Math.abs(ret.scrollLeft - originIndex * ret.offsetWidth) > ret.offsetWidth / 5) {
const positionOffset = Math.abs(ret.scrollLeft) > originIndex * ret.offsetWidth ? 1 : -1;
touch.currentIndex += positionOffset;
}
ret.scrollTo({
left: touch.currentIndex * ret.offsetWidth,
behavior: "smooth",
});
if (originIndex !== touch.currentIndex) {
if (props.onPageSelected) {
props.onPageSelected(touch.currentIndex)
}
}
};
return ret
}