React--简单的抽卡模拟器
生活随笔
收集整理的這篇文章主要介紹了
React--简单的抽卡模拟器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
寫在前面
功能介紹
1、主頁
2、十連抽頁
3、單抽頁
4、抽卡記錄頁
代碼結構
代碼內容
1、heros.json
{"legend": [{"name": "步練師","spell": "bu_lianshi"},{"name": "關羽","spell": "guan_yu"},{"name": "郭嘉","spell": "guo_jia"},{"name": "黃蓋","spell": "huang_gai"},{"name": "黃忠","spell": "huang_zhong"},{"name": "魯肅","spell": "lu_su"},{"name": "陸遜","spell": "lu_xun"},{"name": "司馬懿","spell": "si_mayi"},{"name": "孫尚香","spell": "sun_shangxiang"},{"name": "嚴顏","spell": "yan_yan"},{"name": "于禁","spell": "yu_jin"},{"name": "周瑜","spell": "zhou_yu"},{"name": "諸葛亮","spell": "zhu_geliang"}],"epic": [{"name": "步練師","spell": "bu_lianshi"},{"name": "關羽","spell": "guan_yu"},{"name": "郭嘉","spell": "guo_jia"},{"name": "黃蓋","spell": "huang_gai"},{"name": "黃忠","spell": "huang_zhong"},{"name": "魯肅","spell": "lu_su"},{"name": "陸遜","spell": "lu_xun"},{"name": "司馬懿","spell": "si_mayi"},{"name": "孫尚香","spell": "sun_shangxiang"},{"name": "嚴顏","spell": "yan_yan"},{"name": "于禁","spell": "yu_jin"},{"name": "周瑜","spell": "zhou_yu"},{"name": "諸葛亮","spell": "zhu_geliang"}],"elite": [{"name": "步練師","spell": "bu_lianshi"},{"name": "關羽","spell": "guan_yu"},{"name": "郭嘉","spell": "guo_jia"},{"name": "黃蓋","spell": "huang_gai"},{"name": "黃忠","spell": "huang_zhong"},{"name": "魯肅","spell": "lu_su"},{"name": "陸遜","spell": "lu_xun"},{"name": "司馬懿","spell": "si_mayi"},{"name": "孫尚香","spell": "sun_shangxiang"},{"name": "嚴顏","spell": "yan_yan"},{"name": "于禁","spell": "yu_jin"},{"name": "周瑜","spell": "zhou_yu"},{"name": "諸葛亮","spell": "zhu_geliang"}],"ordinary": [{"name": "步練師","spell": "bu_lianshi"},{"name": "關羽","spell": "guan_yu"},{"name": "郭嘉","spell": "guo_jia"},{"name": "黃蓋","spell": "huang_gai"},{"name": "黃忠","spell": "huang_zhong"},{"name": "魯肅","spell": "lu_su"},{"name": "陸遜","spell": "lu_xun"},{"name": "司馬懿","spell": "si_mayi"},{"name": "孫尚香","spell": "sun_shangxiang"},{"name": "嚴顏","spell": "yan_yan"},{"name": "于禁","spell": "yu_jin"},{"name": "周瑜","spell": "zhou_yu"},{"name": "諸葛亮","spell": "zhu_geliang"}] }就是十三個武將與四種稀有度,分別是傳奇、史詩、精英與普通,抽中概率分別是3%、7%、10%、80%,對應顏色分別是金色、紅色、紫色、藍色
2、index.js
import React from 'react'; import ReactDOM from 'react-dom';// 抽卡相關 import './card.scss'; import CardArea from './components/card/CardArea'; import BtnArea from './components/card/BtnArea'class Game extends React.Component {// 抽卡相關onRef = (ref) => {this.cardArea = ref;}render () {return (<div className="game" style={{ backgroundImage: `url(${require('./images/bg.jpg')})` }}><BtnArea getHeros={ // 調用CardArea的方法() => {this.cardArea.updateCard(10);}} getHero={ // 調用CardArea的方法() => {this.cardArea.updateCard(1);}} /><CardArea onRef={this.onRef} /></div >);} }ReactDOM.render(<Game />,document.getElementById('root') );這個簡單,除了兄弟組件互相調用對方的方法之外也沒什么
3、BtnArea.js
import React from 'react';import History from './History';export default class BtnArea extends React.Component {constructor(props) {super(props);this.state = {times: 0}this.calculationTimes = this.calculationTimes.bind(this) // 方法綁定this的一種解決方案}onRef = (ref) => {this.history = ref}calculationTimes (subtractor) { // 抽獎次數的變化if (this.state.times < subtractor) {alert('抽獎系數不足');return false;} else {this.setState({times: this.state.times - subtractor})}return true;}render () { // 頁面渲染,子組件Historyreturn (<div className="index_page"><History onRef={this.onRef} /><div className="btn_area"><div className="increase_times"><span>{this.state.times}</span><img onClick={() => {this.setState({times: this.state.times + 10})}} src={require('./../../images/add.png')} alt="" /></div><button className="single_btn" style={{ backgroundImage: `url(${require('./../../images/single.png')})` }} onClick={() => {if (this.calculationTimes(1)) {this.props.getHero();}}}>單抽</button><button className="ten_btn" style={{ backgroundImage: `url(${require('./../../images/ten.png')})` }} onClick={() => {if (this.calculationTimes(10)) {this.props.getHeros();}}}>十連抽</button><div className="history_btn" onClick={() => {this.history.getList();}}>抽卡記錄</div></div></div>)} }這是十連抽與單抽按鈕內容,還加上了抽卡記錄
4、Card.js
import React from "react"export default class Card extends React.Component {constructor(props) {super(props);this.state = {underway: false}}getRarity (rarity) { // 將英文轉為中文switch (rarity) {case 'legend':return '傳奇';case 'epic':return '史詩';case 'elite':return '精英';default:return '普通'}}render () { // 單個卡片return (<div className={['card', this.state.underway ? 'flip_card' : ''].join(' ')} onClick={() => {this.setState({underway: true,})}}><div className={["card_face", `rarity_${this.props.cardInfo.rarity}`].join(' ')} style={{ backgroundImage: `url(${require('./../../images/' + this.props.cardInfo.hero.spell + '.jpg')})` }}><div className="card_rarity">{this.getRarity(this.props.cardInfo.rarity)}</div><div className="card_info"><div className="card_name">{this.props.cardInfo.hero.name}</div></div></div><img src={require('./../../images/card_bg.jpg')} alt="" /></div>);} }單個卡片,翻轉卡片動畫用的是切換class再加上CSS動畫功能實現的
5、CardArea.js
import React from 'react'; import Card from './Card';import heros from './../../data/heros.json';export default class CardArea extends React.Component {constructor(props) {super(props);this.state = {cardAreaStatus: false, // 抽卡狀態cardArr: [], // 抽出的卡片indexedDB: null // 本地數據庫}this.addHistory = this.addHistory.bind(this);}componentDidMount () {this.props.onRef && this.props.onRef(this);const request = window.indexedDB.open('History');request.onerror = () => {console.error('Error')}request.onsuccess = (e) => {this.setState({indexedDB: e.target.result})}request.onupgradeneeded = (event) => {const db = event.target.result;let objectStore;console.log(event, db);if (!db.objectStoreNames.contains('heros')) {objectStore = db.createObjectStore('heros', { autoIncrement: true });objectStore.createIndex('id', 'id', { unique: true });objectStore.createIndex('rarity', 'rarity', { unique: false });objectStore.createIndex('name', 'name', { unique: false });}}}addHistory (card) { // 點擊抽卡將抽卡結果加入到indexedDB里console.log(this.state);const customerOS = this.state.indexedDB.transaction(['heros'], 'readwrite').objectStore('heros');const data = {id: Number(Math.random().toString().substr(3, 10) + Date.now()).toString(36),rarity: card.rarity || null,name: card.hero.name || null}const request = customerOS.add(data);request.onsuccess = () => {console.log(data, '數據已新增');}request.onerror = () => {console.error(data);}}// 更新卡池updateCard (num) {this.setState({cardAreaStatus: true,cardArr: this.randomHero(num)})}// 關閉抽卡closeCardArea () {this.setState({cardAreaStatus: false,cardArr: []})}getHeros () { // 獲取單個英雄const rarityNum = Math.floor(Math.random() * 100); // 使用偽隨機數(0 - 100之間的整數)獲取隨機稀有度let rarityArr = heros.ordinary;let rarity = "ordinary";if (rarityNum < 3) { // 此處配置抽卡幾率rarityArr = heros.legend;rarity = "legend";} else if (rarityNum < 10) {rarityArr = heros.epic;rarity = "epic";} else if (rarityNum < 20) {rarityArr = heros.elite;rarity = "elite";}const heroNum = Math.floor(Math.random() * rarityArr.length); // 此處獲取隨機武將const hero = rarityArr[heroNum];const card = {rarity: rarity,hero: hero}this.addHistory(card);return card;}randomHero (num) { // 執行單抽與十連抽操作,按傳入數字判斷const heros = [];for (let i = 0; i < num; i++) {heros.push(this.getHeros());}return heros;}render () { // 生成頁面const cardArea = this.state.cardArr.map((card, index) =><Card key={index} cardInfo={card} />)return (<div className="card_main" style={{ display: this.state.cardAreaStatus ? "flex" : "none", backgroundImage: `url(${require('./../../images/bg_card.jpg')})` }}><div className="close_btn" onClick={this.closeCardArea.bind(this)}><img src={require('./../../images/close.png')} alt="" /></div><div className="card_area">{cardArea}</div></div>);} }這里是抽卡頁,在此處隨機獲取不同稀有度的不同武將
6、History.js
import React from 'react';export default class History extends React.Component {constructor(props) {super(props);this.state = {historyStatus: false,historyList: [],indexedDB: null,count: []}this.getList = this.getList.bind(this);}componentDidMount () {this.props.onRef && this.props.onRef(this);const request = window.indexedDB.open('History');request.onerror = () => {console.error('Error')}request.onsuccess = (e) => {this.setState({indexedDB: e.target.result})}}getList = () => { // 獲取所有抽卡歷史,使用箭頭函數也可以確保this調用沒問題const customerOS = this.state.indexedDB.transaction(['heros'], 'readwrite').objectStore('heros');let dataArr = [];customerOS.openCursor().onsuccess = (event) => {const result = event.target.result;if (result) {dataArr.push(result.value);result.continue();}this.setState({historyStatus: true,historyList: dataArr})}this.getCount();}getRarity (rarity) { // 同樣的英文轉中文switch (rarity) {case 'legend':return '傳奇';case 'epic':return '史詩';case 'elite':return '精英';default:return '普通'}}getCount = () => { // 此處統計抽卡結果,用的是indexedDB自動統計的,當然你也可以用for循環一個一個統計const typeArr = ['legend', 'epic', 'elite', 'ordinary'];let count = [];// 執行事務,從對象倉庫(表)中獲取所有數據const request = this.state.indexedDB.transaction(['heros'], 'readonly').objectStore('heros');for (let index = 0; index < typeArr.length; index++) {const typeCount = request.index('rarity').count(typeArr[index]);//數據獲取成功typeCount.onsuccess = () => {if (typeCount.result) {count.push(typeCount.result);this.setState({count: count})}};}}sumCount () { // 獲取總計的抽獎次數,這里我是遍歷了getCount的結果數組,當然用indexedDB的count方法也可以直接獲取let total = 0;this.state.count.forEach(value => {total += value;});return total;}render () {const historyTab = this.state.historyList.map((history, index) =><tr className={`rarity_${history.rarity}`} key={index}><td>{index + 1}</td><td>{this.getRarity(history.rarity)}</td><td>{history.name}</td></tr>)return (<div className="history_area" style={{ display: this.state.historyStatus ? "flex" : "none" }}><div className="history_list"><table><thead><tr><th>序號</th><th>稀有度</th><th>武將</th></tr></thead><tbody>{historyTab}</tbody></table></div><div className="history_count"><div className="rarity_legend">傳奇:{this.state.count[0]}</div><div className="rarity_epic">史詩:{this.state.count[1]}</div><div className="rarity_elite">精英:{this.state.count[2]}</div><div className="rarity_ordinary">普通:{this.state.count[3]}</div><div className="rarity_total">總計:{this.sumCount()}</div><button onClick={() => {this.setState({historyStatus: false})}}>關閉記錄</button></div></div>)} }具體內容都在代碼里注釋出來了,當然不熟悉indexedDB也可以不要這個內容
7、card.scss
@import "./fonts/font"; html, body {width: 100%;height: 100%;overflow: hidden;margin: 0;padding: 0;/* 設置滾動條的樣式 */::-webkit-scrollbar {width: 5px;}/* 滾動槽 */::-webkit-scrollbar-track {box-shadow: inset006pxrgba(0, 0, 0, 0.3);border-radius: 10px;}/* 滾動條滑塊 */::-webkit-scrollbar-thumb {border-radius: 5px;background: rgba(150, 150, 150, 0.5);box-shadow: inset006pxrgba(0, 0, 0, 0.5);}::-webkit-scrollbar-thumb:window-inactive {background: rgba(255, 0, 0, 0.4);}#root {width: 100%;height: 100%;.game {width: 100%;height: 100%;background-size: 100% 100%;display: flex;align-items: center;justify-content: center;font-family: "AaDingCiShouShu";.rarity_legend {color: #ffd700;.card_rarity {background-color: rgba(255, 215, 0, 0.8);}}.rarity_epic {color: #ff0000;.card_rarity {background-color: rgba(255, 0, 0, 0.8);}}.rarity_elite {color: #800080;.card_rarity {background-color: rgba(128, 0, 128, 0.8);}}.rarity_ordinary {color: #87ceeb;.card_rarity {background-color: rgba(135, 206, 235, 0.8);}}.index_page {.btn_area {.increase_times {position: fixed;top: 2rem;right: 2rem;font-size: 2rem;background-color: rgba(0, 0, 0, 0.5);color: #fff;padding: 0.5rem 1rem;border-radius: 25px;display: flex;align-items: center;img {width: 1.8rem;padding-left: 0.5rem;}}button {width: 12rem;height: 4rem;font-size: 2rem;margin: 0 15rem;border-radius: 4px;color: #ffffff;border: 0;outline: 0;font-family: "AaDingCiShouShu";box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.5);transition: all 0.5s;background-size: 100% 100%;&:hover {outline: 0;}&:active {box-shadow: none;}}.single_btn {background-color: #87ceeb;}.ten_btn {background-color: #ffd700;}.history_btn {position: fixed;bottom: 2rem;right: 2rem;color: #fff;text-decoration-line: underline;cursor: pointer;}}.history_area {position: fixed;width: 100%;top: 0;height: 100%;left: 0;bottom: 0;right: 0;margin: auto;padding: 2rem;background-color: rgba(0, 0, 0, 0.8);border-radius: 4px;z-index: 3;.history_list {width: calc(100% - 20rem);position: relative;table {width: 100%;height: 100%;color: #fff;tbody {display: block;height: calc(100% - 2rem);overflow-y: auto;}thead,tbody tr {display: table;width: 100%;table-layout: fixed;}thead {width: calc(100% - 5px);}th {font-size: 2rem;}td {font-size: 1.6rem;text-align: center;text-shadow: 0 0 1px #fff;}}}.history_count {width: 20rem;div {margin-left: 2rem;font-size: 2rem;height: 4rem;line-height: 4rem;}.rarity_total {color: #fff;}button {position: absolute;right: 2rem;bottom: 2rem;border: 0;padding: 0.5rem 1rem;border-radius: 4px;font-family: "AaDingCiShouShu";}}}}.card_main {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;background-size: inherit;position: absolute;.close_btn {width: 2rem;height: 2rem;position: fixed;top: 2rem;right: 2rem;img {width: 100%;}}.card_area {width: 80%;height: 80%;display: flex;flex-wrap: wrap;justify-content: space-between;align-items: center;.flip_card {animation: flipCard 1s forwards;img {animation: hideBg 0.5s forwards;}}@keyframes flipCard {0% {transform: rotateY(0);}50% {transform: rotateY(90deg);}100% {transform: rotateY(180deg);}}@keyframes hideBg {90% {opacity: 1;}100% {opacity: 0;}}.card {width: calc(20% - 2rem);height: calc(50% - 1rem);border-radius: 8px;margin: 1rem auto;box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);position: relative;img {width: 100%;height: 100%;border-radius: 8px;position: absolute;top: 0;}.card_face {width: 100%;height: 100%;padding: 0.5rem;transform: rotateY(180deg);background-size: cover;border-radius: 8px;text-shadow: 0 0 5px rgba(255, 255, 255, 0.6);.card_rarity {font-size: 1rem;float: right;font-weight: bold;color: #fff;padding: 4px 10px;border-radius: 4px;}.card_info {position: absolute;bottom: 1rem;text-align: center;font-weight: 800;left: 0;right: 0;margin: auto;.card_name {text-shadow: 0 0 10px #000;}}}}}}}} } * {box-sizing: border-box; }這里是樣式文件,內容很多就不一一介紹了
結尾
大體上的代碼都貼出來了,也就是給大家當個例子看看,寫完這個例子對React也就算入門了。
這里是字體文件與圖片文件的下載地址鏈接:
鏈接: 百度云盤-靜態文件 提取碼: 68pi
字體文件很大,可以不要,圖片也能換自己喜歡的,多謝你看完我的文章
總結
以上是生活随笔為你收集整理的React--简单的抽卡模拟器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习中的聚类算法
- 下一篇: 【网络】网络基础