PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
前言
想必大家经常会遇到这么一个问题:今天要吃什么? 如果身边的人非常可爱且负责任且尊重你,Ta会回答:“随便”。好吧,绣球又抛回来了,既然都不知道吃什么,那不如随机决定吧!
本文的内容就是实现一个非常简单的随机选择器 —— 吃啥?它为春节假期在家对于吃什么做不了决定的我们提供了参考意见。
先来看看实现效果,文章最后贴了体验地址。
具体实现
主要由两部分组成 —— 动态背景 & 随机选择器
背景的实现
背景墙由若干个淡入淡出的名词组成,它们的位置都是随机的,且是间歇性变化。这里是用 animation 和 setInterval实现的。【css部分将在最后源码中一起贴出来】
- 首先在js代码中输入备选项食物,用数组保存下来便于后续的随机操作。
- 名词的出现本质上就是往html中插入dom元素,因此我们需要两个函数来生成需要的dom,并随机初始化出现的位置。
function createFood(itemText){
let p = document.createElement('p')
let body = document.body
let { x, y } = randomPos() // 随机初始化位置
p.innerText = itemText
p.className = 'food-item'
p.style.left = x + 'px'
p.style.top = y + 'px'
p.style.animationDuration = ADD_STEP * MAX_NUM / 1000 + 's' // 动态设置动画持续时间,后续会介绍
body.appendChild(p)
}
function randomPos(){
let x = Math.floor(Math.random() * window.innerWidth)
let y = Math.floor(Math.random() * window.innerHeight)
return { x, y }
}
-
我们使用定时器即可间歇添加dom元素。为了防止数组越界,需要判断当前操作索引是否超出数组长度,若超出,则重置为0。
其中,
ADD_STEP表示定时器的频率,我设置为 200ms。
let nowIndex = 0
const ADD_STEP = 200
setInterval(() => {
if(nowIndex >= foodArr.length)
nowIndex = 0
createFood(foodArr[nowIndex])
nowIndex ++
}, ADD_STEP);
- 但这里会存在一个问题,如果不断添加的话,我们页面的dom元素会堆积得越来越多。因此我们需要一个函数来移除已出现的dom。
function removeFood(){
let foodElements = document.querySelectorAll('.food-item')
let body = document.body
body.removeChild(foodElements[0]) // 移除顶部的元素
}
-
这里我们使用
setTimeout来延迟移除元素。我们要做到从元素生成到淡出的时间与被移除需要的时间相同,也就是说,单个元素动画结束的时候,它正好被移除了,这样可以保证页面上的元素总量达到阈值后是不会改变的。因此,修改刚才定时器的内容,且同步调整css动画持续时间。
延迟时间 === 动画持续时间测试后发现与ADD_STEP作商正好是页面最终名词的个数。
const ADD_STEP = 200
const MAX_NUM = 20 // 页面上元素总量阈值
setInterval(() => {
if(nowIndex >= foodArr.length)
nowIndex = 0
createFood(foodArr[nowIndex])
nowIndex ++
// 新增延时移除元素
setTimeout(() => {
removeFood()
}, ADD_STEP * MAX_NUM);
}, ADD_STEP);
// 前文中提到的
p.style.animationDuration = ADD_STEP * MAX_NUM / 1000 + 's'
随机选择的实现
这个就更简单了,监听按钮点击事件,若被点击,则修改按钮的文本,吃什么的一栏开始滚动。再次点击按钮的时候,按钮复原,滚动停止即完成了选择的流程。
btn.addEventListener('click',()=>{
let i = 0
if(!(flag % 2)){
btn.innerText = '就是它!'
timer = setInterval(() => {
if(i >= foodArr.length)
i = 0
foodNameEl.innerText = foodArr[i]
i ++
}, 50);
}else{
clearInterval(timer)
btn.innerText = '开始选择'
}
flag ++
})
在线体验&实现源码
源码部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>掘金-春节吃什么</title>
<style>
* {
margin: 0;
padding: 0;
user-select: none;
}
body {
width: 100vw;
height: 100vh;
background-color: #e74c3c;
position: relative;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.food-item {
font-size: 1.5rem;
color: #f1c40f;
white-space: nowrap;
position: absolute;
animation: hideFood linear forwards;
cursor: pointer;
}
@keyframes hideFood {
from {
opacity: 1;
transform: scale(1.5);
filter: blur(2px);
}
20% {
filter: blur(0);
}
to {
opacity: 0;
transform: scale(0);
}
}
main {
background-color: #e74c3c;
text-align: center;
position: relative;
z-index: 1;
}
.content {
font-size: 2rem;
font-weight: bold;
color: #f1c40f;
text-shadow: 0px 0px 3px #333;
}
.food-name {
color: #ecf0f1;
}
.btn {
margin: 1.2rem 0;
padding: .8rem 3rem;
font-size: 1.2rem;
font-weight: normal;
display: inline-block;
background-color: #f39c12;
color: #ecf0f1;
border-radius: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<main>
<div class="content">
<span>春节假期我要吃</span>
<span class="food-name">什么?</span>
</div>
<span class="btn">开始选择</span>
</main>
<script>
let foodArr = ['饺子', '火锅', '烤肉', '烧烤', '炒饭','米线',
'炸鸡', '汉堡', '麻辣烫', '面疙瘩', '卤肉饭','凉皮',
'汤圆', '烤鱼', '水果', '瘦肉丸', '炸酱面','杂粮煎饼',
'冒菜', '披萨', '肯德基', '小馄饨','肉夹馍', '麻辣香锅',
'蔬菜沙拉', '三汁焖锅','黄焖鸡米饭', '生煎包', '酸菜鱼','土']
let nowIndex = 0
let flag = 0
let btn = document.querySelector('.btn')
let foodNameEl = document.querySelector('.food-name')
const ADD_STEP = 200
const MAX_NUM = 20
function createFood(itemText){
let p = document.createElement('p')
let body = document.body
let { x, y } = randomPos()
p.innerText = itemText
p.className = 'food-item'
p.style.left = x + 'px'
p.style.top = y + 'px'
p.style.animationDuration = ADD_STEP * MAX_NUM / 1000 + 's'
body.appendChild(p)
}
function removeFood(){
let foodElements = document.querySelectorAll('.food-item')
let body = document.body
body.removeChild(foodElements[0])
}
function randomPos(){
let x = Math.floor(Math.random() * window.innerWidth)
let y = Math.floor(Math.random() * window.innerHeight)
return { x, y }
}
setInterval(() => {
if(nowIndex >= foodArr.length)
nowIndex = 0
createFood(foodArr[nowIndex])
nowIndex ++
setTimeout(() => {
removeFood()
}, ADD_STEP * MAX_NUM);
}, ADD_STEP);
btn.addEventListener('click',()=>{
let i = 0
if(!(flag % 2)){
btn.innerText = '就是它!'
timer = setInterval(() => {
if(i >= foodArr.length)
i = 0
foodNameEl.innerText = foodArr[i]
i ++
}, 50);
}else{
clearInterval(timer)
btn.innerText = '开始选择'
}
flag ++
})
</script>
</body>
</html>
结语
几行简单的代码,多多少少解决了不知道要吃什么的问题哈哈哈。
需要的朋友修改下代码中 foodArr 数组的部分,根据自己的口味自定义一下!
预祝大家新年快乐💖!