官网API地址
Frame
Layout(大小位置)
width={100}
height={100}
size={100} //同时设置宽度和高度的快捷方式。
top={100}
left={100}
right={100}
bottom={100}
center=“x”/center=“y”/center //快速居中
position={“relative”}
Visual(样式)
style={{width:100px}} //样式也可以用styled-components
visible={false}
opacity={0.5}
//以下是background
background=“#09F” //色值
backgroundColor="#09F"
background={Color({r: 255, g: 0, b: 102})} //RGB
backgroundColor={Color({r: 255, g: 0, b: 102})}
background={{ alpha: 1, angle: 75, start: "#09F", end: "#F09"}} //渐变
background={{ src: "https://example.com/logo.png"}} //URL
image="https://source.unsplash.com/random"
border="1px solid #09F"
radius={10}
shadow="10px 5px 5px black"
overflow="hidden"
Transfrom (变化)
x={100}
y={100}
z={100}
rotate={45}
rotateX={45}
rotateY={45}
rotateZ={45}
scale={1.5}
scaleX={1.5}
scaleY={2}
skew={15}
skewX={15}
skewY={15}
originX={0.5}
originY={0.5}
originZ={100}
perspective={500} //镜头距离元素表面的位置
preserve3d={true}
交互事件
Animation
支持动画的类型
Value
Numbers
Strings
All Unit Types (px, %, calc(), etc.)
Colors (hex, rgba, hsla)
Complex Values (Strings with numbers and colors)
//animate Complex Values
For instance, "5px 10px #333" can be animated to "0px 0px #333"
but not "0 0 #333".
transfroms
x, y, z
rotate, rotateX, rotateY, rotateZ
scale, scaleX, scaleY, scaleZ
skewX, skewY
originX, originY
perspective
Value Conversion
x
y
width
height
top
left
right
bottom
//数值运算
calc()最大的好处就是用在流体布局上,可以通过calc()计算得到元素的宽度。著作权归作者所有。
语法:width: calc(expression);
calc()语法非常简单,就像我们小时候学加 (+)、减(-)、乘(*)、除(/)一样,使用数学表达式来表示:著作权归作者所有。
vw:视窗宽度的百分比(1vw 代表视窗的宽度为 1%)
vh:视窗高度的百分比
vmin:当前 vw 和 vh 中较小的一个值
vmax:当前 vw 和 vh 中较大的一个值
2、vw、vh与%百分比的区别
(1)% 是相对于父元素的大小设定的比率,vw、vh 是视窗大小决定的。
(2)vw、vh 优势在于能够直接获取高度,而用 % 在没有设置 body 高度的情况下,是无法正确获得可视区域的高度的,所以这是挺不错的优势。
3、vmin、vmax用处
做移动页面开发时,如果使用 vw、wh 设置字体大小(比如 5vw),在竖屏和横屏状态下显示的字体大小是不一样的。
由于 vmin 和 vmax 是当前较小的 vw 和 vh 和当前较大的 vw 和 vh。这里就可以用到 vmin 和 vmax。使得文字大小在横竖屏下保持一致。
Transition-动画曲线
Easing-curve
custom cubic
Spring-curves
Page
stack
这里的话,stack主要是可以自动间距。在画布中设计好,我仔细看了一下,可以通过Override控制的属性是stack里面的单个元素的visible,某一个元素删除之后,其他的元素会跟上来。
应用场景:列表删除
import { Override, Data } from "framer"
const data = Data({
visible:true
})
export function None():Override{
return{
visible:data.visible,
}
}
export function Button():Override{
return{
onTap(){data.visible = false}
}
}
Utilities
useAnimation
用这个可以创建一组连续的动画
import { Override, useAnimation } from "framer"
// Override Docs: https://framer.com/docs/overrides
export function Event_Sequence(): Override {
const animation = useAnimation()
async function sequence() {
await animation.start({ rotate: -90 })
await animation.start({ scale: 1.5 })
await animation.start({ rotate: 0 })
await animation.start({ scale: 1 })
}
return {
animate: animation,
onTap() {
sequence()
},
}
}
案例1:微信好友列表效果模仿
好友列表主要通过Drag事件,来控制消息提醒和删除效果。
主要难点:
- controls组件外声明,这样其他组件也可以参与控制。类似Data,但是强于Data的操作。
- property = condition ? valueWhenTrue : valueWhenFalse 通过布尔状态控制,来达到效果。消息提示用到这个了
视频展示:
import { Override, useTransform, useAnimation, motionValue, Data } from "framer"
//定义设计组件的三个隐藏功能模块的宽度
const data = Data({
redWidth: "",
blueWidth: "",
greyWidth: "", //功能菜单的总宽度
remindOpacity: true,
redDeleteX: 0,
listVisiable: true,
})
//因为对象在被拖动时,X的值是motionValue(这个是object,不是数字)
//X向右移动为正,向左移动为负
const x = motionValue(0)
let controls
//这里用let声明controls,其他任何override都可以控制controls的状态,妙啊
export function Drag(props): Override {
// console.log(data.dragOpened)
controls = useAnimation()
function handleDragToRight() {
//功能菜单隐藏
controls.start({ x: 0, transition: { duration: 0.25 } })
data.redDeleteX = 0
}
function handleDragToLeft() {
//功能菜单显示
controls.start({ x: -data.greyWidth, transition: { duration: 0.25 } })
}
return {
drag: "x",
dragConstraints: {
right: 0,
left: -data.greyWidth,
},
x: x,
animate: controls,
onDragEnd(event, info) {
//获取X的值,Math的方法可以使获得的值(浮点数:有很多小数)变为整数
//因为浮点数(1.353453)和整数(4234)无法做比较
const positionX = Math.floor(info.point.x * 1) / 1
// console.log(positionX)
//获取拖动object时的速度值
const velocityX = Math.floor(info.velocity.x * 1) / 1
// console.log(velocityX)
if (positionX < 0 && positionX > -data.greyWidth * 0.5) {
handleDragToRight()
} else if (
positionX < -data.greyWidth * 0.5 &&
positionX > -data.greyWidth
) {
handleDragToLeft()
}
if (velocityX > 10) {
handleDragToRight()
} else if (velocityX < -10) {
handleDragToLeft()
}
},
onTap(event, info) {
const pointX = Math.floor(info.point.x * 1) / 1
if (pointX < 118) {
handleDragToRight()
}
},
}
}
export function Grey(props): Override {
//获取设计组件greyWidth的宽度
data.greyWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-props.width, 0], {
clamp: false,
})
return {
x: dragX,
onTap() {
;(data.remindOpacity = !data.remindOpacity),
controls.start({
x: 0,
transition: { duration: 0.25 },
})
},
text: data.remindOpacity ? "标记已读" : "标为未读",
//property = condition ? valueWhenTrue : valueWhenFalse
}
}
export function Blue(props): Override {
//获取设计组件blueWidth的宽度
data.blueWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-props.width, 0], {
clamp: false,
})
return {
x: dragX,
}
}
export function Red(props): Override {
//获取设计组件redWidth的宽度
data.redWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-62, 0], {
clamp: false,
})
return {
onTap() {
data.redDeleteX = -157
},
x: dragX,
}
}
//redDeleteX
export function RedDelete(): Override {
return {
animate: { x: data.redDeleteX, transition: { duration: 0.3 } },
onTap() {
data.listVisiable = false
},
}
}
//列表整体
export function List(): Override {
return {
visible: data.listVisiable,
}
}
//remind的透明度
export function Remind(props): Override {
return {
opacity: data.remindOpacity ? 1 : 0,
//property = condition ? valueWhenTrue : valueWhenFalse
animate: { transition: { duration: 0.2 } },
}
}
useTransform
案例1
这个是由useMotionValue, useTransform,一起弄的。应用场景应该是drag,scroll 这种能手动控制实时变化的元素。核心要义就是可以把一组变化的数值的效果,应用到另一种要变化的数值。听起来可能有点绕口,就比如下面的这个这个效果。通过拖动,来改变小方块的x值,然后通过X值的改变再改变,rotate 和
scale的值。这种是实时的。
import { Override, useMotionValue, useTransform } from "framer"
// Override Docs: https://framer.com/docs/overrides
export function Drag_3D(): Override {
const x = useMotionValue(0)
const y = useMotionValue(0)
const rotateX = useTransform(x, [-100, 100], [-60, 60])
const rotateY = useTransform(y, [-100, 100], [60, -60])
return {
x: x,
y: y,
drag: true,
dragConstraints: { left: 0, top: 0, right: 0, bottom: 0 },
rotateY: rotateX,
rotateX: rotateY,
dragElastic: 0.6,
}
}
export function Radial_Gradient(): Override {
return {
background:
"radial-gradient(rgba(255,255,255,0), rgba(255,255,255,0.3))",
}
}
案例2
通过左右拖动,实时改变背景颜色
import { Override, useTransform, motionValue, transform } from "framer"
// Override Docs: https://framer.com/docs/overrides
const x = motionValue(0)
export function Background(): Override {
const background = useTransform(x, [-100, 0, 100], ["#80F", "#40F", "#0BF"])
return {
background: background,
}
}
export function Frame(): Override {
return {
drag: "x",
dragConstraints: {
right: 0,
left: 0,
},
x: x,
}
}
案例3
知识点:
在Drag的过程中,通过Drag的X值来改变其他的X值。
Framer 库:
Override, useTransform, useAnimation, motionValue, Data
动效分析:
- 当从右往左拖动时,拖动的速度值达到一定值的时候,Drag的X值会变为最大值(灰色色块的width),此时功能栏会全部显示。
- 当从右往左拖动时,拖动的速度值没有达到一定值的时候,且距离小于特定X值时,Drag的X值会变为0,功能栏隐藏;X大于特定的值的时候,Drag的X值会变为最大,功能栏显示。
从右往左拖动,同理。
源文件:
支付宝拖动删除的效果.zip在线演示链接 🙈
import { Override, useTransform, useAnimation, motionValue, Data } from "framer"
//定义设计组件的三个隐藏功能模块的宽度
const data = Data({
redWidth: "",
blueWidth: "",
greyWidth: "", //功能菜单的总宽度
})
//因为对象在被拖动时,X的值是motionValue(这个是object,不是数字)
//X像右移动为正,向左移动为负
const x = motionValue(0)
export function Drag(): Override {
const controls = useAnimation()
function handleDragToRight() {
//功能菜单隐藏
controls.start({ x: 0, transition: { duration: 0.25 } })
}
function handleDragToLeft() {
//功能菜单显示
controls.start({ x: -data.greyWidth, transition: { duration: 0.25 } })
}
return {
drag: "x",
dragConstraints: {
right: 0,
left: -data.greyWidth,
},
x: x,
animate: controls,
onDragEnd(event, info) {
//获取X的值,Math的方法可以使获得的值(浮点数:有很多小数)变为整数
//因为浮点数(1.353453)和整数(4234)无法做比较
const positionX = Math.floor(info.point.x * 1) / 1
//获取拖动object时的速度值
const velocityX = Math.floor(info.velocity.x * 1) / 1
// console.log(velocityX)
if (positionX < 0 && positionX > -data.redWidth * 1.5) {
handleDragToRight()
} else if (
positionX < -data.redWidth * 1.5 &&
positionX > -data.greyWidth
) {
handleDragToLeft()
}
if (velocityX > 10) {
handleDragToRight()
} else if (velocityX < -10) {
handleDragToLeft()
}
},
}
}
export function Grey(props): Override {
//获取设计组件greyWidth的宽度
data.greyWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-props.width, 0])
return {
x: dragX,
}
}
export function Blue(props): Override {
//获取设计组件blueWidth的宽度
data.blueWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-props.width, 0])
return {
x: dragX,
}
}
export function Red(props): Override {
//获取设计组件redWidth的宽度
data.redWidth = props.width
const dragX = useTransform(x, [-data.greyWidth, 0], [-props.width, 0])
return {
x: dragX,
}
}
案例4:卡片拖拽删除效果
这个案例中大量的使用了联动操作,
视频演示:
源文件:card.framerx.zip
代码展示:
import { Override, Data, motionValue, useTransform, useAnimation } from "framer"
const data = Data({
//card1
boxShadow: "0px 12px 24px 300px rgba(148, 148, 148, 0.25)",
isDeleted: false,
visible: true,
isDeletedRight: false,
})
//card 1
const x = motionValue(0)
let controls1
export function Card1(): Override {
const rotate = useTransform(x, [-70, 0, 70], [-8, 0, 8])
function MoveToRight() {
controls1.start({ x: 400 })
controls2.start({ opacity: 1, width: 327, y: 18 })
animation.start({ width: 294, y: 18 })
//我这里是对的,但是他会不定时报错,不过,不影响使用。
}
function MoveToLeft() {
controls1.start({ x: -400 })
controls2.start({ opacity: 1, width: 327, y: 18 })
animation.start({ width: 294, y: 18 })
}
//useAnimation
controls1 = useAnimation()
return {
drag: "x",
dragConstraints: {
right: 0,
left: 0,
},
x: x,
rotate: rotate,
animate: controls1,
boxShadow: data.boxShadow,
// boxShadow:data.boxShadow,
onDragEnd(event, info) {
const positionX = Math.floor(info.point.x * 1) / 1
const velocityX = Math.floor(info.velocity.x * 1) / 1
//位置条件判断
if (positionX > 100) {
; (data.isDeleted = true), (data.isDeletedRight =true), MoveToRight()
} else if (positionX < -100) {
;(data.isDeleted = true), MoveToLeft()
}
//速度条件判断
if (velocityX > 40) {
MoveToRight()
} else if (velocityX < -40) {
MoveToLeft()
}
},
onDrag(event, info) {
const positionX1 = Math.floor(info.point.x * 1) / 1
console.log(positionX1)
if (positionX1 > 0) {
data.boxShadow =
"-24px 12px 24px 300px rgba(148, 148, 148, 0.55)"
} else if (positionX1 < 0) {
data.boxShadow =
"24px 12px 24px 300px rgba(148, 148, 148, 0.55)"
}
},
}
}
//card 2
let controls2
export function Card2(): Override {
//useTransfrom
const moveX = 400
const opacity = useTransform(x, [-0.3 * moveX, 0, 0.3 * moveX], [1, 0.6, 1])
const width = useTransform(x, [-moveX, 0, moveX], [327, 294, 327])
const y = useTransform(x, [-moveX, -200, 0, 200, moveX], [18, 0, 0, 0, 18])
//useAnimation
controls2 = useAnimation()
return {
opacity: opacity,
width: width,
y: y,
aniamte: controls2,
transition: { duration: 0.75 },
}
}
//card 3
let animation
export function Card3(): Override {
//useTransfrom
const moveX = 400
const width = useTransform(x, [-moveX, 0, moveX], [294, 262, 294])
const y = useTransform(x, [-moveX, -200, 0, 200, moveX], [18, 0, 0, 0, 18])
//useAnimation
const animation = useAnimation()
return {
width: width,
y: y,
aniamte: animation,
transition: { duration: 0.75 },
}
}
//Card 4
export function Card4(): Override {
return {
y: 0,
opacity: 0,
animate: data.isDeleted
? { y: -18, opacity: 0.6 }
: { y: 0, opacity: 0 },
transition: { duration: 0.35 },
}
}
//以下是下面两个小按钮的动效部分
const x0 = 3
const x1 = 5
const x2 = 6
const x3 = 9 //白色like出现
const x4 = 60
const x5 = 85
const x6 = 104
const x7 = 115
const x8 = 127
const x9 = 320
// const x10 = 30
//以下是右边的按钮的部分
//whiteContent
export function whiteContent(): Override {
const scale = useTransform(x, [0, x6,x9], [1, 1.4,1])
return {
scale: scale,
}
}
//likeIconGreen
export function likeIconGreen(): Override {
const scale = useTransform(x, [0, x1,x6+1], [1, 0,1])
return {
scale: scale,
}
}
//whiteLike
export function whiteLike(): Override {
//useTransform
const opacity = useTransform(x, [x2, x3,x7,x8], [0, 1, 1,0])
const scale = useTransform(x, [x1,x4, x5], [0.2, 1.1, 1.5])
//useAnimation
return {
opacity: opacity,
scale: scale,
}
}
//greenCircle
export function greenCircle(): Override {
const scale = useTransform(x, [0, x0, x1, x6,x9], [0, 0, 0.1, 1.4,1])
return {
scale: scale,
}
}
//whiteCircle
export function whiteCircle(): Override {
const opacity = useTransform(x, [x6,x6+1], [0, 1])
const scale = useTransform(x,[x6,x9],[0,1])
return {
opacity: opacity,
scale:scale
}
}
//Plus
export function Plus(): Override {
return {
animate: {
y: data.isDeletedRight ? -60 : 0,
opacity: data.isDeletedRight ? 0 : 1,
},
transiton: {
duration: 0.35,
},
}
}
//以下是左边的按钮的部分
//whiteContent
export function whiteContentLeft(): Override {
const scale = useTransform(x, [0, -x6,-x9], [1, 1.4,1])
return {
scale: scale,
}
}
//likeIconGreen
export function DeleteIconRed(): Override {
const scale = useTransform(x, [0, -x1,-x6-1], [1, 0,1])
return {
scale: scale,
}
}
//whiteLike
export function whiteDelete(): Override {
//useTransform
const opacity = useTransform(x, [-x2, -x3,-x7,-x8], [0, 1, 1,0])
const scale = useTransform(x, [-x1,-x4, -x5], [0.2, 1.1, 1.5])
//useAnimation
return {
opacity: opacity,
scale: scale,
}
}
//greenCircle
export function RedCircle(): Override {
const scale = useTransform(x, [0, -x0, -x1, -x6,-x9], [0, 0, 0.1, 1.4,1])
return {
scale: scale,
}
}
//whiteCircle
export function whiteCircleLeft(): Override {
const opacity = useTransform(x, [-x6,-x6-1], [0, 1])
const scale = useTransform(x,[-x6,-x9],[0,1])
return {
opacity: opacity,
scale:scale
}
}
useViewportScroll
scrollX
— Horizontal scroll distance in pixels. X轴滑动距离原点的位置(通常是负值)scrollY
— Vertical scroll distance in pixels. Y轴滑动距离原点的位置(通常是负值)!!这个用的多一点scrollXProgress
— Horizontal scroll progress between0
and1
.scrollYProgress
— Vertical scroll progress between0
and1
.- Note:If the returned scroll
MotionValue
s don’t seem to be updating, double check if thebody
tag styles are set towidth: 100%; height: 100%
or similar, as this can break accurate measurement of viewport scroll.
仅使用motionValue来驱动
源文件:
import { Override, useTransform,motionValue } from "framer"
//定义一个移动变量,这个motionValue其实就是,ScrollY的值。这个值是负的。
const scrollY = motionValue(0)
export function Scroll():Override {
return{
contentOffsetY : scrollY
}
}
export function Header():Override {
//此处说一下useTransform。这个就相当于乾坤大挪移,可以把一组正在变的值的情况应用于另外一组要变的值
//现在这个就是把scrollY的值变成opacity
//就是scollY从0到150,然后opacity就是0-1.
//这种对应关系是实时的。不像其他override,达到触发条件才执行。
const opacity = useTransform(scrollY,[-150,0],[1,0])
return{
opacity:opacity
}
}
仅使用motionValue和Data来条件驱动
这里和下面的onScroll的info.point.y其实是差不多的,功能是一样的,只是代码的写法不一样。下面那种会报错,但是不影响使用。按理说,还是这种优雅,这个是在framer 官网看到的。也分享一下
视频展示:
源文件:scroll_listen_onchange.framerx.zip
代码:
import { Override, Data, motionValue, useTransform } from "framer"
// Keep track of the state of our application
const data = Data({ opacity: 0 })
// Create a MotionValue to track contentOffsetY
const contentOffsetY = motionValue(0)
// Listen for changes to contentOffsetY
// contentOffsetY.onChange(offset => (data.isPastLimit = offset < -52))
// 有个大神是上面这样写的,我觉得不适合多条件判断。特意改成下面这种
contentOffsetY.onChange(point => {
if (point < -52) {
data.opacity = 1
} else {
data.opacity = 0
}
})
// Apply this override to your scroll component
export function TrackScroll(): Override {
return {
contentOffsetY: contentOffsetY,
onScroll() {
// console.log(contentOffsetY.get());
//这个可以实时查看scrollY的滚动值
},
}
}
// Apply this override to a frame containing your title
export function ShowTitleIfPastLimit(): Override {
return {
animate: {
opacity: data.opacity,
transition: {
duration: 0.25,
},
},
}
}
仅使用onScroll的info.point.y来驱动
这种滚动动画就是达到某种条件才会触发
源文件:
useViewportScroll.framerx.zip
import { Override, Data } from "framer"
//定义一个移动变量,这个motionValue其实就是,ScrollY的值。这个值是负的。
const data = Data({
opacity:0
})
export function Scroll():Override {
return{
onScroll(info){
//info.point.y : Relative to the device or page. 也就是向下滚动的值
const scrollY = Math.floor(info.point.y * 1) / 1
//此处point会报错,但是不影响使用
//info.point.y的值是浮点数,也就是会有很多小数点,不适合后面的条件判断
//math的方法可以使info.point.y变成整数
const newScrollY = -scrollY
if (newScrollY > 0 && newScrollY <150){
data.opacity = 0
} else if (newScrollY >= 150){
data.opacity = 1
}else{
data.opacity = 0
}
}
}
}
export function Header():Override {
return{
animate:{
opacity: data.opacity,
transition:{
duration:0.2
}
}
}
}
motionValue和onScroll的info.point.y混合使用
这是一个知识星球内容打卡页的交互效果,做了滚动时对页面各个元素的影响,以及下拉刷新的效果。
源代码:
import { Override, useTransform, motionValue, Data } from "framer"
const data = Data({
HeaderNameOpacity: 0,
menuBorderOpacity:0,
length:0,
circlePathOpacity:0
})
//定义一个变量,这个scroll是负值
const scrollY = motionValue(0)
//滚动对象
export function Scroll(props): Override {
return {
contentOffsetY: scrollY,
onScroll(info) {
const ScrollY = Math.floor(info.point.y * 1) / 1
const NewScrollY = -ScrollY
console.log(NewScrollY)
//header的name的透明度的条件判断
if (NewScrollY > 58) {
data.HeaderNameOpacity = 1
} else {
data.HeaderNameOpacity = 0
};
//menu菜单borderColor的条件判断
if (NewScrollY > 239){
data.menuBorderOpacity = 1
console.log("ok")
}else{
data.menuBorderOpacity = 0
}
//ciclePathLength的条件判断
if (ScrollY > 0 && ScrollY <= 64){
data.length = ScrollY*246/64
} else if (ScrollY > 64){
data.length = 246
}
//ciclePathOpacity
if (ScrollY >0){
data.circlePathOpacity = 1
}else{
data.circlePathOpacity = 0,
}
},
}
}
//header的bg的透明度变化
export function HeaderBg(): Override {
const opacity = useTransform(scrollY, [-59, 0], [1, 0])
return {
opacity: opacity,
}
}
//header的name的透明度变化
export function HeaderName(): Override {
return {
opacity: data.HeaderNameOpacity,
}
}
//menu的Y轴的变化
export function Menu(props):Override {
const y = useTransform(scrollY, [-215, 0, 1000], [-215, 0, 1000])
return{
y:y
}
}
//Menu的border
export function MenuBorder():Override {
return{
opacity:data.menuBorderOpacity
}
}
//photo的大小和移动
export function Photo():Override {
const y = useTransform(scrollY,[0,78],[0,78])
const scale = useTransform(scrollY,[78,300],[1,1.62])
return{
y:y,
scale:scale
}
}
//刷新圆圈的长度
export function CirclePath():Override {
return{
length:data.length,
opacity:data.circlePathOpacity
}
}
//刷新圆圈的透明度
export function Circle():Override {
const opacity = useTransform(scrollY, [0, 64], [0, 1])
return{
opacity:opacity
}
}
喜马拉雅的一个例子
源文件:喜马拉雅banner.framerx.zip
import { Override, Data,useTransform,motionValue } from "framer"
import { colors } from "./canvas"
//设定变量current的初始状态
const data = Data({
current: 0,
background: "",
circleX: 0,
bgFrontOpacity: 0,
appearance: "light",
topMenuBg: colors.primary,
sortButtonBG: colors.primary,
inputBg: colors.primary,
sortButtonBorder: "1px solid #fff",
})
//page组件的改变传递current值
export function Page(): Override {
return {
onChangePage(current) {
console.log(current)
;(data.current = current), (data.circleX = current * 10)
if (data.current == 0) {
data.background = "#0f2b42"
}
if (data.current == 1) {
data.background = "#295150"
}
if (data.current == 2) {
data.background = "#0f2b42"
}
if (data.current == 3) {
data.background = "#ba662d"
}
if (data.current == 4) {
data.background = "#9185b9"
}
if (data.current == 5) {
data.background = "#4b4264"
}
if (data.current == 6) {
data.background = "#bcc0c5"
}
if (data.current == 7) {
data.background = "#0f2b42"
}
if (data.current == 8) {
data.background = "#295150"
}
},
}
}
//定义全局变量scrollY,监听滚动的Y值。
const scrollY = motionValue(0)
export function ScrollContent(): Override {
return {
contentOffsetY:scrollY,
onScroll(info: point) {
//此处point报错了,但是不影响使用
const scrollY = Math.floor(info.point.y * 1) / 1
const newScrollY = -scrollY
if (newScrollY > 155) {
;(data.bgFrontOpacity = 1),
(data.appearance = "dark"),
(data.topMenuBg = colors.dark_primary),
(data.sortButtonBG = colors.menu),
(data.inputBg = colors.two),
(data.sortButtonBorder = "1px solid #F86643")
} else {
;(data.bgFrontOpacity = 0),
(data.appearance = "light"),
(data.topMenuBg = colors.primary),
(data.sortButtonBG = colors.primary),
(data.inputBg = colors.primary),
(data.sortButtonBorder = "1px solid #fff")
}
},
}
}
//根据Page组件传递的current值,来判断小圆点的位置
export function Circle1(): Override {
return {
animate: { x: data.circleX, transition: { duration: 0.35 } },
}
}
//通过Page组件传递的状态值来判断背景颜色
export function BgBannerBack(): Override {
const y = useTransform(scrollY,[-26,-155],[0,-129])
return {
background: data.background,
y:y
}
}
export function BgBannerFront(): Override {
return {
background: data.background,
}
}
export function WhiteSolid(): Override {
return {
animate: {
opacity: data.bgFrontOpacity,
transition: { duration: 0.35 },
},
}
}
export function StatusBar(): Override {
return {
appearance: data.appearance,
}
}
//顶部导航栏颜色的变化
export function TopMenu(): Override {
return {
background: data.topMenuBg,
}
}
//分类按钮的变化
export function sortButton(): Override {
return {
background: data.sortButtonBG,
}
}
//input区的颜色变化
export function inputBg(): Override {
return {
background: data.inputBg,
}
}
export function sortButtonBorder(): Override {
return {
border: data.sortButtonBorder,
}
}
useCycle
循环一组值
import { useCycle,Override } from "framer"
export function MyComponent(): Override {
const [x, cycleX] = useCycle(0, 50, 100)
return {
animate: { x: x },
onTap(){
cycleX()
}
}
}
//再点击时候,x的值会在0,50,100之间循环。
循环多种状态
export function MultiVariants():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()
},
onmousedown(){
cycle(0)
},
onMouseLeave(){
cycle(2)
}
}
}