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