1. import {
    2. Override,
    3. Data,
    4. motionValue,
    5. useTransform,
    6. transform,
    7. useAnimation,
    8. useCycle,
    9. } from "framer";
    10. // ts-ignore
    11. import { cloneElement } from "react";
    12. const data = Data({
    13. toggle: true,
    14. text: "交互事件",
    15. currentIndicator: 0,
    16. loading: "false",
    17. });
    18. // 除了更改文字内容,其他override要作用在frame元素上。
    19. /*
    20. 关于 Tap 事件
    21. whileTap: 当元素被 手指/鼠标 按下时改变动画的属性
    22. onTapStart: 在被点击的元素上开始轻击手势时进行的回调
    23. onTap: 当轻击手势成功结束时还在此元素上进行回调
    24. onTapCancle: 当轻击手势结束于此元素之外时进行回调
    25. event: MouseEvent | TouchEvent | PointerEvent
    26. */
    27. export function TapEvent(): Override {
    28. return {
    29. whileTap: {
    30. scale: 1.2,
    31. },
    32. onTapStart(event, info) {
    33. console.log(
    34. "onTapStart:",
    35. "pointX",
    36. info.point.x,
    37. "pointX",
    38. info.point.y,
    39. event.isTrusted
    40. ),
    41. (data.text = "onTapStart");
    42. },
    43. onTap(event, info) {
    44. console.log(
    45. "onTap:",
    46. "pointX",
    47. info.point.x,
    48. "pointX",
    49. info.point.y,
    50. event.isTrusted
    51. ),
    52. (data.text = "onTap");
    53. },
    54. onTapCancel(event, info) {
    55. console.log(
    56. "onTapCancle:",
    57. "pointX",
    58. info.point.x,
    59. "pointX",
    60. info.point.y,
    61. event.isTrusted
    62. ),
    63. (data.text = "onTapCancle");
    64. },
    65. };
    66. }
    67. /*
    68. 关于 Hover 事件
    69. whileHover: 当鼠标悬浮在元素上改变动画的属性
    70. onHoverStart: 当鼠标悬浮在元素上产生回调
    71. onHoverEnd:当鼠标悬浮在元素上然后离开产生回调
    72. event: MouseEvent
    73. */
    74. export function HoverEvent(): Override {
    75. return {
    76. whileHover: {
    77. scale: 1.2,
    78. },
    79. onHoverStart(event, info) {
    80. console.log(
    81. "onHoverStart:",
    82. "pointX",
    83. info.point.x,
    84. "pointX",
    85. info.point.y,
    86. event.isTrusted
    87. );
    88. },
    89. onHoverEnd(event, info) {
    90. console.log(
    91. "onHoverEnd:",
    92. "pointX",
    93. info.point.x,
    94. "pointX",
    95. info.point.y,
    96. event.isTrusted
    97. );
    98. },
    99. };
    100. }
    101. /*
    102. 关于 pan 事件
    103. The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels.
    104. The pan gesture is ended when the pointer is released.
    105. onPan: the pan gesture is recognised on this element.
    106. onPanStart: the pan gesture begins on this element.
    107. onPanEnd: the pan gesture ends on this element.
    108. event: MouseEvent | TouchEvent | PointerEvent
    109. info: PanInfo
    110. A PanInfo object containing x and y values for:
    111. point: Relative to the device or page.
    112. delta: Distance moved since the last event.
    113. offset: Offset from the original pan event.
    114. velocity: Current velocity of the pointer.
    115. */
    116. export function PanEvent(): Override {
    117. return {
    118. onPanStart(event, info) {
    119. console.log(
    120. "onPanStart:",
    121. "pointX",
    122. info.point.x,
    123. "pointX",
    124. info.point.y,
    125. event.isTrusted
    126. ),
    127. (data.text = "onPanStart");
    128. },
    129. onPan(event, info) {
    130. console.log(
    131. "onPan:",
    132. "pointX",
    133. info.point.x,
    134. "pointX",
    135. info.point.y,
    136. event.isTrusted
    137. ),
    138. (data.text = "onPan");
    139. },
    140. onPanEnd(event, info) {
    141. console.log(
    142. "onPanEnd:",
    143. "pointX",
    144. info.point.x,
    145. "pointX",
    146. info.point.y,
    147. event.isTrusted
    148. ),
    149. (data.text = "onPanEnd");
    150. },
    151. };
    152. }
    153. /*
    154. 关于 Drag 事件
    155. The drag gesture follows the rules of the pan gesture but
    156. applies pointer movement to the x and/or y axis of the component.
    157. onDrag: fires when the component is dragged.
    158. onDragStart: fires when dragging starts.
    159. onDragEnd: fires when dragging ends.
    160. event: MouseEvent | TouchEvent | PointerEvent
    161. info: PanInfo
    162. A PanInfo object containing x and y values for:
    163. point: Relative to the device or page.
    164. delta: Distance moved since the last event.
    165. offset: Offset from the original pan event.
    166. velocity: Current velocity of the pointer.
    167. */
    168. export function DragEvent(): Override {
    169. return {
    170. drag: true, // boolean | "x" | "y"
    171. dragConstraints: { left: 0, right: 0, top: 0, bottom: 0 }, // Applies constraints on the permitted draggable area. "left" | "right" | "top" | "bottom"
    172. dragElastic: 0.6, //boolean | number ,The degree of movement allowed outside constraints.0 = no movement, 1 = full movement. Set to 0.5 by default.
    173. dragTransition: { bounceStiffness: 600, bounceDamping: 20 },
    174. dragMomentum: true, //true default
    175. dragDirectionLock: true, //true or false
    176. dragPropagation: false, // false default
    177. //
    178. onDragStart(event, info) {
    179. console.log(
    180. "onDragStart:",
    181. "pointX",
    182. info.point.x,
    183. "pointX",
    184. info.point.y,
    185. event.isTrusted
    186. ),
    187. (data.text = "onDragStart");
    188. },
    189. onDrag(event, info) {
    190. console.log(
    191. "onDrag:",
    192. "pointX",
    193. info.point.x,
    194. "pointX",
    195. info.point.y,
    196. event.isTrusted
    197. ),
    198. (data.text = "onDrag");
    199. },
    200. onDragEnd(event, info) {
    201. console.log(
    202. "onDragEnd:",
    203. "pointX",
    204. info.point.x,
    205. "pointX",
    206. info.point.y,
    207. event.isTrusted
    208. ),
    209. (data.text = "onDragEnd");
    210. },
    211. };
    212. }
    213. /*
    214. 关于 Scroll 事件
    215. onScroll: fires when the component is Scrollged.
    216. onScrollStart: fires when Scrollging starts.
    217. onScrollEnd: fires when Scrollging ends.
    218. event: MouseEvent | TouchEvent | PointerEvent
    219. info: PanInfo
    220. A PanInfo object containing x and y values for:
    221. point: Relative to the device or page.
    222. delta: Distance moved since the last event.
    223. offset: Offset from the original pan event.
    224. velocity: Current velocity of the pointer.
    225. */
    226. export function ScrollEvent(): Override {
    227. const scrollY = motionValue(0);
    228. scrollY.onChange((point) => {
    229. console.log(point);
    230. });
    231. return {
    232. contentOffsetY: scrollY,
    233. onScrollStart(info) {
    234. console.log(
    235. "onScrollStart:",
    236. "pointX",
    237. info.point.x,
    238. "pointX",
    239. info.point.y
    240. ),
    241. (data.text = "onScrollStart");
    242. },
    243. onScroll(info) {
    244. // console.log("onScroll:","pointX",info.offset.x,"scrollY",info.offset.y),
    245. data.text = "onScroll";
    246. },
    247. onScrollEnd(info) {
    248. console.log(
    249. "onScrollEnd:",
    250. "pointX",
    251. info.point.x,
    252. "pointX",
    253. info.point.y
    254. ),
    255. (data.text = "onScrollEnd");
    256. },
    257. };
    258. }
    259. export function ScrollRefresh(): Override {
    260. const controls = useAnimation();
    261. const scrollY = motionValue(0);
    262. const transition = {
    263. duration: 0.2,
    264. ease: [0.3, 0.0, 0.1, 1.0],
    265. };
    266. return {
    267. contentOffsetY: scrollY,
    268. // Only enable drag when the spinner is not loading
    269. dragEnabled: data.loading === "false",
    270. // When the layer has been dragged past a certain point, begin the loading animation
    271. onPanEnd() {
    272. if (data.loading === "false" && scrollY.get() > 116) {
    273. // Keep the layer pinned at 116px from the top while loading
    274. data.loading = "true";
    275. controls.start({ y: 116 });
    276. // When the animation is complete, animate the layer back to the top and set the loading state to false
    277. setTimeout(() => {
    278. data.loading = "false";
    279. controls.start({ y: 0, transition: transition });
    280. }, 1500);
    281. } else {
    282. controls.start({ y: 0 });
    283. }
    284. },
    285. scrollAnimate: controls,
    286. };
    287. }
    288. /*
    289. 关于Page组件
    290. 这个函数只用于Page组件
    291. */
    292. export function Page(): Override {
    293. return {
    294. onChangePage(current, previous) {
    295. data.currentIndicator = current;
    296. },
    297. };
    298. }
    299. // 这个用于通过index控制很多元素相同的字组件的属性,一般和Page组件相关
    300. export function sameItemGroup(props): Override {
    301. return {
    302. children: props.children.map((indicator, index) => {
    303. let opacity = 0.3;
    304. if (index === data.currentIndicator) {
    305. opacity = 1;
    306. }
    307. return cloneElement(indicator, {
    308. animate: { opacity: opacity },
    309. });
    310. }),
    311. };
    312. }
    313. export function Page_Effects(): Override {
    314. return {
    315. gap: 0,
    316. effect(info) {
    317. const offset = info.normalizedOffset;
    318. const opacity = transform(offset, [-1, 0, 1], [0.4, 1, 0.4]);
    319. const scale = transform(offset, [-1, 0, 1], [0.5, 1, 0.5]);
    320. const x = transform(offset, [-1, 0, 1], [20, 0, -20]);
    321. return { opacity, scale, x };
    322. },
    323. };
    324. }
    325. // 属性大全
    326. export function VisualStyle(): Override {
    327. return {
    328. visible: true,
    329. text: "",
    330. originX: 0.5,
    331. originY: 1,
    332. originZ: 0.1,
    333. animate: {
    334. // basic
    335. width: 100,
    336. height: 100,
    337. opacity: 0.8,
    338. background: "#09D", // "#09F" |
    339. border: "1px solid #000",
    340. radius: 20,
    341. shadow: "10px 5px 5px rgba(0,0,0,0.1)",
    342. // transform
    343. x: 1,
    344. y: 1,
    345. z: 1,
    346. rotate: 20,
    347. rotateX: 10,
    348. rotateY: 10,
    349. rotateZ: 10,
    350. scale: 1.2,
    351. scaleX: 1.3,
    352. scaleY: 1.3,
    353. skew: 15,
    354. skewX: 13,
    355. skewY: 14,
    356. perspective: 500,
    357. },
    358. onUpdate(latest) {
    359. console.log(latest.width, latest.height); //这里可以调用animate中变化的元素的实时的值
    360. },
    361. onAnimationStart() {
    362. console.log("animation start");
    363. },
    364. onAnimationComplete() {
    365. console.log("Animation completed");
    366. },
    367. };
    368. }
    369. // animation controls 这种用于一次性改变多个属性 或者是序列动画
    370. /*
    371. Supported Value Types
    372. Numbers
    373. Strings
    374. All Unit Types (px, %, calc(), etc.)
    375. Colors (hex, rgba, hsla)
    376. Complex Values (Strings with numbers and colors)
    377. x, y, z
    378. rotate, rotateX, rotateY, rotateZ
    379. scale, scaleX, scaleY, scaleZ
    380. skewX, skewY
    381. originX, originY
    382. perspective
    383. */
    384. export function Animation_controls(): Override {
    385. const controls = useAnimation();
    386. async function sequence() {
    387. await controls.start({
    388. x: 60,
    389. backgroundColor: "#f00",
    390. transition: { duration: 3 },
    391. });
    392. await controls.start({
    393. x: -20,
    394. backgroundColor: "rgb(217, 15, 224)",
    395. transition: { duration: 2 },
    396. });
    397. }
    398. return {
    399. animate: controls,
    400. onTap() {
    401. sequence();
    402. },
    403. };
    404. }
    405. // useCycle 循环多种状态
    406. export function UseCycle(): Override {
    407. const variants = {
    408. green: { background: "#1ea463" },
    409. yellow: { background: "#fecd45" },
    410. red: { background: "#de5347" },
    411. };
    412. const [current, cycle] = useCycle("green", "yellow", "red");
    413. return {
    414. variants: variants,
    415. animate: current,
    416. onTap() {
    417. cycle();
    418. },
    419. };
    420. }
    421. export function Text(): Override {
    422. return {
    423. textContent: data.text,
    424. };
    425. }