🧨春节假期要吃什么?选择恐惧症的我写了几行代码听天由命

810 阅读3分钟

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

前言

想必大家经常会遇到这么一个问题:今天要吃什么? 如果身边的人非常可爱且负责任且尊重你,Ta会回答:“随便”。好吧,绣球又抛回来了,既然都不知道吃什么,那不如随机决定吧!

本文的内容就是实现一个非常简单的随机选择器 —— 吃啥?它为春节假期在家对于吃什么做不了决定的我们提供了参考意见。

先来看看实现效果,文章最后贴了体验地址。

实现效果

具体实现

主要由两部分组成 —— 动态背景 & 随机选择器

背景的实现

背景墙由若干个淡入淡出的名词组成,它们的位置都是随机的,且是间歇性变化。这里是用 animationsetInterval实现的。【css部分将在最后源码中一起贴出来】

  1. 首先在js代码中输入备选项食物,用数组保存下来便于后续的随机操作。

image.png

  1. 名词的出现本质上就是往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 }
}
  1. 我们使用定时器即可间歇添加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);
  1. 但这里会存在一个问题,如果不断添加的话,我们页面的dom元素会堆积得越来越多。因此我们需要一个函数来移除已出现的dom
function removeFood(){
    let foodElements = document.querySelectorAll('.food-item')
    let body = document.body
    body.removeChild(foodElements[0]) // 移除顶部的元素
}
  1. 这里我们使用 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 数组的部分,根据自己的口味自定义一下!

预祝大家新年快乐💖!