Kinh nghiệm VueJS
Contents
- 1. Điểm tương đồng giữa React và VueJS
- 2. Những kiến thức chung
- 3. Kinh nghiệm
- 3.1 Cài vue cli
- 3.2 Cài project Vue
- 3.3 Lệnh run server
- 3.4 Build deploy server
- 3.5 Props
- 3.6 Sử dụng sass/scss trong vue
- 3.6 Yêu cầu vue re render DOM
- 3.7 Console trong template
- 3.8 Sử dụng mixin để tối ưu code
- 3.9 Thư viện hỗ trợ vuejs
- 3.10 Các khái niệm học thêm được
- 3.11 Sử dụng vuejs vào file html
- 3.12 Watch trong vuejs phải có trong data
- 3.13 Radar chart vuejs – chartjs
- 3.14 Sử dụng biến trong file .env
1. Điểm tương đồng giữa React và VueJS
Vue | React |
Data | State |
VueX | Redux |
Vue Router | Router |
Component | Components |
Props | Props |
npm | npm |
2. Những kiến thức chung
Cấu trúc thư mục:
+src:
+main.js
+App.vue => component gốc
+assets: hình ảnh, font
+components
+component
+Template : nội dung phải nằm chung 1 thẻ bao đóng
+Script
+Style: hỗ trợ cả css và scss
-
-
- scoped style: style dành riêng cho component
-
+Tạo component:
+Tạo file .vue
+Import vào component cha
+Khai báo vào component cha
+ 2 ways binding:
+Life cycle:
+Binding:
+Value Binding: {{ tenBien }}
+Property Binding:
v-bind:id="tenBien" //viết tắt :id="tenBien"
+style and class binding:
:class="tenBien" /* Tên biến: + Kiểu dữ liệu: bool + Nếu true thì gắn tên class vào component + else thì không */
+Model: Liên kết 1 element với 1 property
V-model
+Even Handling:
v-on:click="tenHam()" //viết tắt: @click="TenHam()"
+prevent default event: Hủy event mặc định
@click.prevent
+ ref: Ánh xạ chỉnh element
this.$refs.tenRef
+ condition rendering
v-show v-hide v-if v-else-if v-else
+list rendering
v-for="(tenBienTam, index) in mang" :key="index"
+methods: hàm của vue object
methods: { addTasks: function() { //biến sử dụng this.tenBien } }
+watch: theo dõi sự thay đổi của Data
watch: { tenBien: function() { //code }, tenBien: function(newValue, oldValue) { //code } }
+hooks: Như trong life cycle
mounted() { } ....
+props: truyền dữ liệu component cha và component con
props: [ 'tenProps' ] //component cha :tenProps="tenBien"
+filter:
ví dụ: 100000 => 100,000
Property vẫn là 100000 để có thể tính toán tiếp còn html render sẽ là 100,000
filters: { abc: function() { //code } } //chỗ fileter {{ tenBien | abc }}
Video mình học:
2.1 Vue Router
2.1.1 Cài đặt
2.1.2 import
import VueRouter from 'vue-router' Vue.use(VueRouter); const routes = [ { name: 'Login', path: '/login', component: Login }, { name: 'CreateEvent', path: '/create-event', component: CreateEvent, //beforeEach: checkRoute }, { name: 'Calendar', path: '/', component: Calendar, //beforeEach: checkRoute }, { name: 'CreateTask', path: '/create-task', component: CreateTask, //beforeEach: checkRoute }, { name: 'EditEvent', path: '/edit-event/:id', component: EditEvent, //beforeEach: checkRoute }, ] const router = new VueRouter({ routes, // short for `routes: routes` mode: 'history' }) router.beforeEach( (to, from, next) => { /** * if route là /login => allow */ if (to.fullPath == "/login"){ return next(); } /** * if localStorage.getItem("username") has data * => allow access * else equals "" || undefine || not exists => (not data) * => not allow * => redirect login page */ if ( localStorage.getItem("username") ) { return next(); } else { console.log("else next"); return next({ path: '/login'}); } }); new Vue({ router, store, render: h => h(App) }).$mount('#app')
2.1.3 Link to ở component
<router-link :to="'/create-event/' + this.dateSelect + '/abcUser'"> <ButtonCreate /> </router-link>
2.1.4 Redirect
this.$router.push({ path: '/' }); //or this.$router.push({ name: 'Calendar' }); //or this.$router.push({ name: 'EditEvent', params: { id: id }});
2.1.5 get param
date: this.$route.params.date, userName: this.$route.params.user
2.1.6 Sử dụng html thay vì component
const routes = [ { path: '*', name: '404', component: { template: '<div>Not Found</div>' } } ];
2.1.7 Go back route
$router.go(-1)
2.2 VueX
2.2.1 Cài đặt
npm install vuex
2.2.2 Tạo store
Tạo:
- folder src/store
- file store/index.js
//file index.js import Vuex from 'vuex'; import Vue from 'vue'; import todos from './modules/todos'; // Load Vuex Vue.use(Vuex); // Create store export default new Vuex.Store({ modules: { todos } });
2.2.3 Gắn Store vào main.js
import Vue from 'vue' import App from './App.vue' import store from './store'; Vue.config.productionTip = false new Vue({ store, render: h => h(App), }).$mount('#app')
2.2.4 Tạo modules
Tạo:
- folder store/mudules
- file modules/tenFile.js
Ở đây mình lấy ví dụ todo.js
//file todo.js import axios from 'axios'; const state = { }; const getters = { }; const actions = { }; const mutations = { }; export default { state, getters, actions, mutations };
- state: nơi chứa state, data
- getters: cho các component lấy dữ liệu
- actions: cho các component set dữ liệu
- mutations: nơi set lại state, data từ action
FILE MODULES MẪU
import axios from 'axios'; const state = { todos: [] }; const getters = { allTodos: state => state.todos }; const actions = { async fetchTodos({ commit }) { const response = await axios.get( 'https://jsonplaceholder.typicode.com/todos' ); commit('setTodos', response.data); }, async addTodo({ commit }, title) { const response = await axios.post( 'https://jsonplaceholder.typicode.com/todos', { title, completed: false } ); commit('newTodo', response.data); }, async deleteTodo({ commit }, id) { await axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`); commit('removeTodo', id); }, async filterTodos({ commit }, e) { // Get selected number const limit = parseInt( e.target.options[e.target.options.selectedIndex].innerText ); const response = await axios.get( `https://jsonplaceholder.typicode.com/todos?_limit=${limit}` ); commit('setTodos', response.data); }, async updateTodo({ commit }, updTodo) { const response = await axios.put( `https://jsonplaceholder.typicode.com/todos/${updTodo.id}`, updTodo ); console.log(response.data); commit('updateTodo', response.data); } }; const mutations = { setTodos: (state, todos) => (state.todos = todos), newTodo: (state, todo) => state.todos.unshift(todo), removeTodo: (state, id) => (state.todos = state.todos.filter(todo => todo.id !== id)), updateTodo: (state, updTodo) => { const index = state.todos.findIndex(todo => todo.id === updTodo.id); if (index !== -1) { state.todos.splice(index, 1, updTodo); } } }; export default { state, getters, actions, mutations };
2.2.5 Sử dụng ở Component
import { mapGetters, mapActions } from "vuex"; export default { name: 'ListTodo', components: { Todo }, computed: mapGetters(["allTodos"]), methods: { ...mapActions(["fetchTodos"]), dbClickItemTodo(id) { } }, created() { this.fetchTodos(); } }
- import vào
- getter ở dòng 6: chứa các hàm định nghĩa ở modules
- action ở dòng 8, chứa các hàm định nghĩa ở modules
2.3 Form validate
3. Kinh nghiệm
Cần setup:
- Cài Nodejs
- Vue CLI
- Vue Project
3.1 Cài vue cli
npm install -global @vue/cli //hoặc gọn hơn npm i -g @vue/cli //kiểm tra vue --version
3.2 Cài project Vue
vue create tenProject chọn => Default([vue2],.....)
3.3 Lệnh run server
npm run serve
3.4 Build deploy server
npm run build
Khi chạy xong nó sẽ build ra thư mục dist. Từ thư mục này có thể up lên hosting.
3.5 Props
3.5.1 Truyền method
//Component cha <template> <AddTodo :submitForm="addTodo"/> </template> <script> import AddTodo from './components/todo/AddTodo'; export default { ... methods: { addTodo(todo) { this.TodoData = [...this.TodoData, {content: todo}]; } } } </script>
<template> ... </template> <script> export default { ... props: { submitForm: { type: Function } }, methods: { submit() { this.submitForm(this.inputText); this.inputText = ""; } } } </script>
3.6 Sử dụng sass/scss trong vue
Ban đầu chạy comment line tại thư mục gốc
npm install -D sass-loader node-sass
Sau đó trong thư mục gốc tạo file webpack.config.js và paste nội dung bên dưới vào.
{ test: /\.sass$/, use: [ 'vue-style-loader', 'css-loader', { loader: 'sass-loader', options: { indentedSyntax: true, // sass-loader version >= 8 sassOptions: { indentedSyntax: true } } } ] }
npm run server => để run lại server
3.6 Yêu cầu vue re render DOM
this.$forceUpdate();
3.7 Console trong template
<template> {{ test() }} </template> <script> method: { test () { console.log('abc'); } } </script>
3.8 Sử dụng mixin để tối ưu code
//mixin.js export default { data () { title: 'Mixin' } }
import mixin from './mixin.js' export default { mixins: [mixin], data () { title: 'Component' }, created: function () { console.log(this.title) } } // => "Component"
Xem thêm bài viết: https://viblo.asia/p/cach-su-dung-mixin-trong-vuejs-Qpmle7QrKrd
3.9 Thư viện hỗ trợ vuejs
- Validate: V-mask https://www.npmjs.com/package/v-mask
3.9.1 Thanh scroll dạng mảnh
Demo: https://lab.morioh.com/v-smooth-scrollbar/
npm i @morioh/v-smooth-scrollbar
import Vue from 'vue' import ScrollBar from '@morioh/v-smooth-scrollbar' // global register Vue.use(ScrollBar);
<div v-scrollbar style="max-height: 500px; max-height:500px"></div>
3.10 Các khái niệm học thêm được
- Two-way binding: template thay đổi thì data thay đổi và ngược lại.
- refs: lấy dom để làm một việc gì đó giống document.getElementById…
- Emit custom event: tạo sự kiện component con lên component cha để thay đổi data của component cha.
https://viblo.asia/p/giao-tiep-giua-cac-component-trong-vuejs-gDVK29yw5Lj - provide/inject: làm cho việc truyền dữ liệu giữa component ông, cố, cụ kị xuống component con dễ hơn. không phỉa bị sót khi truyền thông qua props.
- diving deeper:
+ scope style: style chỉ áp dụng cho component.
+ slots: tạo khoảng trống component con để component cha có thể thêm content vào đó.
+ Compilation slots: sử dụng slots có biến - Computed khác method: computed chỉ sử dụng data của component, không thể truyền tham số, lưu caching nên xử lý nhanh hơn.
- Plugin: Tạo ra mục đích giống như wordpress, import vào là xài bất cứ đâu, không xài nữa chỉ cần gỡ ra.
https://viblo.asia/p/gioi-thieu-don-gian-ve-plugin-trong-vue-1VgZvVR2ZAw
3.11 Sử dụng vuejs vào file html
let param = { DOM_QueryToVueBinding: '#app' } let data = ` <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js" integrity="sha512-bZS47S7sPOxkjU/4Bt0zrhEtWx0y0CRkhEp8IckzK+ltifIIE9EMIMTuT/mEzoIMewUINruDBIR/jJnbguonqQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> $(document).ready(function () { new Vue({ el: 'DOM_QUERY', data() { return { } }, mounted() { }, methods: { }, watchs: { }, }) }); </script> `; data = data.replaceAll('DOM_QUERY', param.DOM_QueryToVueBinding); console.log(data); console.log('Thêm class or id ở trên (el: ...) vào template');
3.12 Watch trong vuejs phải có trong data
Đừng để mất thời gian vì điều này, hãy nhớ có trong data mới watch được. Mình từng bị điều này mất cả ngày trời để mò mẫm.
// Muốn watch được thuộc tính c trong form ... watch: { "form.c": function() { // code } } ... // Muốn chạy được thì trong data ... data() { return { form: { a: 1, b: '', c: '' } } } ... // Thay vì như thế nào => sẽ không bao giờ watch được ... data() { return { form: { a: 1, b: '', } } }
3.13 Radar chart vuejs – chartjs
https://www.chartjs.org/docs/2.9.4/
https://github.com/tronghao/module-frontend
Vue => Chart => Radar
<RadarChart :labels="chart.labels" :data="chart.data" /> chart: { labels: ['メンテンス性', 'PCスペック', 'ロマン', 'ケーブル整理', '作業領域', '収納力'], data: [4, 3, 5, 2, 4, 5], },
3.14 Sử dụng biến trong file .env
Muốn sử dụng được thì biến phải có tiền tố MIX_ nếu build bằng webpack laravel.
// in .env MIX_BASIC_AUTH_USERNAME MIX_BASIC_AUTH_PASSWORD // in vue process.env.MIX_BASIC_AUTH_USERNAME process.env.MIX_BASIC_AUTH_PASSWORD