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

Châm ngôn của mình là học để kiếm tiền.

Vì thế mình build các khóa học của mình để giúp anh em tiến bộ nhanh hơn x10 lần , để kiếm được nhiều tiền hơn

  • 🏆 React.js Super: Trở thành React.js Developer trong 7 ngày với mức thu nhập 20 triệu/tháng
  • 🏆 Node.js Super: Giúp bạn học cách phân tích, thiết kế, deploy 1 API Backend bằng Node.js
  • 🏆 Next.js Super: Mình sẽ chia sẻ từ A-Z kiến thức về Next.js, thứ giúp mình kiếm hơn 1 tỉ/năm

💡 Mẹo:

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é.


Kiến thức trong khóa học Next.js này đã giúp mình kiếm hơn 1 tỉ đồng/năm

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ể 😅

Website bạn đang đọc được viết bằng Next.js TypeScript và tối ưu từng chi tiết nhỏ như SEO, hiệu suất, nội dung để đảm bảo bạn có trải nghiệm tốt nhất.

Với lượt view trung bình là 30k/tháng (dù website rất ít bài viết). Website này đem lại doanh thu 1 năm vừa qua là hơn 1 tỉ đồng

Đó chính là sức mạnh của SEO, sức mạnh của Next.js.

Mình luôn tin rằng kiến thức là chìa khóa giúp chúng ta đi nhanh nhất.

Mình đã dành hơn 6 tháng để phát triển khóa học Next.js Super | Dự án quản lý quán ăn & gọi món bằng QR Code. Trong khóa này các bạn sẽ được học mọi thứ về framework Next.js, 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, 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