PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
先来看看成品,体验链接:
对春节最多的印象,对我来说是算命,小时候一到寒假,我爸就拿个老黄历,再用一些铜钱,给我们家人算命。抛铜钱然后查老黄历,反正不管怎么算,给我们算出来的都是好命,什么前途无量、一生富贵这种。刚开始我还觉得很神奇,相信了,有一次跟我姐姐说我的命,我爸听见了就跟我说,不要迷信,你还是得好好学习。
这不,现在的我只相信科学。但是偶尔回想起小时候暖黄色的灯泡下,一家人围在桌子旁一边聊天,一边扔铜钱,一边查老黄历的事情,还是很温馨。
今年因为疫情,又回不了家过年了,很多人和我一样,不如我们来试试用代码实现算命吧。
另外,本项目也可以作为React入门者学习资料,带你掌握从0搭建一个React项目,另外掌握动画、函数组件与Hook等。
创建项目
npx create-react-app goodluck
cd goodluck
yarn dev
此命令需要node环境支持,且版本需要14+,所以如果提示你版本过低,可以用n升级下,
安装n: npm install -g n
安装node指定版本: n stable
背景
先在来个红红火火的背景图,并写个center居中的className样式,留作备用,如下我写在了index.css中:
html,
body {
height: 100%;
}
body {
background-image: url("../public/imgs/fu.png");
background-size: contain;
}
.center {
display: flex;
align-items: center;
justify-content: center;
}
硬币转动特效
为了探测运气,我们先来实现下硬币转动的动画,首先先来两张硬币正反两面的图片(当然我也没找到完全大小一样的,于是我先是去网上找了两个基本上能用的,但是它们大小不一样、不是png,于是我开始自己动手ps,后面用到的很多图片,都是网图+ps,ps细节就不说了,如果你不会ps,可以去github直接用我的图片,或者留言1,我可以出个ps基本入门教程)。
我设置了五枚铜钱来实现旋转效果,每个铜钱0.5s旋转一圈,无限旋转:
<div className="canvas">
{[0, 1, 2, 3, 4].map((item, index) => (
<div key={index} className={classnames("coin-rotate", "coin")}>
<div className={classnames("coin0")}></div>
<div className={classnames("coin1")}></div>
</div>
))}
</div>
关于实现旋转的css稍复杂,不过核心就是两个div的旋转切换而已,详细css代码如下:
.canvas {
display: flex;
justify-content: space-around;
}
.coin {
position: relative;
width: 100px;
height: 100px;
}
.coin:hover {
animation-play-state: paused;
}
.coin-rotate {
transform-style: preserve-3d;
animation: rotate 0.5s infinite linear;
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
}
@keyframes rotate {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
.coin0,
.coin1 {
position: absolute;
left: 0px;
top: 0px;
width: inherit;
height: inherit;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.coin0 {
transform: translateZ(1px);
background-image: url("../public/imgs/coin0.png");
}
.coin1 {
background-image: url("../public/imgs/coin1.png");
}
如果你对css不熟悉,或者不熟悉某个属性,推荐菜鸟教程,对于不同的css效果有详细的动画与描述。
获取铜钱状态
刚刚我们设置了铜钱的无限旋转,那肯定得停下来,并且每个铜钱都有自己的正反面。这个时候我们需要定义下铜钱状态,比如我设置了一个全局变量defaultState:
const defaultState = {
// loading为true代表铜钱在旋转
loading: false,
// 长度为5、默认值为0的数组,(0代表硬币反面,1代表正面)
data: new Array(5).fill(0),
luck: {
// 算命的结果语
destiny: "",
// 一个class数组,标记不同命运的不同动画效果,具体的代码定义在index.css
classNames: [],
// 头图,如金钱豹
banner: "",
},
};
这里我们首先需要获取铜钱状态,这里我多次调用了getLuckNum这个函数,即随机获取0与1:
// 获取五枚铜钱的正反面,当然是随机数,你想什么呢,难不成还看你生辰八字
export function getLuckNum() {
return Math.round(Math.random());
}
接下来这里我们获取命运结果的函数如下:
const getLuck = () => {
let newState = { ...defaultState };
if (state.loading) {
newState.loading = false;
// 获取五枚铜钱的正反面,玄机查看utils
for (let i = 0; i < 5; i++) {
newState.data[i] = getLuckNum();
}
newState.luck = getGoodLuck(wish);
} else {
newState.loading = true;
}
setState(newState);
};
好了,准备工作都做好了,App组件该出场了: 首先是决定命运的button:
<button onClick={getLuck}>
{state.loading ? "查看结果" : "查看运势"}
</button>
然后是显示命运结果的组件:
<div className="canvas">
{state.data.map((item, index) => (
<div
key={index}
className={classnames(state.loading && "coin-rotate", "coin")}
>
<div
className={classnames(
"coin0",
!state.loading && item === 1 && "hide"
)}
></div>
<div
className={classnames(
"coin1",
!state.loading && item === 0 && "hide"
)}
></div>
</div>
))}
</div>
{state.luck?.classNames != "" && !state.loading && (
<div className={classnames("luck-bg center", state.luck?.mainStyle)}>
{state.luck?.classNames &&
state.luck?.classNames.map((item, index) => (
<div
key={index}
className={classnames("luck", item, "center")}
></div>
))}
<div
className={classnames(state.luck.banner, "banner", "center")}
></div>
<div className="blessing center">{state.luck?.destiny}</div>
)}
</div>
);
}
说出愿望吧
在上一步中,你可能注意到了,getGoodLuck接收了参数wish,就是说用户可以输入愿望。算命嘛,就算你是去庙里,别人也会问你是求前途还是求姻缘,我当年高考,我妈就去庙里给我算了算,求了高考,结果我就考上了。哈哈,算命有时候当做心里安慰还是很有用的,虽然我高考后才知道这事。
接下来写个输入框,让用户输入所求,如“暴富”,然后点击button开始扔硬币 当然input框我们需要做成受控组件,首先定义状态wish:
const [wish, setWish] = useState("");
当然是用Hook定义state了,如果你和eric也有一个坚持不用函数组件和Hook的领导,趁过年,赶紧换了吧。
<input
className="name"
type="text"
value={name}
placeholder="说出你的愿望吧"
onChange={(e) => {
setName(e.target.value);
}}
onKeyUp={(e) => {
if (e.keyCode === 13) {
getLuck();
}
}}
/>
如果你很好奇,怎么根据愿望给出命运结果呢,其实我有个大json,去里面搜索数据就行了,相当于算命先生的脑库。具体代码过多,我就不全贴出来了,想看全套的代码的,可以点击文末链接去github查看。
丰富
好了,到现在为止,已经能看到效果了,为了能让用户多次算命,我加了个一键重启的button,当然这和刷新页面是一样的效果~
来输入暴富,看看发生了什么~
当然你也可以尝试其他输入,如脱单、暴瘦、升职加薪等等~
除了算命,本项目还可以用作React入门学习,被我点名的,赶紧学起来吧~
知识点总结
除了算命这一娱乐之外,本项目知识点如下:
- js基础,如数组、字符串、正则匹配等
- 动画
- 均衡获取随机数
- Hook state使用
- 在create react app中配置less
- 等等
其中,第五条其实和本项目关系不大,你可以不配置~