🔥Được vừa ra mắt khóa học Node.js Super đấy, xem thử đi nào

Tạo app ảo thuật với Javascript

🎉 Nếu anh em thấy Front-End cạnh tranh quá thì chúng ta học thêm Back-End thôi.

Mình đang có khóa học🏆 Node.js Super, với các kiến thức như: Express.js, TypeScript, MongoDB, Socket.io, Docker, AWS, Swagger, ...

Vậy nên anh em có thể mua ngay từ bây giờ để tăng khả năng pass phỏng vấn nhé 😉

Hi anh em, hôm nay mình sẽ hướng dẫn mọi người làm một app ảo thuật nho nhỏ với những con số nhé. Đem cái này đi tán gái thì thì xịn luôn nha.


🥇Cách chơi

  1. Đầu tiên bạn sẽ nhập một số 4 chữ số
  2. Mình sẽ ghi ngẫu nhiên một số vào tờ giấy và để sang một bên
  3. Tiếp theo bạn nhập ngẫu nhiên một số 4 chữ số
  4. Mình sẽ nhập ngẫu nhiên một số 4 chữ số phía dưới bạn
  5. Lặp lại bước 3, bạn nhập một số
  6. Lặp lại bước 4, mình nhập một số
  7. Bây giờ ta có tổng 5 số của mình và bạn vừa nhập lúc nãy. Và con số này lại trùng với con số mà mình đã ghi vào tờ giấy ở bước thứ 2 dù cho mình và bạn đều nhập ngẫu nhiên.

Các bạn có thể xem video dưới đây để hiểu rõ luật chơi nhé.


🥇Giải thích quy luật

Bạn thấy vi diệu phải không? Thật ra thì không có gì là ngẫu nhiên cả, mọi thứ đã được tính toán và chỉ có bạn là ngẫu nhiên thôi.

Nếu bạn lấy số của bạn + số của mình phía dưới sẽ luôn bằng 9999. Nếu gọi x là số của bạn và y là số của mình thì ta có.

bash
x1 + x2 + y3 + x4 + y5 = sum
Tương đương
x1 + (x2 + y3) + (x4 + y5) = sum
Tương đương
x1 + 9999 + 9999 = sum
Tương đương
sum = x1 + 19998

Vậy mình chỉ cần lấy số đầu tiên của bạn cộng thêm cho 19998 là sẽ có được kết quả tính tổng.


🥇Hướng dẫn code

Các bạn có thể tham khảo mã muồn tại link Github này

Mình đã chú thích trong code rồi nha.

index.html

html
<!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>Magic Number</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h1 class="title-1">Magic Number</h1>
<div class="main">
<div class="main-control">
<div class="reset-area">
<button class="btn-reset">Reset</button>
</div>
<div class="result"></div>
<form>
<div class="form-group">
<input
type="text"
inputmode="numeric"
pattern="[0-9]*"
placeholder="..."
minlength="4"
maxlength="4"
required
/>
<button type="submit">OK</button>
</div>
</form>
</div>
<div class="main-info">
<h2 class="title-2">Dãy số</h2>
<div class="magic-numbers"></div>
</div>
</div>
<p class="description">Cách chơi:</p>
<p class="description">
Đầu tiên bạn hãy nhập một số có 4 chữ số bất kỳ. Mình sẽ viết một số dự đoán vào một khu vực khác (bạn có thể
click vào để xem trước).
</p>
<p class="description">
Tiếp theo bạn hãy nhập một số gồm 4 chữ số, mình sẽ nhập ngẫu nhiên 4 chữ số phía dưới số của bạn.
</p>
<p class="description">
Làm lại lần nữa, bạn nhập tiếp tục số 4 chữ số, mình sẽ nhập ngẫu nhiên 4 chữ số phía dưới số của bạn.
</p>
<p class="description">
Boom, chúng ta có tổng các dãy số của bạn và mình bằng với con số mà mình đã viết từ trước mặc dầu các con số
của bạn và mình đều ngẫu nhiên!
</p>
</div>
<script src="app.js"></script>
</body>
</html>

app.js

js
// Thứ tự nhập
let turn = 1
// Mảng chứa các số đã nhập
let numbers = []
// Function tạo element
// element này sẽ được chèn vào trong <div class="magic-numbers"></div>
const createMagicNumber = (className, role, value) => {
const node = document.createElement('div')
node.className = className
node.innerHTML = `
<span>${role}</span>
<span>${value}</span>
`
return node
}
const magicNumbersNode = document.querySelector('.magic-numbers')
const resultNode = document.querySelector('.result')
const formNode = document.querySelector('form')
// Lắng nghe sự kiện submit số
formNode.addEventListener('submit', (event) => {
event.preventDefault()
const value = document.querySelector('form input').value
// Tạo element của bạn
const yourNode = createMagicNumber('number number-you', 'Bạn', value)
// Reset ô input sau khi submit
document.querySelector('form input').value = ''
// Nếu là lần đầu tiên thì chỉ cần chèn 1 node là node của bạn
if (turn === 1) {
// Tính nhanh kết quả
// công thức phía dưới tương đương Number(value) + 19998
result = Number('2' + value) - 2
resultNode.innerHTML = `
<div class="result-overlay"></div>
<span>Dự đoán: ${result}</span>
`
resultNode.classList.add('active')
magicNumbersNode.appendChild(yourNode)
numbers.push(Number(value))
turn++
} else {
// Nếu là lần thứ 2 trở đi thì chèn 2 node vào
// là node của bạn và node của mình
const myNode = createMagicNumber('number number-me', 'Mình', 9999 - Number(value))
magicNumbersNode.appendChild(yourNode)
magicNumbersNode.appendChild(myNode)
numbers.push(Number(value), 9999 - Number(value))
turn += 2
}
// Nếu là lượt cuối thì sẽ chèn thêm element tính tổng
if (turn === 6) {
const sumValue = numbers.reduce((current, result) => result + current)
const sumNode = createMagicNumber('number number-sum', 'Tổng', sumValue)
magicNumbersNode.appendChild(sumNode)
// Ẩn cái ô input đi, không cho nhập nữa
formNode.style.display = 'none'
}
})
// Lắng nghe sự kiện nhấn button reset
document.querySelector('.btn-reset').addEventListener('click', () => {
magicNumbersNode.innerHTML = ''
resultNode.innerHTML = ''
resultNode.classList.remove('active')
turn = 1
numbers = []
formNode.style = null
})
// Lắng nghe sự kiện nhấn vào khu vực result.
// Chúng ta sẽ thực hiện làm mờ hoặc xóa làm mờ.
resultNode.addEventListener('click', () => {
document.querySelector('.result-overlay').classList.toggle('hide')
})

Cho thêm một chút css cho đẹp nhé

style.css

css
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 10px;
min-height: 100%;
}
body {
background-color: #0093e9;
background-image: linear-gradient(160deg, #0093e9 0%, #80d0c7 100%);
color: #fff;
font-family: 'Roboto', sans-serif;
font-size: 1.9rem;
padding: 1.5rem;
}
.title-1 {
text-align: center;
font-size: 3rem;
margin-bottom: 1rem;
}
.title-2 {
text-align: center;
font-size: 2.5rem;
margin-bottom: 1rem;
}
.main {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1rem;
margin-bottom: 2rem;
}
.container {
max-width: 400px;
margin: 0 auto;
}
.magic-numbers {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.number {
background: rgba(255, 255, 255, 0.25);
box-shadow: 0 8px 10px 0 rgba(31, 38, 135, 0.2);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.18);
margin-bottom: 1rem;
}
.number.number-me {
background: rgba(255, 255, 89, 0.25);
}
.number.number-sum {
background: rgba(250, 77, 77, 0.25);
}
.number span {
padding: 1rem;
display: inline-block;
}
.number span:first-child {
width: 70px;
}
form {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.reset-area {
text-align: center;
margin-bottom: 1rem;
}
.reset-area .btn-reset {
padding: 1rem 1.5rem;
font-size: 1.9rem;
background-color: #fe5f55;
transition: 0.2s background-color;
cursor: pointer;
color: #fff;
border: 0;
border-radius: 3px;
}
.reset-area .btn-reset:hover {
background-color: #fe2f22;
}
.result {
display: none;
position: relative;
text-align: center;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0 20px 30px rgba(0, 0, 0, 0.1);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.18);
margin: 2rem auto;
cursor: pointer;
}
.result.active {
display: block;
}
.result-overlay {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(3px);
-webkit-backdrop-filter: blur(3px);
}
.result-overlay.hide {
display: none;
}
.form-group {
position: relative;
border: 1px solid rgba(255, 255, 255, 0.18);
display: flex;
align-items: center;
height: 5rem;
background: #fff;
border-radius: 3px;
}
.form-group input {
border: 0;
height: 100%;
padding: 1rem;
font-size: 2rem;
width: 100px;
outline: none;
}
.form-group button {
font-size: 1.6rem;
padding: 1rem;
background: #fb5533;
color: #fff;
border: 0;
cursor: pointer;
border-radius: 3px;
margin-right: 2px;
}
.description {
margin-bottom: 1rem;
font-size: 1.4rem;
}

🥇Test app

Mọi người có thể vào link này https://magic-number.vercel.app/ để test hoặc test trực tiếp trên blog của mình.

Một app ảo thuật đơn giản nhưng cũng khá thú vị, giúp chúng ta rèn luyện các thao tác DOM trên Javascript. Anh em cũng có thể đem cái này đi gây ấn tượng với crush cũng được ^^!, có kết quả nhớ feedback mình biết với nhé.


Khóa học ReactJs giúp bạn chinh phục mức lương 25 - 30 triệu/tháng

Phew! Cuối cùng bạn cũng đã đọc xong. Bài viết này có hơi dài một tí vì mình muốn nó đầy đủ nhất có thể 😅

Chúng ta đều hiểu rằng Javascript và React không hề dễ, chúng có quá nhiều concept cần phải học. Mình cũng cảm thấy nó khó! Nay lại có thể Typescript nữa 🥲, thật sự khó nuốt.

Nhưng đừng lo: Bạn có thể nắm vững các kiến thức trên chỉ trong một khóa học ReactJs Super - Shopee Clone Typescript

Mình đã bắt đầu code React vào năm 2019, và nó đã trở thành thư viện ưa thích của mình để xây dựng UI và web app. Mình cũng đã làm việc với nhiều framework khác như Angular, Vue nhưng thực sự chỉ có React là đem lại cho mình cảm xúc và sự hiệu quả. 💓

Nếu bạn đang gặp khó khăn với React, mình ở đây để giúp bạn!

Mình đã dành hơn 6 tháng để phát triển khóa học ReactJs Super - Shopee Clone Typescript. Trong khóa này bạn sẽ được học mọi thứ về thư viện ReactJs, các kiến thức từ cơ bản cho đến nâng cao nhất, mục đích của mình là giúp bạn chinh phục mức lương 25 - 30 triêu/tháng

Nếu bạn cảm thấy bài viết này của mình hữu ích, mình nghĩ bạn sẽ thích hợp với phong cách dạy của mình. Không như bài viết này, khóa học là sự kết hợp giữa các bài viết, video, quizz, bài tập nhỏ và dự án lớn có thể xin việc được ngay. Học xong mình đảm bảo bạn sẽ lên tay ngay. 💪🏻

Avatar Dư Thanh Được
Dư Thanh Được
Một developer thích nghiên cứu và chia sẻ kiến thức về lập trình, blockchain, marketing. Chuyên code và dạy lập trình website