Thumbnail
Category: Lập trình

Kinh nghiệm VueJS

Date: November 27, 2020
124 views

1. Điểm tương đồng giữa React và VueJS

Vue React

Data State

VueX Redux

Vue RouterRouter

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')
​


<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

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

  1. Two-way binding: template thay đổi thì data thay đổi và ngược lại.
  2. refs: lấy dom để làm một việc gì đó giống document.getElementById…
  3. Emit custom event: tạo sự kiện component con lên component cha để thay đổi data của component cha.
  4. https://viblo.asia/p/giao-tiep-giua-cac-component-trong-vuejs-gDVK29yw5Lj
  5. 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.
  6. diving deeper:
  7. scope style: style chỉ áp dụng cho component.
  8. slots: tạo khoảng trống component con để component cha có thể thêm content vào đó.
  9. + Compilation slots: sử dụng slots có biến
  10. 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.
  11. 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.
  12. 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


Copyright © 2025 All Right Reserved