Tôi không có tài năng gì cả. Tôi chỉ đam mê hiểu biết
 Tạo Hiệu Ứng Đánh Chữ JS

Tạo Hiệu Ứng Đánh Chữ JS


Ngày 17 Tháng 2 Năm 2020

Tạo Hiệu Ứng Đánh Chữ JS

Xin chào các bạn quay lại blog của mình. Hôm nay mình sẽ giới thiệu cách tạo hiệu ứng đánh chữ bằng HTML, CSS và Javascript. Để hiểu rõ hơn các bạn cùng mình tìm hiểu nhé!

Hiệu Ứng Đánh Chữ

Đi vào bước thứ nhất các bạn tạo một thư mục có cấu trúc file như sau nhé:

Cấu trúc Thư Mục TẠo Hiệu Ứng Đánh Chữ Javascript

Sau khi đã tạo xong cấu trúc thư mục thì bước tiếp theo là các bạn tải một tập tin mà mình đã chứa sẵn các file đã được nén để ở đường dẫn bên dưới giúp các bạn không cần phải mất thời gian để tạo các file HTML, CSS và hình ảnh.
Tải File Hieu_ung_danh_chu

Bây giờ mình sẽ tạo cấu trúc file HTML, thêm các thẻ HTML cần thiết cho trang_chinh.html sau đó liên kết nó với file style.css và hieu_ung_chu.js để dễ hiệu chỉnh. Các bạn lưu ý là đường dẫn style.css lúc nào cũng nằm dưới cùng trong thẻ <head> của một trang HTML bởi vì khi ta chỉnh sửa CSS thì nó sẽ không bị ảnh hưởng bởi các file CSS khác. Để nắm rõ hơn các bạn theo dõi đoạn code dưới đây nhé:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hiệu Ứng Chữ</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="hieu_ung_chu">
        <h1>Hãy cùng nhau tìm hiểu về  <span class="danh_chu" data-thoiGianDoi="1500" data-chu='["HTML", "CSS", "JAVASCRIPT"]'></span></h1>
        <h2>Chào mừng các bạn đến với Website của mình.</h2>
    </div>
    <script src="hieu_ung_chu.js"></script>
</body>
</html>

Như các bạn thấy ở đây có hai thuộc tính cho thẻ span là data-thoiGianDoi và data-chu. Đây là một thuộc tính mới trong HTML5 có cấu trúc tổng quát là data-* với * là tên các bạn có thể đặt tùy ý giúp chúng ta lưu các thông tin thêm về đối tượng HTML. Ở ví dụ này là thuộc tính thời gian đợi và thuộc tính chữ cho thẻ span và nếu muốn tìm hiểu thêm thì các bạn tham khảo ở đây nhé: Tham Khảo. Cách lấy dữ liệu này mình sẽ nói ở phần Javascript còn bây giờ chúng ta cùng chỉnh CSS giúp thiết lập ảnh nền, màu sắc cho font cũng như các thẻ có trong <body>. Để hiểu rõ hơn các bạn xem đoạn code dưới đây nhé:

body{
    height: 100vh;
    background: #000 url('hinh_anh.jpg') no-repeat center center / cover;
    color:#fff;
    overflow: hidden;
}
.hieu_ung_chu {
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    padding: 0 3rem;
}
h1, h2{
    font-weight: 200;
    margin: 0.4rem;
}
h1{
    font-size: 3.5rem;
}
h2{
    font-size:2rem;
}
.tu {
   border-right: 0.2rem solid #ccc; 
}
@media(min-width: 1200px) {
    h1{
        font-size: 5rem;
    }
}
@media(max-width: 800px){
    .hieu_ung_chu{
        padding: 0 1rem;
    }
    h1{
        font-size: 3rem;
    }
}
@media(max-width:500px) {
    h1 {
        font-size: 2.5rem;
    }
    h2{
        font-size: 1.5rem;
    }
}

Và chúng mình cùng xem kết quả nhé:

Ảnh Hiệu ứng đánh chữ phiên bản HTML

Chúng ta thiết lập ảnh nền bằng ảnh mà mình đã để ở trong đường dẫn tải thư mục ở trên hoặc các bạn có thể dùng hình tùy ý nhưng chất lượng ảnh phải cao tí vì nếu thấp thì sẽ dễ bị vỡ ảnh nhé. Và chỉnh thẻ <div class="hieu_ung_chu"> nằm giữa màn hình theo chiều cao thông qua display:flex;flex-direction: column;justify-content: center; sau đó chỉnh cỡ chữ cho các thẻ h1, h2. Ở đây có lưu ý nhỏ là thuộc tính @media giúp chúng ta có thể căn chỉnh trang web trên nhiều thiết bị khác nhau. Để hiểu rõ hơn các bạn tham khảo ở đây nha: Tham Khảo.

Bây giờ chúng ta sẽ đi vào thiết lập file Hieu_ung_danh_chu.js. Bước đầu tiên mình sẽ tạo một đối tượng có tên là hieu_ung_danh_chu dùng chứa các thông tin cần thiết và hàm ham_danh_chu() để có thể tạo được hiệu ứng này. Để hiểu rõ các bạn xem đoạn code sau nhé:

const hieu_ung_danh_chu = function(the_html_chua_chu, chu, thoiGianDoi) {
    this.the_html_chua_chu = the_html_chua_chu;
    this.chu = chu;
    this.tu = '';
    this.vi_tri_index_chu = 0;
    this.thoiGianDoi = parseInt(thoiGianDoi, 10);
    this.ham_danh_chu();
    this.dang_xoa_chu = false;
}

Để nắm rõ hơn mục đích của các biến thì các bạn xem đoạn demo sau khi hiệu ứng được hoàn thành. Sau đó mình sẽ giải thích để các bạn dễ hình dung hơn:

Ok bây giờ các bạn theo dõi bảng sau đây để hiểu chức năng của từng biến nhé:

BiếnÝ Nghĩa
this.the_html_chua_chuLà nơi mà chúng ta sẽ hiển thị nội dung hiệu ứng chữ.
this.chuLà nơi chứa mảng ["HTML", "CSS", "JAVASCRIPT"] bằng cách lấy thông qua thuộc tính data-chu
this.thoiGianDoiLà biến chứa thời gian của hiệu ứng bằng cách lấy thông qua thuộc tính data-thoiGianDoi sau đó được chuyển sang số bởi hàm parseInt
this.tuBiến lưu trữ các từ của chữ. Khi đi vào sâu mình sẽ giải thích rõ hơn nhé.
this.vi_tri_index_chuLà biến lưu vị trí chỉ mục(index) của chữ hiện tại trong mảng. Để vào sâu mình sẽ nói công dụng nhé.
this.ham_danh_chu();Đây là hàm chính sẽ xử lý logic để tạo hiệu ứng.
this.dang_xoa_chuĐây sẽ là biến theo dạng true hoặc false giúp ta xác định khi nào chuyển sang chữ mới hay là xóa chữ. Để hiểu các bạn xem lại video trên nhé!

Thì bây giờ chúng ta sẽ gọi một hàm là chay_ham có chức năng sẽ lấy các giá trị thẻ HTML cần thiết để lưu vào các biến trên bằng cách khởi tạo mới một đối tượng hieu_ung_danh_chu. Hàm này sẽ chạy mỗi khi mà trang được load. Để hiểu rõ hơn các bạn xem đoạn code nhé:

document.addEventListener('DOMContentLoaded', chay_ham);
function chay_ham() {
    const the_html_chua_chu = document.querySelector('.danh_chu');
    const chu = JSON.parse(the_html_chua_chu.getAttribute('data-chu'));
    const thoiGianDoi = the_html_chua_chu.getAttribute('data-thoiGianDoi');
         new hieu_ung_danh_chu(the_html_chua_chu, chu, thoiGianDoi);
}

Các bạn để ý là sự kiện DOMContentLoaded sẽ được kích hoạt khi trang HTML đã tải xong mà không phải chờ tải hình ảnn, css của trang đó. Trong hàm chay_ham thì mình sẽ lấy ra đối tượng HTML <span class="danh_chu"> sẽ hiển thị chữ hiệu ứng sau khi nó hoàn thành và lấy thông tin về hai thuộc tính là data-chu và data-thoiGianDoi. Sau đó ta mới khởi tạo mới đối tượng hieu_ung_danh_chu với tham số là 3 thông tin trên. Kế tiếp ta sẽ thiết lập hàm ham_danh_chu xử lý các logic để tạo có thể tạo ra được hiệu ứng. Các bạn theo dõi đoạn code để nắm rõ hơn nhé:

hieu_ung_danh_chu.prototype.ham_danh_chu = function () {
    const index_chu_hien_tai = this.vi_tri_index_chu % this.chu.length;
    const chu_hien_tai = this.chu[index_chu_hien_tai];
    console.log(chu_hien_tai);
    setTimeout(() => this.ham_danh_chu(), 500);
}

Ở đây mình sẽ lấy ra vị trí hiện tại của chữ và đặt mặc định nó là 0. Khi đó ta sẽ có được chữ hiện tại thông qua this.chu[index_chu_hien_tai] nghĩa là trong biến chu chứa mảng ["HTML", "CSS", "JAVASCRIPT"] sẽ gọi như sau chu[0],chu[1] và chu[2]. Lưu ý nhỏ là mình dùng dấu %(chia lấy dư) để tìm ra vị trí index chữ hiện tại bởi vì nó sẽ giúp ta gọi được tuần hoàn có nghĩa là: 0 % 3 = 0, 1 % 3 = 1, 2 % 3 = 2, 3 % 3 = 0 => Ta quay lại từ đầu và cứ tiếp tục gọi như thế. Và hàm setTimeout() sẽ thực hiện một hàm nào đó theo thời gian đã cho. Bây giờ chúng mình xem kết quả nhé:

Do bây giờ mặc định index_chu_hien_tai của ta là 0 nên nó sẽ hiện ra "HTML" trong bảng console của Google Chorme mỗi 0.5s . Tiếp theo sẽ thiết lập điều kiện là nếu dang_xoa_chu=true thì sẽ xóa từng từ trong chữ còn dang_xoa_chu=false thì sẽ thêm từ tới khi hoàn thành chữ. Và thực hiện hiệu ứng bằng cách thêm vào thẻ <span class="danh_chu"> một thẻ span nữa với nội dung là biến tu. Để hiểu rõ hơn các bạn xem đoạn code nhé:

hieu_ung_danh_chu.prototype.ham_danh_chu = function () {
    const index_chu_hien_tai = this.vi_tri_index_chu % this.chu.length;
    const chu_hien_tai = this.chu[index_chu_hien_tai];
    console.log(chu_hien_tai);
    if(this.dang_xoa_chu) {
        this.tu = chu_hien_tai.substring(0, this.tu.length - 1);
    } else {
        this.tu = chu_hien_tai.substring(0, this.tu.length + 1);
    }
    this.the_html_chua_chu.innerHTML = `<span class="tu">${this.tu}</span>`;
    setTimeout(() => this.ham_danh_chu(), 500)
}

Do mặc định biến dang_xoa_chu của chúng ta bằng false nên hàm sẽ thực hiện điều kiện thứ hai. Để dễ hình dung các bạn xem video dưới đây nhé:

Các bạn có thể thấy là nó mới chạy được một chữ vì ta chưa thiết lập logic chuyển sang chữ tiếp theo cho nó. Bây giờ ta sẽ gọi một câu lệnh if/else dùng để kiểm tra xem
Trường hợp 1: Nếu biến dang_xoa_chu = false và từ hiện tại đã hoàn thành bằng cách so sánh this.tu === chu_hien_tai: ta sẽ đổi dang_xoa_chu = true
Trường hợp 2: Nếu biến dang_xoa_chu = true và từ hiện tại bằng rỗng bằng cách so sánh this.tu === "": ta sẽ đổi dang_xoa_chu = fale và vị trí index chữ hiện tại sẽ cộng thêm 1(sẽ chạy sang từ tiếp theo).
Để dễ hình dung các bạn xem đoạn code sau đây nhé:

hieu_ung_danh_chu.prototype.ham_danh_chu  =  function  ()  {
        const  index_chu_hien_tai  =  this.vi_tri_index_chu  %  this.chu.length;
        const  chu_hien_tai  =  this.chu[index_chu_hien_tai];
        console.log(chu_hien_tai);
        if(this.dang_xoa_chu)  {
                this.tu  =  chu_hien_tai.substring(0,  this.tu.length  -  1);
        }  else  {
                this.tu  =  chu_hien_tai.substring(0,  this.tu.length  +  1);
        }
        this.the_html_chua_chu.innerHTML  =  `<span  class="tu">${this.tu}</span>`;
        if(!this.dang_xoa_chu  &&  this.tu  ===  chu_hien_tai)  {
                this.dang_xoa_chu  =  true;
        }  else  if  (this.dang_xoa_chu  &&  this.tu  ===  ''){
                this.dang_xoa_chu  =  false;
                this.vi_tri_index_chu++;
        }
        setTimeout(()  =>  this.ham_danh_chu(),  500)
}

Bây giờ chúng ta cùng xem kết quả nhé:

Nhìn thời gian hiệu ứng chưa được thích hợp lắm nhỉ giờ chúng ta sẽ thiết lập là thời gian xóa chữ sẽ nhanh hơn thời gian thêm chữ. Để hiểu rõ các bạn xem đoạn code sau nhé:

hieu_ung_danh_chu.prototype.ham_danh_chu = function() {
    const index_chu_hien_tai = this.vi_tri_index_chu % this.chu.length;
    const chu_hien_tai = this.chu[index_chu_hien_tai];
    if(this.dang_xoa_chu) {
        this.tu = chu_hien_tai.substring(0, this.tu.length - 1);
    } else {
        this.tu = chu_hien_tai.substring(0, this.tu.length + 1);
    }
         this.the_html_chua_chu.innerHTML = `<span class="tu">${this.tu}</span>`
    let toc_do_danh_chu = 300;
    if(this.dang_xoa_chu) {
        toc_do_danh_chu = toc_do_danh_chu /2;
    }
    if(!this.dang_xoa_chu && this.tu === chu_hien_tai) {
        toc_do_danh_chu = this.thoiGianDoi;
        console.log(this.thoiGianDoi);
        this.dang_xoa_chu = true;
    } else if (this.dang_xoa_chu && this.tu === ''){
        this.dang_xoa_chu = false;
        this.vi_tri_index_chu++;
        toc_do_danh_chu = 300;
    }
    setTimeout(() => this.ham_danh_chu(), toc_do_danh_chu);
}

Kết quả cuối cùng của chúng ta là:

Mình cũng gửi các bạn đường dẫn để tải về những file trong thư mục Hieu_ung_danh_chu để bạn đễ hình dung và có thể xem lại!
Đường dẫn tải File Source Code

Tổng kết:

Qua đây mình mong bài viết sẽ giúp các bạn ôn lại kiến thức, vận dụng hiệu quả trong thực tiễn và nếu có thắc mắc gì cứ gửi email mình sẽ phản hồi sớm nhất có thể. Rất mong bạn tiếp tục ủng hộ trang web để mình có thể viết nhiều bài hay hơn nữa nhé. Chúc bạn có một ngày vui vẻ!