Vue React
Data State
VueX Redux
Vue RouterRouter
Component Components
Props Props
npm npm
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
+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:
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')
<router-link :to="'/create-event/' + this.dateSelect + '/abcUser'"> <ButtonCreate /> </router-link>
this.$router.push({ path: '/' });
//or
this.$router.push({ name: 'Calendar' });
//or
this.$router.push({ name: 'EditEvent', params: { id: id }});
date: this.$route.params.date, userName: this.$route.params.user
const routes = [
{
path: '*',
name: '404',
component: {
template: '<div>Not Found</div>'
}
}
];
$router.go(-1)
npm install vuex
Tạo:
//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
}
});
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')
Tạo:
Ở đâ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
};
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
};
import { mapGetters, mapActions } from "vuex";
export default {
name: 'ListTodo',
components: { Todo },
computed: mapGetters(["allTodos"]),
methods: {
...mapActions(["fetchTodos"]),
dbClickItemTodo(id) {
}
},
created() {
this.fetchTodos();
}
}
Cần setup:
npm install -global @vue/cli //hoặc gọn hơn npm i -g @vue/cli //kiểm tra vue --version
vue create tenProject chọn => Default([vue2],.....)
npm run serve
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.
//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>
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
this.$forceUpdate();
<template>
{{ test() }}
</template>
<script>
method: {
test () {
console.log('abc');
}
}
</script>
//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
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>
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');
Đừ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: '',
}
}
}

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],
},
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