Biến ảnh sprites thành ảnh động với vuejs

Ảnh sprites là gì?

Sprites là một hình ảnh lớn được tạo ra bằng cách gộp nhiều ảnh nhỏ lại với nhau theo một cách được định trước sao cho có thể tái sử dụng lại từng ảnh nhỏ mà không bị ảnh hưởng bởi các ảnh khác.

Kiểu như thế này :

Hoặc các sticker của fb:

Mục tiêu của bài viết

Ưu điểm so với việc dùng ảnh gif

  1. Tôi ưu hơn performance web vì thay vì load ảnh gif thì thay vào đó là anh png.
  2. Có thể tương tác với ảnh (vd: có thể cho ảnh dừng lại hoặc tiếp tục chuyển động, hoặc chuyển động vs số lần nhất định rồi ngừng).
  3. Tùy chỉnh chuyển động nhanh chậm của ảnh.

    Xây dựng component vuejs

    Hướng giải quyết

    Đơn giản chỉ là dùng js để thay đổi background-position qua từng phần của bước ảnh và lặp lại khi đến ảnh cuối vậy là mình đã có 1 ảnh tương tự gif.

Viết component

Khởi tạo các props và style cho component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
<div :style="style">
</div>
</template>

<script>
import { clearInterval } from 'timers';
export default {
props: {
image: String, // Url image
height: Number, // chiều cao của component
width: Number, // chiều rộng của component
loop: Number, // số lần lặp của ảnh
frame: Number, // số hình chạy qua trên 1 giây
max: Number, // số hình của ảnh
column: Number, // số cột
row: Number, // số dòng
},

data(){
// khởi tạo style ban đầu
return {
style: {
width: this.width + 'px',
height: this.height + 'px',
background: `url(${this.image})`,
backgroundSize: `${this.width * this.column}px ${this.height * this.row}px`,
backgroundPosition: '0px 0px'
}
}
},

Tiếp theo chúng ta viết function để ảnh có thể chuyển động.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
methods: {
play() {
let i = 0
let position = {
x: 0,
y: 0,
loop: 0,
} // khởi tạo vị trí ban đầu
const playTimer = setInterval(() => {
i++;
if(i % this.column) {
position.x -= this.width;
} else {
position.y -= this.height;
position.x = 0;
}

if (i == this.max) {
i = 0
position.y = 0;
position.x = 0;
position.loop++;
if(position.loop >= this.loop) {
clearInterval(playTimer)
}
}

this.$set(this.style, 'backgroundPosition', `${position.x}px ${position.y}px`) // set lại style
}, 1000/this.frame);
}
}

Gọi hàm play()

1
2
3
mounted() {
this.play()
},

Vậy là chúng ta đã viết xong component để ảnh chuyện động. full code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<template>
<div :style="style">
</div>
</template>

<script>
export default {
name: 'HelloWorld',
props: {
image: String,
height: Number,
width: Number,
loop: Number,
frame: Number,
max: Number,
column: Number,
row: Number,
},

mounted() {
this.play()
},

data(){
return {
style: {
width: this.width + 'px',
height: this.height + 'px',
background: `url(${this.image})`,
backgroundSize: `${this.width * this.column}px ${this.height * this.row}px`,
backgroundPosition: '0px 0px'
}
}
},

methods: {
play() {
let i = 0
let position = {
x: 0,
y: 0,
loop: 0,
}
const playTimer = setInterval(() => {
i++;
if(i % this.column) {
position.x -= this.width;
} else {
position.y -= this.height;
position.x = 0;
}

if (i == this.max) {
i = 0
position.y = 0;
position.x = 0;
position.loop++;
if(position.loop >= this.loop) {
clearInterval(playTimer)
}
}

this.$set(this.style, 'backgroundPosition', `${position.x}px ${position.y}px`)
}, 1000/this.frame);
}
}
}
</script>

Việc tiếp theo là chúng ta gọi component này ra và sử dụng thôi.

Mình test thử với ảnh này nhé:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div id="app">
<ImageGif
image = "https://images.viblo.asia/a28b8126-1298-4ca7-a507-53865b32238d.png"
:width="100"
:height="100"
:column="7"
:row="4"
:max="27"
:frame="20"
:loop="10"
/>
</div>
</template>

<script>
import ImageGif from './components/image-gif.vue'

export default {
name: 'app',
components: {
ImageGif
}
}
</script>

Thành quả :

https://codesandbox.io/s/vue-template-znn3p

Kết luận

Các bạn cũng có thể tham khảo thêm github:
https://github.com/tuananhp-1844/image-gif