Facebook đã tạo hiệu ứng xoxo như thế nào?

Trong thời gian gần đây, nhất là sau vụ Facebook làm lộ dữ liệu của 50 triệu người dùng thì hàng loạt fanpage hùa nhau dụ người dùng tương tác bằng cách comment bff để xem nó có nhảy ra hiệu ứng không, nếu có thì tài khoản của bạn an toàn, còn nếu không thì tài khoản của bạn bị ai đó theo dõi. Sự thật thì đó chẳng phải là cách kiểm tra tài khoản mà chỉ là một hiệu ứng Facebook làm ra cho vui được các fanpage sử dụng để câu like. Phải nói thật các bạn admin fanpage giỏi thật, có thể tranh thủ câu like trong mọi hoàn cảnh.

À mà thôi, bài viết này không phải để nói về các bạn fanpage kia, mà là để nói về cách Facebook làm ra cái hiệu ứng để cho vui kia kìa.

Và trước khi bắt đầu thì mình xin quảng cáo một xíu. Nếu các bạn lười đọc thì có thể xem session live coding của mình ở trên channel Youtube cũng của mình luôn. Sau khi xem xong thì nhớ like, subscribe và nhấn thêm cái chuông để luôn được thông báo mỗi khi mình ra video mới nhé!

Rồi, giờ thì bắt đầu vào nội dung chính.

Để giải quyết được vấn đề hiển thị hiệu ứng thì chúng ta sẽ phải giải quyết hai thành phần chính.

  • Xử lý cắt chuỗi ở mỗi status của người dùng để biết được từ khoá hiển thị hiệu ứng có xuất hiện hay không. Việc này có thể xử lý ở frontend hoặc là backend, tuy nhiên cho dù xử lý ở đâu thì chúng ta cũng phải khởi tạo danh sách từ khoá cùng animation tương ứng. Về quan điểm cá nhân thì mình thiên về cách xử lý ở backend, khi đó kết quả trả về của mỗi post sẽ là từ khoá xuất hiện, và animation tương ứng, frontend chỉ việc đơn giản là hiển thị ra theo thông tin mà server trả về, với cách làm này frontend sẽ không phải xử lý quá nhiều, phù hợp để chạy trên những thiết bị di động có cấu hình yếu.
  • Sau khi đã có đầy đủ thông tin để hiển thị thì frontend sẽ làm tìm cách nào đó để chạy những hiệu ứng cho thật mượt mà, và đây sẽ là phần chủ yếu trong bài viết này của mình.

Sau khi tìm hiểu những hiệu ứng của Facebook thì mình biết được họ đã dùng một thư viện có tên là Lottie (tên cũ là bodymovin.js). Thư viện này hỗ trợ chúng ta chạy những hiệu ứng được trích xuất ra từ Adobe After Effect dưới dạng JSON nhờ sự hỗ trợ của plugin bodymovin, và nó cũng giúp chạy trên nhiều nền tảng khác nhau như Web, Android, iOS, React Native.

Để bắt đầu integrate Lottie mình sẽ tạo một project mới bằng Gatsby. Gatsby là một công cụ để giúp chúng ta tạo ra những trang web tĩnh sử dụng ReactJS.

Sau khi đã cài đặt Gatsby, các bạn gõ lệnh gatsby new xoxo để tạo project mới tên là xoxo, và sau khi chạy xong thì thư mục xoxo sẽ được tạo và chứa toàn bộ code của project.

Sau khi cài đặt xong project, các bạn cài đặt thêm thư viện lottie-web bằng lệnh

yarn add lottie-web

Sau khi đã cài đặt xong thì các bạn có thể bắt đầu code được rồi.

Đầu tiên chúng ta sẽ tạo một element xoxo để click vào.

Trong src/pages/index.js các bạn thêm một thẻ span vào trong hàm render.

class IndexPage extends React.Component {
_click = () => {
console.log('clicked')
}
render() {
return (
<div>
<p>
<span
style={{
fontWeight: 'bold',
color: 'purple',
cursor: 'pointer',
}}
onClick={this._click}
>
Click me
</span>
{' to see miracle'}
</p>
</div>
)
}
}
export default IndexPage
view raw index.js hosted with ❤ by GitHub

Như các bạn có thể thấy thì mình đã sửa code từ functional component thành class, mục đích của việc này trong phần kế tiếp mình sẽ giải thích, và nếu các bạn chưa thành thạo ReactJS các bạn có thể tham khảo các series Học ReactJS trong vòng 15 phút hay Học React/Redux qua ví dụ thực tế. Ngoài ra, mình cũng tạo thêm hàm _click để xử lý event click của thẻ span.

Tiếp theo thì mình sẽ gắn animation vào thông qua hàm loadAnimation của lottie. Hàm loadAnimation đòi hỏi chúng ta truyền vào container, đây là element trong cây DOM để chứa animation. Và để xác định được element trong ReactJS chúng ta phải xử lý sau khi component đã được mount, giải thích thêm một xíu thì mount component tức là hành động nhét cái component của chúng ta vào cây DOM, và hành động này chỉ xảy ra một lần duy nhất khi khởi tạo component. Và để xử lý chuyện này thì chúng ta phải dùng đến các life cycle method của React Component, vì thê chúng ta không thể xử dụng functional component được mà phải sử dụng cách create class.

Bây giờ chúng ta thêm life cycle componentDidMount vào trong component.

class IndexPage extends React.Component {
componentDidMount() {
lottie.loadAnimation({
container: this._el,
renderer: 'svg',
animationData: animation,
})
}
render() {
return (
<div>
<p>
<span
style={{
fontWeight: 'bold',
color: 'purple',
cursor: 'pointer',
}}
onClick={this._click}
>
Click me
</span>
{' to see miracle'}
</p>
<div
id="animation"
ref={el => (this._el = el)}
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
left: 0,
}}
/>
</div>
)
}
}
view raw index.js hosted with ❤ by GitHub

Trong đoạn code trên, mình đã gọi hàm loadAnimation trong life cycle componentDidMount, và thay vì mình đặt id cho thẻ div rồi truyền vào containerdocument.getElementById thì mình dùng cú pháp reference của ReactJS. Chắc các bạn đang hỏi animationData ở đâu ra. Lottie cung cấp cho chúng ta một trang web tên là LottieFiles đây là nơi chứa rất nhiều free animation được làm sẵn cho lottie, và các bạn có thể tải về sau đó lấy file json import vào project. Mình cũng chỉ lấy đại một cái trên đây làm mẫu thôi. Nếu các bạn biết Adobe After Effect thì các bạn có thể tự tạo cho mình một cái riêng.

Bây giờ chúng ta sẽ làm cho animation chỉ xuất hiện sau khi click vào chữ Click me. Giải pháp thì vô cùng đơn giản đó là chúng ta sẽ thêm cho component này một state là animationShow, và container của animation chỉ được render khi animationShow là true.

class IndexPage extends React.Component {
constructor(props) {
super(props)
this.state = {show: false}
}
_click = () => {
this.setState({show: true})
setTimeout(() => this.setState({show: false}), 1500)
}
render() {
return (
<div>
<p>
<span
style={{
fontWeight: 'bold',
color: 'purple',
cursor: 'pointer',
}}
onClick={this._click}
>
Click me
</span>
</p>
{this.state.show && (
<div
id="animation"
ref={el => (this._el = el)}
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
left: 0,
}}
/>
)}
</div>
)
}
}
view raw index.js hosted with ❤ by GitHub

Lúc này các bạn chạy thử và bị lỗi vì lottie không thể tìm thấy element container đúng không, đơn giản là nhớ check element tồn tại trước khi gọi hàm loadAnimation nhé.

Tuy nhiên thì sau khi sửa code đã chạy được nhưng khi click thì animation không xuất hiện. Lạ nhỉ.

Việc này có thể lý giải như sau, hàm loadAnimation chỉ được gọi một lần sau khi component được mount, tuy nhiên thì container của nó được update liên tục mỗi lần component được render, vì thế việc sử dụng componentDidMount ở đây sẽ không còn hợp lý nữa, thay vào đó chúng ta sẽ tìm một life cycle nào đó luôn chạy ở mỗi lần render và có thể xử lý được cây DOM, và đó sẽ là componentDidUpdate.

Cuối cùng code của chúng ta sẽ như sau.

class IndexPage extends React.Component {
constructor(props) {
super(props)
this.state = {show: false}
}
componentDidUpdate() {
if (this._el) {
lottie.loadAnimation({
container: this._el,
renderer: 'svg',
animationData: animation,
})
}
}
_click = () => {
this.setState({show: true})
setTimeout(() => this.setState({show: false}), 1500)
}
render() {
return (
<div>
<p>
<span
style={{
fontWeight: 'bold',
color: 'purple',
cursor: 'pointer',
}}
onClick={this._click}
>
Click me
</span>
</p>
{this.state.show && (
<div
id="animation"
ref={el => (this._el = el)}
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
left: 0,
}}
/>
)}
</div>
)
}
}
view raw index.js hosted with ❤ by GitHub

Như vậy là xong!

Bài viết này tuy không khó về mặt kỹ thuật nhưng mình hy vọng nó sẽ giải thích được nhiều thứ khi các bạn sử dụng ReactJS, cũng như sẽ giúp tạo động lực cho các bạn để bắt đầu tìm hiểu những thứ thú vị trong cuộc sống, không kể nó có phải là code hay không, hẹn gặp lại lần sau nhé. À còn nữa, chúng ta đang sống trong thời đại tương tác, nếu các bạn thấy hay và bổ ích, nhớ like và share bài viết này đến nhiều người hơn nhé! Hẹn gặp lại.

Source code của ví dụ trong bài viết các bạn có thể tìm thấy ở https://github.com/codeaholicguy/lottie-sample/

Một suy nghĩ 1 thoughts on “Facebook đã tạo hiệu ứng xoxo như thế nào?

Bình luận