单击时结合拖动和动画拖动位置(动画 x.set())
Combine dragging and animating drag position on click (animate x.set())
对于客户端,我们正在构建水平拖动的媒体项行。使用 Framer-Motion 水平拖动效果很好,但我无法在单击按钮时为 x 位置设置动画。
这是总体思路:
这是我目前拥有的组件(为简洁起见,我删除了样式等):
const HorizontalScroll = ({ children }) => {
const x = useMotionValue(0);
function onLeftClick() {
const xPos = x.get();
if (Math.round(xPos) === 0) {
return;
}
const newXPosition = xPos + 600;
x.set(newXPosition > 0 ? 0 : newXPosition);
}
function onRightClick() {
const xPos = x.get();
const newXPosition = xPos - 600;
x.set(newXPosition < -2000 ? -2000 : newXPosition);
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
style={{ width: 2000, x }}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};
因此,当我向左或向右单击箭头时,我会执行 x.set()
。执行 x.set()
有效,但不是动画。
我可以使用 useSpring
或 useTransform
而不是 const x = useMotionValue(0)
,但这会破坏拖动行为。
简而言之,我想为 x.set()
制作动画,但我不知道该怎么做。有人有想法吗?
我终于发布了我的问题,并在不到一个小时的时间内找到了我自己问题的答案...
以防有人遇到相同的边缘案例问题。我想到的(这绝不是最优雅的解决方案)是使用 useAnimation
。我的组件目前看起来像这样:
const translateXForElement = (element) => {
const transform = element.style.transform;
if (!transform || transform.indexOf('translateX(') < 0) {
return 0;
}
const extractTranslateX = transform.match(/translateX\((-?\d+)/);
return extractTranslateX && extractTranslateX.length === 2
? parseInt(extractTranslateX[1], 10)
: 0;
}
const HorizontalScroll = ({ children }) => {
const dragRef = useRef(null);
const animation = useAnimation();
function onLeftClick() {
const xPos = translateXForElement(dragRef.current);
const newXPosition = xPos + 600;
animation.start({
x: newXPosition > 0 ? 0 : newXPosition,
});
}
function onRightClick() {
const xPos = translateXForElement(dragRef.current);
const newXPosition = xPos - 600;
animation.start({
x: newXPosition < -2000 ? -2000 : newXPosition,
});
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
animate={animation}
style={{ width: 2000, x: 0, opacity: 1 }}
ref={dragRef}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};
我找不到一个(不错的)解决方案来检索元素的当前 translateX
,所以我暂时在 element.style.transform
上做了一个正则表达式。太糟糕了 useAnimation()
不允许检索 x
(或者我遗漏了一些东西)。
当然,如果您对我的代码有任何意见,我很乐意听取!
我发现您可以在变量中跟踪它
const HorizontalScroll = ({ children }) => {
const dragRef = useRef(null);
const xPos = useRef(0);
const animation = useAnimation();
function onLeftClick() {
const newXPosition = xPos.current + 600;
animation.start({
x: newXPosition > 0 ? 0 : newXPosition,
});
}
function onRightClick() {
const newXPosition = xPos.current - 600;
animation.start({
x: newXPosition < -2000 ? -2000 : newXPosition,
});
}
function onUpdate(latest){
xPos.current = latest.x;
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
onUpdate={onUpdate}
animate={animation}
style={{ width: 2000, x: 0, opacity: 1 }}
ref={dragRef}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};
对于客户端,我们正在构建水平拖动的媒体项行。使用 Framer-Motion 水平拖动效果很好,但我无法在单击按钮时为 x 位置设置动画。
这是总体思路:
这是我目前拥有的组件(为简洁起见,我删除了样式等):
const HorizontalScroll = ({ children }) => {
const x = useMotionValue(0);
function onLeftClick() {
const xPos = x.get();
if (Math.round(xPos) === 0) {
return;
}
const newXPosition = xPos + 600;
x.set(newXPosition > 0 ? 0 : newXPosition);
}
function onRightClick() {
const xPos = x.get();
const newXPosition = xPos - 600;
x.set(newXPosition < -2000 ? -2000 : newXPosition);
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
style={{ width: 2000, x }}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};
因此,当我向左或向右单击箭头时,我会执行 x.set()
。执行 x.set()
有效,但不是动画。
我可以使用 useSpring
或 useTransform
而不是 const x = useMotionValue(0)
,但这会破坏拖动行为。
简而言之,我想为 x.set()
制作动画,但我不知道该怎么做。有人有想法吗?
我终于发布了我的问题,并在不到一个小时的时间内找到了我自己问题的答案...
以防有人遇到相同的边缘案例问题。我想到的(这绝不是最优雅的解决方案)是使用 useAnimation
。我的组件目前看起来像这样:
const translateXForElement = (element) => {
const transform = element.style.transform;
if (!transform || transform.indexOf('translateX(') < 0) {
return 0;
}
const extractTranslateX = transform.match(/translateX\((-?\d+)/);
return extractTranslateX && extractTranslateX.length === 2
? parseInt(extractTranslateX[1], 10)
: 0;
}
const HorizontalScroll = ({ children }) => {
const dragRef = useRef(null);
const animation = useAnimation();
function onLeftClick() {
const xPos = translateXForElement(dragRef.current);
const newXPosition = xPos + 600;
animation.start({
x: newXPosition > 0 ? 0 : newXPosition,
});
}
function onRightClick() {
const xPos = translateXForElement(dragRef.current);
const newXPosition = xPos - 600;
animation.start({
x: newXPosition < -2000 ? -2000 : newXPosition,
});
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
animate={animation}
style={{ width: 2000, x: 0, opacity: 1 }}
ref={dragRef}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};
我找不到一个(不错的)解决方案来检索元素的当前 translateX
,所以我暂时在 element.style.transform
上做了一个正则表达式。太糟糕了 useAnimation()
不允许检索 x
(或者我遗漏了一些东西)。
当然,如果您对我的代码有任何意见,我很乐意听取!
我发现您可以在变量中跟踪它
const HorizontalScroll = ({ children }) => {
const dragRef = useRef(null);
const xPos = useRef(0);
const animation = useAnimation();
function onLeftClick() {
const newXPosition = xPos.current + 600;
animation.start({
x: newXPosition > 0 ? 0 : newXPosition,
});
}
function onRightClick() {
const newXPosition = xPos.current - 600;
animation.start({
x: newXPosition < -2000 ? -2000 : newXPosition,
});
}
function onUpdate(latest){
xPos.current = latest.x;
}
return (
<>
<button
type="button"
onClick={onLeftClick}
>
Left
</button>
<motion.div
drag="x"
dragConstraints={{ left: -2000, right: 0 }}
initial={false}
onUpdate={onUpdate}
animate={animation}
style={{ width: 2000, x: 0, opacity: 1 }}
ref={dragRef}
>
{children}
</motion.div>
<button
type="button"
onClick={onRightClick}
>
Right
</button>
</>
);
};