“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
前言
新一季的 Rick&Morty 已经上线,剧集质量虽然有所下降,但 E03 中的 SheepCounter 挺有意思。自己照着剧中的设定开发了一款界面极其相似、交互更为丰富的小程序,小程序的终极目标只有一个:数羊!数羊!!数羊!!!。
不会真有人觉得这款小程序会起到催眠作用吧。
小程序虽然简单,但也探索出了一些有意思的小实现。下面就和大家分享探讨一下:
曲线路径的动画实现
首先就是小羊跳入、跳出界面的动画,仔细观察地话可以发现,小羊移动的路径其实是条曲线。
水平或者垂直移动的动画不难实现,我们可以通过控制绝对定位下的 left/right 或者 top/bottom 来实现。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.zone {
position: relative;
width: 200px;
height: 400px;
top: 100px;
left: 400px;
border: 1px solid red;
}
.ball {
position: absolute;
width: 50px;
height: 50px;
background-color: cadetblue;
border-radius: 50%;
top: 30px;
right: -100px;
animation: XIn 1s linear;
animation-fill-mode: forwards;
}
@keyframes XIn {
0% {
right: -100px;
}
100% {
right: 50%;
}
}
</style>
</head>
<body>
<div class="zone">
<div class="ball"></div>
</div>
</body>
</html>
如果是需要曲线移动呢?animation 中似乎没有可以设置曲线移动的属性。不过我们可以参照高中物理知识思考一下,二维平面上移动无外乎水平或者垂直两个方向,当两个方向的移动同时发生且速度不一致时,便可以合成为曲线运动。结合此原理,我们可以轻松地想到:只要在animation中同时设置速度不一致的垂直移动动画和水平移动动画即可。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.zone {
position: relative;
width: 200px;
height: 400px;
top: 100px;
left: 400px;
border: 1px solid red;
}
.ball {
position: absolute;
width: 50px;
height: 50px;
background-color: cadetblue;
border-radius: 50%;
top: 30px;
right: -100px;
animation: XIn 1s cubic-bezier(0.28, 0.58, 0.4, 0.73), YIn 1s linear;
animation-fill-mode: forwards;
}
@keyframes XIn {
0% {
right: -100px;
}
100% {
right: 50%;
}
}
@keyframes YIn {
0% {
top: 30px;
}
100% {
top: 50%;
}
}
</style>
</head>
<body>
<div class="zone">
<div class="ball"></div>
</div>
</body>
</html>
这样也就成功实现了曲线移动效果。
自定义输入框的实现
可以看到,在我们小程序的数羊界面中已经有了自定义实现了键盘。在小程序中进行输入时,我们肯定不希望弹起系统键盘。
要实现这个功能,最简单的方法便是将input组件禁用,再通过修改禁用状态下的组件样式即可。
但这款小程序本就是消遣娱乐的产物,所以我决定曲线救国:自定义实现一个输入框。
输入框最有辨识度的特点是什么?那自然是闪烁的光标。光标才可以为我们自定义的输入框注入灵魂。闪烁效果其实也只是个动画而已,以下是简单的实现效果:
.sCursor {
position: absolute;
display: inline-block;
width: 3px;
height: 50px;
margin-left: 4px;
background: #000;
top: 24px;
animation: blink 800ms infinite reverse;
}
@keyframes blink {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<View className={style.sInput}>
{/* <!-- 文本 --> */}
{inputValue?.split('').map((v: string, i: number) => (
<Text key={i} className={style.sValue}>{v} </Text>
))}
{/* <!-- 光标 --> */}
<View className={style.sCursor} />
</View>
为了避免用户忘记了自己数到了第几只羊,我决定在用户输入错误两次后,用placeholder的形式来提示用户。自定义placeholder的思路也非常简单,只需要将其绝对定位至正常输入的文本之下:
.inputZone {
width: 500px;
height: 100px;
position: relative;
.sInput {
width: 100%;
height: 100%;
padding: 10px 40px;
letter-spacing: 6px;
position: relative;
.sValue {
font-size: 60px;
font-family: 'handwriting';
}
.sCursor {
//...
}
}
.sTip {
position: absolute;
font-size: 60px;
font-family: 'handwriting';
z-index: 1;
top: 10px;
left: 40px;
color: rgb(145, 142, 142);
}
}
<View className={style.inputZone}>
<View className={style.sInput}>
{/* <!-- 文本 --> */}
{inputValue?.split('').map((v: string, i: number) => (
<Text key={i} className={style.sValue}>{v}</Text>
))}
{/* <!-- 光标 --> */}
<View className={style.sCursor} />
</View>
{tip && !inputValue ? (
<Text className={style.sTip}>{tip}</Text>
) : null}
</View>
键盘功能的实现就更简单了,只需要根据不同按钮点击事件触发相应的功能就行。想必大家都能想到,这里不贴代码了。
尾言
兴趣是学习的最好老师。一款看起来极其简单的小程序,真正实践开发起来也能遇到一些未曾了解过的知识点。Xdm,如果你也有有趣的点子,别犹豫,行动起来吧!
最后插一句,希望Rick&Morty后续剧集的质量能upup!!