Vue實(shí)現(xiàn)紅包雨小游戲的示例代碼
0 寫(xiě)在前面
紅包也叫壓歲錢(qián),是過(guò)農(nóng)歷春節(jié)時(shí)長(zhǎng)輩給小孩兒用紅紙包裹的禮金。據(jù)傳明清時(shí)期,壓歲錢(qián)大多數(shù)是用紅繩串著賜給孩子。民國(guó)以后,則演變?yōu)橛眉t紙包裹。中國(guó)的紅包傳統(tǒng)民族文化在民間如此,社區(qū)、公司也奉行如儀。除了春節(jié)以外,在其他喜慶場(chǎng)合,例如婚禮、新店開(kāi)張等亦有送紅包的習(xí)俗。
本期迎新春專(zhuān)題用代碼制作一個(gè) 紅包雨小游戲 ,效果如下所示??赐瓯疚南嘈拍阋部梢酝瓿蛇@樣一個(gè)小游戲設(shè)計(jì)。
1 準(zhǔn)備工作
使用 Vue 構(gòu)建工程。流程為
vue init webpack vue-demo
cd vue-demo
cnpm install # npm install
從網(wǎng)絡(luò)上下載一些喜慶的圖片作為背景和紅包樣式,這些樣式可以任選,給想整活的同學(xué)們充足的自由度。
2 設(shè)計(jì)HTML+CSS樣式
html樣式很簡(jiǎn)單,主要分為兩個(gè)部分:紅包雨 和 搶紅包面板。
<!-- 紅包雨 --> <div id="wrapper"></div> <!-- 搶紅包面板 --> <div id="panel"> ?? ?<div id="hb"> ? ? ?? ?<span id="text">{{ result }}</span> ? ? ? ? <div id="btn" @click="gameOn">繼續(xù)搶紅包</div> ? ? </div> </div>
CSS樣式稍微復(fù)雜一些,放在下文完整代碼中,需要的自取。其中比較少用的是annimation動(dòng)畫(huà)渲染樣式
animation: dropDowm 3s forwards; /* 旋轉(zhuǎn)動(dòng)畫(huà) */ @keyframes dropDowm { 0% { top: 0px; transform: translateY(-100%) rotate(0deg); } 100% { top: 110%; transform: translateY(0%) rotate(360deg); } }
這里講解一下,annimation常見(jiàn)參數(shù)如下:
animation-name:關(guān)鍵幀動(dòng)畫(huà)名稱(chēng)
animation-duration:動(dòng)畫(huà)執(zhí)行時(shí)間
animation-timing-function: 動(dòng)畫(huà)的執(zhí)行速度函數(shù)
animation-delay: 動(dòng)畫(huà)延遲時(shí)間
animation-iteration-count:動(dòng)畫(huà)執(zhí)行次數(shù)
animation-direction: 動(dòng)畫(huà)執(zhí)行方向,包含alternate(間隔運(yùn)動(dòng))、 reverse(反向運(yùn)動(dòng))、reverse-alternate(反向間隔運(yùn)動(dòng))
animation-fill-mode:規(guī)定當(dāng)動(dòng)畫(huà)不播放時(shí)(當(dāng)動(dòng)畫(huà)完成時(shí),或當(dāng)動(dòng)畫(huà)有一個(gè)延遲未開(kāi)始播放時(shí)),要應(yīng)用到元素的樣式,包含forwards(動(dòng)畫(huà)停止在最后一個(gè)關(guān)鍵幀的位置)、backwards(動(dòng)畫(huà)第一個(gè)關(guān)鍵幀立即執(zhí)行)、both(第一個(gè)關(guān)鍵幀也停止在最后一個(gè)關(guān)鍵幀)
設(shè)計(jì)完成后運(yùn)行結(jié)果如下圖所示,分別為背景和面板。
3 設(shè)計(jì)JavaScript邏輯
程序的邏輯如下所示
上述最關(guān)鍵的就是監(jiān)聽(tīng)用戶(hù)搶紅包的行為,并判斷是否搶到了紅包,監(jiān)聽(tīng)函數(shù)設(shè)計(jì)如下所示,如果成功搶到紅包,則總金額自動(dòng)累加。
mouseHandler(e) { var event = e || window.event, money = event.target.dataset.money; if (money) { this.result = "恭喜搶到紅包" + money + "元"; for (var i = 0, len = this.imgList.length; i < len; i++) { this.imgList[i].style.animationPlayState = "paused"; } panel.style.display = "block"; this.totalMoney += Number(money); } }
接下來(lái)要考慮如何讓紅包隨機(jī)掉落,核心代碼如下:
for (var i = 0; i < num; i++) { let img = new Image(); img.src = this.imgUrl; // 隨機(jī)設(shè)置紅包分布 img.style.left = this.ranNum(0, window.innerWidth) + "px"; let delay = this.ranNum(0, 100) / 10; // 設(shè)置紅包出現(xiàn)時(shí)間 img.style.animationDelay = delay + "s"; if (this.delayTime < delay) { this.delayTime = delay; this.lastImg = img; } //設(shè)置每個(gè)紅包的金額 img.dataset.money = this.ranNum(0, 1000) / 100;
其他函數(shù)基本都是服務(wù)于這兩個(gè)核心功能的,這里不贅述。
4 完整代碼
<template> <div id="app"> <!-- 紅包雨 --> <div id="wrapper"></div> <!-- 搶紅包面板 --> <div id="panel"> <div id="hb"> <span id="text">{{ result }}</span> <div id="btn" @click="gameOn">繼續(xù)搶紅包</div> </div> </div> </div> </template>
<script> export default { ? name: "App", ? data() { ? ? return { ? ? ? totalMoney: 0, // 所有搶到紅包的總金額 ? ? ? delayTime: 0, // 延時(shí) ? ? ? lastImg: null, // 最后一張掉落的圖片 ? ? ? imgList: null, // 紅包隨機(jī)序列 ? ? ? result: "", // 游戲結(jié)果 ? ? ? imgUrl: require("./assets/hongbao.jpg"), ? ? }; ? }, ? methods: { ? ? // @breif:開(kāi)始游戲 ? ? start() { ? ? ? let dom = this.createDom(20); ? ? ? this.imgList = document.getElementsByTagName("img"); ? ? ? document.getElementById("wrapper").appendChild(dom); ? ? }, ? ? // @breif: 創(chuàng)建紅包序列 ? ? createDom(num) { ? ? ? // 創(chuàng)建文檔碎片 ? ? ? let frag = document.createDocumentFragment(); ? ? ? for (var i = 0; i < num; i++) { ? ? ? ? let img = new Image(); ? ? ? ? img.src = this.imgUrl; ? ? ? ? // 隨機(jī)設(shè)置紅包分布 ? ? ? ? img.style.left = this.ranNum(0, window.innerWidth) + "px"; ? ? ? ? let delay = this.ranNum(0, 100) / 10; ? ? ? ? // 設(shè)置紅包出現(xiàn)時(shí)間 ? ? ? ? img.style.animationDelay = delay + "s"; ? ? ? ? if (this.delayTime < delay) { ? ? ? ? ? this.delayTime = delay; ? ? ? ? ? this.lastImg = img; ? ? ? ? } ? ? ? ? //設(shè)置每個(gè)紅包的金額 ? ? ? ? img.dataset.money = this.ranNum(0, 1000) / 100; ? ? ? ? frag.appendChild(img); ? ? ? } ? ? ? return frag; ? ? }, ? ? // @breif:繼續(xù)游戲 ? ? gameOn() { ? ? ? document.getElementById("panel").style.display = "none"; ? ? ? for (let i = 0, len = this.imgList.length; i < len; i++) { ? ? ? ? this.imgList[i].style.animationPlayState = "running"; ? ? ? } ? ? }, ? ? // 監(jiān)聽(tīng)鼠標(biāo)事件 ? ? mouseHandler(e) { ? ? ? var event = e || window.event, ? ? ? ? money = event.target.dataset.money; ? ? ? if (money) { ? ? ? ? this.result = "恭喜搶到紅包" + money + "元"; ? ? ? ? for (var i = 0, len = this.imgList.length; i < len; i++) { ? ? ? ? ? this.imgList[i].style.animationPlayState = "paused"; ? ? ? ? } ? ? ? ? panel.style.display = "block"; ? ? ? ? this.totalMoney += Number(money); ? ? ? } ? ? }, ? ? // 監(jiān)聽(tīng)動(dòng)畫(huà)事件 ? ? annimationHandler(e) { ? ? ? document.getElementById("panel").style.display = "block"; ? ? ? this.result = "恭喜總共搶到了" + this.totalMoney.toFixed(2) + "元"; ? ? },? ? // @breif:產(chǎn)生min~max間的隨機(jī)數(shù) ? ? ranNum(min, max) { ? ? ? return Math.ceil(Math.random() * (max - min) + min); ? ? }, ? }, ? mounted() { ? ? this.start(); ? ? window.addEventListener("mousedown", this.mouseHandler); ? ? this.lastImg.addEventListener("webkitAnimationEnd", this.annimationHandler); ? }, }; </script>
<style> * { ? padding: 0; ? margin: 0; } body { ? height: 100%; ? width: 100%; ? background: url("./assets/background.jpg"); ? background-size: cover; ? overflow: hidden; } #wrapper img { ? position: absolute; ? transform: translateY(-100%); /* 下落動(dòng)畫(huà) */ ? animation: dropDowm 3s forwards; /* 旋轉(zhuǎn)動(dòng)畫(huà) */ } @keyframes dropDowm { ? 0% { ? ? top: 0px; ? ? transform: translateY(-100%) rotate(0deg); ? } ? 100% { ? ? top: 110%; ? ? transform: translateY(0%) rotate(360deg); ? } } #panel { ? display: none; } #panel::before { ? content: ""; ? position: fixed; ? top: 0; ? left: 0; ? right: 0; ? bottom: 0; ? background-color: rgba(0, 0, 0, 0.5); } #hb { ? width: 350px; ? height: 450px; ? border-radius: 20px; ? background-color: #e7223e; ? color: #fad755; ? position: fixed; ? left: 50%; ? top: 50%; ? margin-top: -225px; ? margin-left: -175px; ? font-size: 30px; ? font-weight: 900; ? display: flex; ? flex-direction: column; ? justify-content: center; ? align-items: center; } #btn { ? background-color: #fad755; ? color: #e7223e; ? font-size: 18px; ? margin-top: 10px; ? padding: 10px; ? border: none; ? outline: none; ? cursor: pointer; } </style>
以上就是Vue實(shí)現(xiàn)紅包雨小游戲的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Vue紅包雨游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vite結(jié)合whistle實(shí)現(xiàn)一勞永逸開(kāi)發(fā)環(huán)境代理方案
這篇文章主要為大家介紹了Vite結(jié)合whistle實(shí)現(xiàn)一勞永逸開(kāi)發(fā)環(huán)境代理方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07解決vue打包報(bào)錯(cuò)Unexpected token: punc的問(wèn)題
這篇文章主要介紹了解決vue打包報(bào)錯(cuò)Unexpected token: punc的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10vue實(shí)現(xiàn)彈框遮罩點(diǎn)擊其他區(qū)域彈框關(guān)閉及v-if與v-show的區(qū)別介紹
vue如何簡(jiǎn)單的實(shí)現(xiàn)彈框,遮罩,點(diǎn)擊其他區(qū)域關(guān)閉彈框, 簡(jiǎn)單的思路是以一個(gè)div作為遮罩,這篇文章給大家詳細(xì)介紹了vue實(shí)現(xiàn)彈框遮罩點(diǎn)擊其他區(qū)域彈框關(guān)閉及v-if與v-show的區(qū)別介紹,感興趣的朋友一起看看吧2018-09-09在antd中setFieldsValue和defaultVal的用法
這篇文章主要介紹了在antd中setFieldsValue和defaultVal的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10VUE3中watch監(jiān)聽(tīng)使用實(shí)例詳解
watch函數(shù)用來(lái)偵聽(tīng)特定的數(shù)據(jù)源,并在回調(diào)函數(shù)中執(zhí)行副作用,下面這篇文章主要給大家介紹了關(guān)于VUE3中watch監(jiān)聽(tīng)使用的相關(guān)資料,需要的朋友可以參考下2022-06-06Vue3中echarts無(wú)法縮放的問(wèn)題及解決方案
很多朋友在使用vue3+echarts5技術(shù)時(shí)會(huì)遇到echarts無(wú)法綻放的問(wèn)題,今天小編就給大家分享下問(wèn)題描述及解決方案,感興趣的朋友跟隨小編一起看看吧2022-11-11關(guān)于Vue中keep-alive的作用及使用方法
keep-alive是Vue的內(nèi)置組件,當(dāng)它包裹動(dòng)態(tài)組件時(shí),會(huì)緩存不活動(dòng)的組件實(shí)例,該組件將不會(huì)銷(xiāo)毀,這篇文章主要介紹了關(guān)于Vue中keep-alive的作用是什么?怎么使用,需要的朋友可以參考下2023-04-04