Khi cân nhắc đặt hàng phát triển ứng dụng web hoặc ứng dụng di động mới, sáng tạo và thân thiện với người dùng, các doanh nhân và người khởi nghiệp thường nghĩ đến việc chuyển sang HTML [ngôn ngữ đánh dấu siêu văn bản]
Rất tự nhiên, bạn chọn phiên bản mới nhất của ngôn ngữ phổ biến được giới thiệu vào năm 2014, dựa trên quy trình mã hóa SCC và JavaScript
Các nhà phát triển tài năng và có tầm nhìn xa trên khắp thế giới chuyển sang HTML5 để tiết kiệm chi phí bảo trì, sử dụng các tùy chọn lưu trữ nâng cao, hợp lý hóa và tối ưu hóa quá trình phát triển ứng dụng di động bằng HTML5
Công nghệ trao quyền cho các chuyên gia tài năng của chúng tôi để xây dựng mã sạch, hiệu quả, nhỏ gọn. Môi trường phát triển có lợi và thư viện phong phú cho phép rút tiền ngoại tuyến, cho phép sử dụng các thành phần trang web đã xem trước đó mà không cần kết nối mạng. Ngoài ra, tất cả các ứng dụng dựa trên HTML5 đều tương thích với hầu hết các trình duyệt được sử dụng rộng rãi như Opera, Firefox hoặc Chrome
Trong khi đó, một số thách thức do việc sử dụng ngôn ngữ tồn tại. Ứng dụng web HTMP5 có thể chạy chậm hơn ứng dụng gốc được thiết kế đặc biệt cho nền tảng nhất định [Android hoặc iOS] hoặc thiết bị di động
Nó không phải là hiệu quả nhất và không phải là tiên tiến nhất về bảo mật và hiệu suất. Vì vậy, tại sao chúng tôi sử dụng HTML5 cho các tác phẩm độc đáo của mình?
HTML5 là gì?
HTML5 là phiên bản mới nhất [thứ năm] của ngôn ngữ đánh dấu phổ biến và là công nghệ biến đổi trang web, giúp các trang web có thể truy cập được từ cả thiết bị di động và máy tính để bàn. Nó kết hợp 3 loại mã
HTML cho cấu trúc;
CSS [Cascading Style Sheets] để trình bày;
Sử dụng JavaScript cho API [Giao diện lập trình ứng dụng] để xây dựng trang web
Do đó, với HTML5, bạn không cần các giải pháp phần mềm bổ sung. Bạn có thể xem phim, nghe nhạc, tìm kiếm thông tin trực tuyến cần thiết, v.v. Ngôn ngữ đa nền tảng tương thích với mọi netbook, máy tính bảng hoặc Smart TV. Nó thân thiện với nhà phát triển, cho phép mọi ứng dụng HTML5 hoạt động trơn tru và hoàn hảo. Ngoài ra, nó là mã nguồn mở, vì vậy, chúng tôi không trả bất kỳ khoản tiền bản quyền nào khi sử dụng nó
HTML5 JavaScript Phát triển ứng dụng di động
Bộ công cụ khung với các thư viện phong phú [như JQuery], nhiều mô-đun tiện dụng, dễ tùy chỉnh rất có lợi cho các nhà phát triển tài năng, giàu kinh nghiệm của chúng tôi. Nó giúp chúng tôi cải thiện hiệu suất ứng dụng, sử dụng nhiều phần tử DOM [Mô-đun đối tượng tài liệu]. Công nghệ này rất hữu ích để thúc đẩy tính tương tác của trang web, cho phép hoạt ảnh, truyền phát âm thanh và video
Tại đây, tại Công ty Woxapp, việc phát triển ứng dụng di động với HTML5 và jQuery rất chuyên nghiệp và tiết kiệm chi phí. Bộ công cụ giúp công việc mã hóa và lập trình trở nên dễ dàng hơn đối với các nhà phát triển và nhà thiết kế web tài năng của chúng tôi, vì nhiều khía cạnh tạo ứng dụng được sắp xếp hợp lý và hỗ trợ
Do đó, chúng tôi sử dụng công nghệ HTML5 cho các ứng dụng iOS và Android hướng đến mục tiêu của mình, được thiết kế cho ngành thể dục và chăm sóc sức khỏe, tìm kiếm nhà hàng, nhà vận chuyển và giao nhận vận chuyển, định vị địa lý, mua sắm trực tuyến
Chúng tôi làm việc chăm chỉ để tạo UX [trải nghiệm người dùng] xuất sắc, điều chỉnh các tính năng ứng dụng HTMP5 độc đáo của chúng tôi cho các thiết bị di động và HĐH [hệ điều hành] đặc biệt
Trong khi đó, các nhà phát triển giàu kinh nghiệm của chúng tôi có năng lực và sáng tạo, vì vậy chúng tôi kết hợp các công nghệ HTML5 tiên tiến với các ngôn ngữ và nền tảng tương thích khác để đảm bảo hiệu suất và tốc độ tải ứng dụng tốt nhất có thể
Các tính năng ứng dụng di động HTML5 cơ bản
Vì vậy, chúng tôi phát triển các ứng dụng Android với HTML5 và JavaScript bằng cách sử dụng các tính năng phong phú của cả hai ngôn ngữ
Những yếu tố vô song này bao gồm
hỗ trợ âm thanh/video;
hoạt động đa ngôn ngữ [khả năng tiếp cận];
bộ nhớ đệm ngoại tuyến;
thiết kế thân thiện với thiết bị di động [đáp ứng];
đáng tin cậy, lưu trữ thông minh;
mã sạch;
định vị địa lý;
tương tác tốt hơn
Các ứng dụng dựa trên HTML5 của chúng tôi giúp mọi tài nguyên trực tuyến, tệp âm thanh và video có thể truy cập được. Mã JavaScript thanh lịch, đơn giản và dễ đọc. HTML5 cho phép các tùy chọn lưu trữ cục bộ hoàn hảo và an toàn
Ngay cả khi bạn đóng cửa sổ, dữ liệu và cookie của bạn vẫn được lưu trong trình duyệt của bạn. Do đó, chúng tôi sử dụng ngôn ngữ HTML5 tiên tiến cùng với nhiều công nghệ phát triển hiệu quả khác và tương lai thuộc về nó
Vì vậy, bạn đã thấy tiêu đề và bạn đang tự hỏi làm thế nào bạn có thể xây dựng một ứng dụng di động thực tế chỉ bằng cách sử dụng kiến thức về các công nghệ web cơ bản mà không cần phải học phát triển Android hoặc IOS? . Bằng cách này, chúng tôi sẽ đạt được một loại ứng dụng được gọi là Ứng dụng web lũy tiến [PWA]
Trong bài viết này, chúng ta sẽ tìm hiểu cách tận dụng sức mạnh của HTML, CSS và Javascript để xây dựng một ứng dụng di động đơn giản. Chúng tôi sẽ không sử dụng các framework như Ionic hoặc React Native. Điều này là do hướng dẫn này tập trung vào việc chỉ ra cách một ứng dụng web cơ bản có thể được tạo ra để cảm nhận và hoạt động giống như một ứng dụng di động gốc có thể được cài đặt và chạy trên thiết bị di động bằng phương pháp đơn giản nhất với ít trừu tượng nhất
Để tiếp tục, chúng ta hãy giới thiệu ngắn gọn về PWAs
Ứng dụng web lũy tiến là gì?
Theo Tài liệu web MDN chính thứcỨng dụng web lũy tiến [PWA] là các ứng dụng web sử dụng nhân viên dịch vụ, bảng kê khai và các tính năng nền tảng web khác kết hợp với tính năng nâng cao lũy tiến để mang đến cho người dùng trải nghiệm ngang bằng với các ứng dụng gốc
Nói một cách đơn giản, về cơ bản, chúng là các trang web được tạo kiểu giống như các ứng dụng có thể chạy bên trong trình duyệt trang web hoặc được cài đặt trực tiếp trên thiết bị di động và được truy cập như một ứng dụng gốc
Có ba thành phần chính của PWA;
- Nhân viên phục vụ. Nhân viên dịch vụ biến trang web thành một ứng dụng bằng cách cho phép trang web tải xuống và lưu trữ các tệp trên thiết bị
- Bản kê khai web. Tệp JSON này cung cấp siêu thông tin cơ bản về ứng dụng, chẳng hạn như biểu tượng ứng dụng, màu nền, v.v.
- HTTPS an toàn. HTTPS là bắt buộc và làm cho PWA an toàn hơn các ứng dụng web thông thường
PWA có ưu và nhược điểm. Trong số những người trước đây
- Giá rẻ và phát triển nhanh. PWA ít tốn kém hơn, nhanh hơn và dễ tạo hơn các ứng dụng gốc. Phát triển ứng dụng gốc từ đầu đòi hỏi các công nghệ cụ thể cho cả hai nền tảng. HTML, CSS và JavaScript là tất cả những gì cần thiết cho PWA
- Tính khả dụng đa nền tảng. Một trong những lợi thế đầy hứa hẹn của PWAs là chúng có thể được cài đặt và chạy trên nhiều thiết bị trên nhiều hệ điều hành khác nhau
- Chức năng ngoại tuyến. Việc không có hoặc không có internet sẽ không ngăn người dùng sử dụng ứng dụng của bạn vì ứng dụng này có thể lưu vào bộ nhớ đệm dữ liệu để xem ngoại tuyến bằng nhân viên dịch vụ
- Hiệu suất. So với các ứng dụng di động gốc, PWAs nhẹ hơn nhiều, không chiếm nhiều dung lượng bộ nhớ và có thời gian tải nhanh hơn
Về mặt tiêu cực
- Mức sử dụng pin cao. Vì PWA là mã web cấp cao được tích hợp sẵn nên điện thoại phải làm việc nhiều hơn để đọc mã;
- Truy cập phần cứng di động. PWA không thể truy cập các tính năng phần cứng khác nhau như Bluetooth của thiết bị, cảm biến tiệm cận, v.v.
- Phân phối Vì PWA không được phân phối qua cửa hàng ứng dụng nên bạn có thể bỏ lỡ những người dùng chủ yếu duyệt qua cửa hàng ứng dụng
Bạn nên cân nhắc sử dụng/xây dựng Ứng dụng web lũy tiến nếu bạn đáp ứng các tiêu chí sau
- Bạn không có ngân sách để xây dựng một ứng dụng chính thức
- Bạn cần thúc đẩy đối tượng mục tiêu của mình nhanh hơn
- Có khả năng tương thích đa nền tảng là điều cần thiết cho doanh nghiệp của bạn
Chúng tôi sẽ xây dựng ứng dụng di động “Todo List” bằng HTML, CSS và Javascript. Trước tiên, chúng tôi sẽ xây dựng một ứng dụng web trong khi sử dụng IndexedDB cho cơ sở dữ liệu của chúng tôi, hộp làm việc để làm cho nó hoạt động ngoại tuyến và bảng kê khai web để làm cho nó có thể cài đặt được trên các thiết bị. Kết quả cuối cùng sẽ như sau
Chúng tôi bắt đầu bằng cách tạo một thư mục trống có tên Ứng dụng Todo và sau đó tạo ba tệp bên trong có tên là index.html
,
Copy0,1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Copy1 và thư mục nội dung [sẽ chứa logo của chúng tôi]1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Cấu trúc HTML của chúng tôi
Chuyển đến tệp index.html
và nhập các dòng mã sau
Copy1
2
3
4
5
6
7My Todo
8
9
10
11
12
13
Todo PWA
14
15
16
17
18
19
20
21
Tasks
22
23
24
25
26
27
28
29
30
Tại đây, chúng tôi đã tạo bố cục trang HTML và liên kết cả
Copy0 và1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Copy1 của chúng tôi. Bây giờ, hãy tiếp tục và thêm một số kiểu dáng1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Tạo kiểu cho ứng dụng của chúng tôi bằng CSS
Cập nhật tệp
Copy0 bằng mã bên dưới1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Copy1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Phát lại phiên mã nguồn mở
OpenReplay là bộ phát lại phiên mã nguồn mở cho phép bạn xem những gì người dùng làm trên ứng dụng web của bạn, giúp bạn khắc phục sự cố nhanh hơn. OpenReplay tự lưu trữ để kiểm soát hoàn toàn dữ liệu của bạn
Bắt đầu tận hưởng trải nghiệm sửa lỗi của bạn - bắt đầu sử dụng OpenReplay miễn phí
Thiết lập Dexie. js để làm việc với IndexedDB
Hãy chuyển sang tệp Javascript của chúng tôi. Nhưng trước tiên, hãy định cấu hình cơ sở dữ liệu IndexedDB của chúng tôi, một cơ sở dữ liệu trong trình duyệt sẽ lưu trữ tất cả các todo của chúng tôi
Ghi chú. Đây không phải là bộ nhớ cục bộ mà là cơ sở dữ liệu thực tế nằm trong trình duyệt
Để tương tác với cơ sở dữ liệu này, chúng tôi sẽ cần cài đặt
Copy6, một trình bao bọc xung quanh IndexedDB sẽ giúp chúng tôi quản lý cơ sở dữ liệu của mình một cách dễ dàng. Đi đến dexie. js và tải xuống tệp script. Thêm phần sau vào thẻ đầu của bạn trong1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
index.html
________số 8_______
Sau đó, trong tệp
Copy1, chúng tôi khởi tạo cơ sở dữ liệu mới bằng cách sử dụng1:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Copy61:root {
2 --dark: #05152E;
3 --darker: #1F2937;
4 --darkest: #001E3C;
5 --grey: #6B7280;
6 --pink: #EC4899;
7 --purple: #8B5CF6;
8 --light: #EEE;
9}
10
11* {
12 margin: 0;
13 box-sizing: border-box;
14 font-family: "Fira sans", sans-serif;
15}
16
17body {
18 display: flex;
19 flex-direction: column;
20 min-height: 100vh;
21 color: #FFF;
22 background-color: var[--dark];
23}
24
25header {
26 padding: 2rem 1rem;
27 max-width: 800px;
28 width: 100%;
29 margin: 0 auto;
30}
31
32header h1{
33 font-size: 2.5rem;
34 font-weight: 300;
35 color: white;
36 margin-bottom: 1rem;
37}
38h1{
39 text-align: center;
40}
41#new-task-form {
42 display: flex;
43}
44
45input, button {
46 appearance: none;
47 border: none;
48 outline: none;
49 background: none;
50}
51
52#new-task-input {
53 flex: 1 1 0%;
54 background-color: var[--darker];
55 padding: 1rem;
56 border-radius: 1rem;
57 margin-right: 1rem;
58 color: var[--light];
59 font-size: 1.25rem;
60}
61
62#new-task-input::placeholder {
63 color: var[--grey];
64}
65
66#new-task-submit {
67 color: var[--pink];
68 font-size: 1.25rem;
69 font-weight: 700;
70 background-image: linear-gradient[to right, var[--pink], var[--purple]];
71 -webkit-background-clip: text;
72 -webkit-text-fill-color: transparent;
73 cursor: pointer;
74 transition: 0.4s;
75}
76
77#new-task-submit:hover {
78 opacity: 0.8;
79}
80
81#new-task-submit:active {
82 opacity: 0.6;
83}
84
85main {
86 flex: 1 1 0%;
87 max-width: 800px;
88 width: 100%;
89 margin: 0 auto;
90}
91
92.task-list {
93 padding: 1rem;
94}
95
96.task-list h2 {
97 font-size: 1.5rem;
98 font-weight: 300;
99 color: var[--grey];
100 margin-bottom: 1rem;
101}
102
103#tasks .task {
104 display: flex;
105 justify-content: space-between;
106 background-color: var[--darkest];
107 padding: 1rem;
108 border-radius: 1rem;
109 margin-bottom: 1rem;
110}
111
112.task .content {
113 flex: 1 1 0%;
114}
115
116.task .content .text {
117 color: var[--light];
118 font-size: 1.125rem;
119 width: 100%;
120 display: block;
121 transition: 0.4s;
122}
123
124.task .content .text:not[:read-only] {
125 color: var[--pink];
126}
127
128.task .actions {
129 display: flex;
130 margin: 0 -0.5rem;
131}
132
133.task .actions button {
134 cursor: pointer;
135 margin: 0 0.5rem;
136 font-size: 1.125rem;
137 font-weight: 700;
138 text-transform: uppercase;
139 transition: 0.4s;
140}
141
142.task .actions button:hover {
143 opacity: 0.8;
144}
145
146.task .actions button:active {
147 opacity: 0.6;
148}
149
150.task .actions .edit {
151 background-image: linear-gradient[to right, var[--pink], var[--purple]];
152 -webkit-background-clip: text;
153 -webkit-text-fill-color: transparent;
154}
155
156.task .actions .delete {
157 color: crimson;
158}
Copy1//creating database structure
2
3const db = new Dexie["Todo App"];
4db.version[1].stores[{ todos: "++id, todo" }];
5
6const form = document.querySelector["#new-task-form"];
7const input = document.querySelector["#new-task-input"];
8const list_el = document.querySelector["#tasks"];
9
10//add todo
11form.onsubmit = async [event] => {
12 event.preventDefault[];
13 const todo = input.value;
14 await db.todos.add[{ todo }];
15 await getTodos[];
16 form.reset[];
17};
18
19//display todo
20const getTodos = async [] => {
21 const allTodos = await db.todos.reverse[].toArray[];
22 list_el.innerHTML = allTodos
23 .map[
24 [todo] => `
25
26
27
28
29
30
31 Delete
32
33
34 `
35 ]
36 .join[""];
37};
38window.onload = getTodos;
39
40//delete todo
41const deleteTodo = async [event, id] => {
42 await db.todos.delete[id];
43 await getTodos[];
44};
Trong mẫu mã trên, chúng tôi đã triển khai các chức năng cơ bản mà ứng dụng của chúng tôi nên có. Chúng tôi có thể thêm, hiển thị và xóa todos khỏi cơ sở dữ liệu của mình. Bây giờ chúng ta đã thiết lập ứng dụng cơ bản, đã đến lúc tập trung vào những gì sẽ làm cho ứng dụng của chúng ta hoạt động giống như một ứng dụng di động thông thường. Trước tiên, chúng tôi sẽ làm cho ứng dụng của mình có chức năng ngoại tuyến, chức năng này sẽ cho phép ứng dụng hoạt động mà không cần kết nối internet
Thiết lập Hộp làm việc
Google workbox là công cụ sẽ tạo ra service worker, giúp ứng dụng của chúng ta hoạt động mà không cần kết nối internet. Trước tiên, hãy cài đặt hộp làm việc trên toàn cầu trên máy của chúng tôi. Chạy
Copy1npm install Workboxcli --global
Sau đó, để định cấu hình hộp làm việc của chúng tôi, hãy chạy
Copy1workbox wizard
Trong bảng điều khiển, bạn sẽ được yêu cầu đăng ký đường dẫn gốc của ứng dụng của mình. Chọn Nhập đường dẫn thủ công, sau đó sử dụng. / làm đường dẫn gốc
Sau đó, chọn bộ đệm tất cả các tệp. Ngoài ra, đồng ý lưu cho nhân viên dịch vụ và cấu hình, và cuối cùng chọn không cho tùy chọn cuối cùng
Sau đó, chúng ta sẽ thấy rằng một tệp có tên
Copy0 đã được tạo. Ngay sau đó, hãy chạy lệnh này để tạo nhân viên dịch vụ1
Copy1workbox generateSW workbox-config.js
Bây giờ hãy thêm đoạn mã dưới đây vào thẻ đầu của tệp HTML. Nó sẽ đăng ký nhân viên dịch vụ khi cửa sổ được tải
Copy1
2// Check that service workers are supported
3if ["serviceWorker" in navigator] {
4 // Use the window load event to keep the page load performant
5
6 window.addEventListener["load", [] => {
7 navigator.serviceWorker.register["./sw.js"];
8 }];
9}
10
Truy cập trình duyệt của bạn, nhấp chuột phải và nhấp vào kiểm tra, sau đó điều hướng đến các ứng dụng và tìm nhân viên dịch vụ. Bạn sẽ thấy rằng nhân viên dịch vụ đã chạy
Trước khi chúng tôi tiếp tục, hãy đẩy mã của bạn vào repo GitHub của bạn và lưu trữ nó. Đối với bài viết này, tôi đang lưu trữ với các trang GitHub
Làm cho ứng dụng có thể cài đặt được
Chúng tôi phải thêm một bảng kê khai web vào ứng dụng của mình để đạt được điều này. Đây là tệp JSON sẽ lưu trữ các chi tiết cần thiết về ứng dụng của chúng tôi, chẳng hạn như logo, tên ứng dụng, mô tả, v.v. Chuyển đến thư mục gốc của thư mục ứng dụng và tạo
Copy1. Sau đó thêm mã này dưới đây1
Copy1{
2 name: "Todo PWA",
3 short_name: "Todo",
4 icons: [
5 {
6 src: "./assets/icon-100.png",
7 sizes: "100x100",
8 type: "image/png",
9 },
10 {
11 src: "./assets/icon-150.png",
12 sizes: "150x150",
13 type: "image/png",
14 },
15 {
16 src: "./assets/icon-250.png",
17 sizes: "250x250",
18 type: "image/png",
19 },
20 {
21 src: "./assets/icon-500.png",
22 sizes: "500x500",
23 type: "image/png",
24 },
25 ],
26 theme_color: "#FFFFFF",
27 background_color: "#FFFFFF",
28 start_url: "/PWA-TodoApp/",
29 display: "standalone",
30 orientation: "portrait",
31 };
Sau đó, thêm liên kết đến tệp kê khai vào phần đầu của tệp index.html
của chúng tôi. Bây giờ hãy đẩy những thay đổi này vào repo của bạn
Thử nghiệm ứng dụng trên thiết bị di động
Cuối cùng, chúng tôi đã hoàn thành ứng dụng Di động của mình chỉ bằng cách sử dụng HTML, CSS và Javascript. Hãy tiếp tục và truy cập URL được lưu trữ của bạn và cài đặt ứng dụng của bạn trên thiết bị di động của bạn
Phần kết luận
chúc mừng. về làm cho nó ở đây. Bạn đã học cách thiết lập ứng dụng dành cho thiết bị di động bằng kiến thức về công nghệ web cơ bản và tổng quan về PWAs. Bạn có thể tiến xa hơn và mở rộng kiến thức của mình bằng cách sử dụng các khung khác để giúp bạn thêm nhiều khả năng hơn vào ứng dụng của mình