import {
Override,
Data,
motionValue,
useTransform,
transform,
useAnimation,
useCycle,
} from "framer";
// ts-ignore
import { cloneElement } from "react";
const data = Data({
toggle: true,
text: "交互事件",
currentIndicator: 0,
loading: "false",
});
// 除了更改文字内容,其他override要作用在frame元素上。
/*
关于 Tap 事件
whileTap: 当元素被 手指/鼠标 按下时改变动画的属性
onTapStart: 在被点击的元素上开始轻击手势时进行的回调
onTap: 当轻击手势成功结束时还在此元素上进行回调
onTapCancle: 当轻击手势结束于此元素之外时进行回调
event: MouseEvent | TouchEvent | PointerEvent
*/
export function TapEvent(): Override {
return {
whileTap: {
scale: 1.2,
},
onTapStart(event, info) {
console.log(
"onTapStart:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onTapStart");
},
onTap(event, info) {
console.log(
"onTap:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onTap");
},
onTapCancel(event, info) {
console.log(
"onTapCancle:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onTapCancle");
},
};
}
/*
关于 Hover 事件
whileHover: 当鼠标悬浮在元素上改变动画的属性
onHoverStart: 当鼠标悬浮在元素上产生回调
onHoverEnd:当鼠标悬浮在元素上然后离开产生回调
event: MouseEvent
*/
export function HoverEvent(): Override {
return {
whileHover: {
scale: 1.2,
},
onHoverStart(event, info) {
console.log(
"onHoverStart:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
);
},
onHoverEnd(event, info) {
console.log(
"onHoverEnd:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
);
},
};
}
/*
关于 pan 事件
The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels.
The pan gesture is ended when the pointer is released.
onPan: the pan gesture is recognised on this element.
onPanStart: the pan gesture begins on this element.
onPanEnd: the pan gesture ends on this element.
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo
A PanInfo object containing x and y values for:
point: Relative to the device or page.
delta: Distance moved since the last event.
offset: Offset from the original pan event.
velocity: Current velocity of the pointer.
*/
export function PanEvent(): Override {
return {
onPanStart(event, info) {
console.log(
"onPanStart:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onPanStart");
},
onPan(event, info) {
console.log(
"onPan:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onPan");
},
onPanEnd(event, info) {
console.log(
"onPanEnd:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onPanEnd");
},
};
}
/*
关于 Drag 事件
The drag gesture follows the rules of the pan gesture but
applies pointer movement to the x and/or y axis of the component.
onDrag: fires when the component is dragged.
onDragStart: fires when dragging starts.
onDragEnd: fires when dragging ends.
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo
A PanInfo object containing x and y values for:
point: Relative to the device or page.
delta: Distance moved since the last event.
offset: Offset from the original pan event.
velocity: Current velocity of the pointer.
*/
export function DragEvent(): Override {
return {
drag: true, // boolean | "x" | "y"
dragConstraints: { left: 0, right: 0, top: 0, bottom: 0 }, // Applies constraints on the permitted draggable area. "left" | "right" | "top" | "bottom"
dragElastic: 0.6, //boolean | number ,The degree of movement allowed outside constraints.0 = no movement, 1 = full movement. Set to 0.5 by default.
dragTransition: { bounceStiffness: 600, bounceDamping: 20 },
dragMomentum: true, //true default
dragDirectionLock: true, //true or false
dragPropagation: false, // false default
//
onDragStart(event, info) {
console.log(
"onDragStart:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onDragStart");
},
onDrag(event, info) {
console.log(
"onDrag:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onDrag");
},
onDragEnd(event, info) {
console.log(
"onDragEnd:",
"pointX",
info.point.x,
"pointX",
info.point.y,
event.isTrusted
),
(data.text = "onDragEnd");
},
};
}
/*
关于 Scroll 事件
onScroll: fires when the component is Scrollged.
onScrollStart: fires when Scrollging starts.
onScrollEnd: fires when Scrollging ends.
event: MouseEvent | TouchEvent | PointerEvent
info: PanInfo
A PanInfo object containing x and y values for:
point: Relative to the device or page.
delta: Distance moved since the last event.
offset: Offset from the original pan event.
velocity: Current velocity of the pointer.
*/
export function ScrollEvent(): Override {
const scrollY = motionValue(0);
scrollY.onChange((point) => {
console.log(point);
});
return {
contentOffsetY: scrollY,
onScrollStart(info) {
console.log(
"onScrollStart:",
"pointX",
info.point.x,
"pointX",
info.point.y
),
(data.text = "onScrollStart");
},
onScroll(info) {
// console.log("onScroll:","pointX",info.offset.x,"scrollY",info.offset.y),
data.text = "onScroll";
},
onScrollEnd(info) {
console.log(
"onScrollEnd:",
"pointX",
info.point.x,
"pointX",
info.point.y
),
(data.text = "onScrollEnd");
},
};
}
export function ScrollRefresh(): Override {
const controls = useAnimation();
const scrollY = motionValue(0);
const transition = {
duration: 0.2,
ease: [0.3, 0.0, 0.1, 1.0],
};
return {
contentOffsetY: scrollY,
// Only enable drag when the spinner is not loading
dragEnabled: data.loading === "false",
// When the layer has been dragged past a certain point, begin the loading animation
onPanEnd() {
if (data.loading === "false" && scrollY.get() > 116) {
// Keep the layer pinned at 116px from the top while loading
data.loading = "true";
controls.start({ y: 116 });
// When the animation is complete, animate the layer back to the top and set the loading state to false
setTimeout(() => {
data.loading = "false";
controls.start({ y: 0, transition: transition });
}, 1500);
} else {
controls.start({ y: 0 });
}
},
scrollAnimate: controls,
};
}
/*
关于Page组件
这个函数只用于Page组件
*/
export function Page(): Override {
return {
onChangePage(current, previous) {
data.currentIndicator = current;
},
};
}
// 这个用于通过index控制很多元素相同的字组件的属性,一般和Page组件相关
export function sameItemGroup(props): Override {
return {
children: props.children.map((indicator, index) => {
let opacity = 0.3;
if (index === data.currentIndicator) {
opacity = 1;
}
return cloneElement(indicator, {
animate: { opacity: opacity },
});
}),
};
}
export function Page_Effects(): Override {
return {
gap: 0,
effect(info) {
const offset = info.normalizedOffset;
const opacity = transform(offset, [-1, 0, 1], [0.4, 1, 0.4]);
const scale = transform(offset, [-1, 0, 1], [0.5, 1, 0.5]);
const x = transform(offset, [-1, 0, 1], [20, 0, -20]);
return { opacity, scale, x };
},
};
}
// 属性大全
export function VisualStyle(): Override {
return {
visible: true,
text: "",
originX: 0.5,
originY: 1,
originZ: 0.1,
animate: {
// basic
width: 100,
height: 100,
opacity: 0.8,
background: "#09D", // "#09F" |
border: "1px solid #000",
radius: 20,
shadow: "10px 5px 5px rgba(0,0,0,0.1)",
// transform
x: 1,
y: 1,
z: 1,
rotate: 20,
rotateX: 10,
rotateY: 10,
rotateZ: 10,
scale: 1.2,
scaleX: 1.3,
scaleY: 1.3,
skew: 15,
skewX: 13,
skewY: 14,
perspective: 500,
},
onUpdate(latest) {
console.log(latest.width, latest.height); //这里可以调用animate中变化的元素的实时的值
},
onAnimationStart() {
console.log("animation start");
},
onAnimationComplete() {
console.log("Animation completed");
},
};
}
// animation controls 这种用于一次性改变多个属性 或者是序列动画
/*
Supported Value Types
Numbers
Strings
All Unit Types (px, %, calc(), etc.)
Colors (hex, rgba, hsla)
Complex Values (Strings with numbers and colors)
x, y, z
rotate, rotateX, rotateY, rotateZ
scale, scaleX, scaleY, scaleZ
skewX, skewY
originX, originY
perspective
*/
export function Animation_controls(): Override {
const controls = useAnimation();
async function sequence() {
await controls.start({
x: 60,
backgroundColor: "#f00",
transition: { duration: 3 },
});
await controls.start({
x: -20,
backgroundColor: "rgb(217, 15, 224)",
transition: { duration: 2 },
});
}
return {
animate: controls,
onTap() {
sequence();
},
};
}
// useCycle 循环多种状态
export function UseCycle(): Override {
const variants = {
green: { background: "#1ea463" },
yellow: { background: "#fecd45" },
red: { background: "#de5347" },
};
const [current, cycle] = useCycle("green", "yellow", "red");
return {
variants: variants,
animate: current,
onTap() {
cycle();
},
};
}
export function Text(): Override {
return {
textContent: data.text,
};
}