Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Time: {{time}} s
Moves: {{moves}}
Finish: {{correctItems.length / 2}}/18
RESET
{{counting}}
Press me to START
* { box-sizing: border-box; } a:hover { cursor: pointer; } body { padding: 0; margin: 0; background-color: rgb(79, 39, 20); height: 100vh; width: 100vw; display: flex; align-items: center; justify-content: center; } #app { position: relative; height: 482px; width: 887px; background-image: url("https://dlgarenanow-a.akamaihd.net/mgames/ftmtw/dl/h5/20220128_twolayer/modal/rewards_bg_01.png"); font-family: "Kdam Thmor Pro", sans-serif; font-size: 28px; } .container { display: flex; margin: 20px 15px 70px 15px; flex-wrap: wrap; } .cell-move { transition: transform 1s; } .flip-card { cursor: pointer; background-color: transparent; width: 95px; height: 95px; &_shake { animation: shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; transform: translate3d(0, 0, 0); backface-visibility: hidden; } } @keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 20%, 80% { transform: translate3d(2px, 0, 0); } 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } 40%, 60% { transform: translate3d(4px, 0, 0); } } .flip-card-inner { position: relative; width: 100%; height: 100%; text-align: center; transition: transform 0.6s; transform-style: preserve-3d; } .flip-card-inner_click { transform: rotateY(180deg); } .flip-card-front, .flip-card-back { position: absolute; width: 100%; height: 100%; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .flip-card-front { background-image: url("https://dlgarenanow-a.akamaihd.net/mgames/ftmtw/dl/h5/20220128_twolayer/modal/reward_icon.png"); } .flip-card-back { display: flex; align-items: center; justify-content: center; background: url("https://dlgarenanow-a.akamaihd.net/mgames/ftmtw/dl/h5/20220128_twolayer/modal/icon_04.png") center no-repeat; transform: rotateY(180deg); &_correct { background: url("https://dlgarenanow-a.akamaihd.net/mgames/ftmtw/dl/h5/20220128_twolayer/modal/icon_01.png") center no-repeat; animation: flicker 0.2s ease alternate 3; } &_shake { background: url("https://dlgarenanow-a.akamaihd.net/mgames/ftmtw/dl/h5/20220128_twolayer/modal/icon_03.png") center no-repeat; } } @keyframes flicker { 0% { opacity: 0; } 100% { opacity: 1; } } .buttons { position: absolute; bottom: 20px; display: flex; width: 100%; justify-content: space-evenly; } .start { display: flex; padding: 5px; max-width: 400px; position: relative; cursor: pointer; &:before { position: absolute; left: 0; bottom: 0; content: ""; display: block; width: 100%; height: 100%; background-color: rgb(79, 39, 20); transform-origin: 0 bottom 0; transform: scaleY(0); transition: 0.4s ease-out; } &:hover { .start-title { color: #fff; } &:before { transform: scaleY(1); } } } .start-title { position: relative; font-weight: 700; line-height: 1.333; transition: 0.4s ease-out; }
new Vue({ el: "#app", data() { return { clickItems: [], correctItems: [], shakeItems: [], moves: 0, time: 0, timerId: null, counting: 8, isStarting: false, started: false, shuffling: false, lock: true, list: Array.apply(null, { length: 36 }).map(function (_, index) { return { id: index, pairId: Math.ceil((index + 1) / 2) }; }) }; }, methods: { checkClick(index) { return this.isStarting || this.clickItems.some((i) => i.index === index); }, checkCorrect(index) { return this.correctItems.some((i) => i.index === index); }, checkShake(index) { return this.shakeItems.some((i) => i.index === index); }, click(i, index) { if (this.clickItems.some((c) => c.index === index) || this.lock) return; const item = { ...i, index }; this.clickItems.push(item); if (this.clickItems.length < 2 || this.clickItems.length % 2 !== 0) return; this.moves++; this.lock = true; if (this.clickItems[this.clickItems.length - 2]?.pairId !== i.pairId) { setTimeout(() => { this.shakeItems.push(this.clickItems[this.clickItems.length - 1]); this.shakeItems.push(this.clickItems[this.clickItems.length - 2]); }, 300); setTimeout(() => { this.clickItems.pop(); this.clickItems.pop(); this.lock = false; }, 600); setTimeout(() => { this.shakeItems = []; }, 900); } else { setTimeout(() => { this.correctItems.push(this.clickItems[this.clickItems.length - 2]); this.correctItems.push(this.clickItems[this.clickItems.length - 1]); this.lock = false; }, 600); } }, shuffle() { this.list = _.shuffle(this.list); }, start() { const duration = 1000; const counter = setInterval(() => { if (this.counting > 0) { this.counting--; } }, duration); this.shuffling = true; this.shuffle(); setTimeout(() => this.shuffle(), duration); setTimeout(() => this.shuffle(), duration * 2); setTimeout(() => { this.shuffling = false; this.isStarting = true; counter; }, duration * 3); setTimeout(() => { clearInterval(counter); this.counting = 8; this.isStarting = false; this.lock = false; this.started = true; }, duration * 8); }, reset() { this.clickItems = []; this.correctItems = []; this.shakeItems = []; this.moves = 0; this.time = 0; clearInterval(this.timerId); this.timerId = null; this.counting = 8; this.isStarting = false; this.started = false; this.shuffling = false; this.lock = true; } }, watch: { started(state) { this.timerId = setInterval(() => this.time++, 1000); if (state) { this.timerId; } else { clearInterval(this.timerId); this.time = 0; } }, finish(state) { if (state) { clearInterval(this.timerId); this.lock = true; } } }, computed: { finish() { return this.correctItems.length >= 36; } } });