Tìm kiếm bài viết

Lập trình App đơn giản với Vuejs

09.11.2020

5.0/5 (1 Reviews)

Todo App đơn giản với Vuejs, tìm hiểu về VueJS đơn giản đến nâng cao qua từng ví dụ bạn nhé.

    Cài đặt môi trường cho Vuejs

    Như mọi framework khác, để xài được nó thì bạn phải cài đặt nó đã npm install -g @vue/cli,

    Tạo vue project bằng dòng lệnh sau vue create todo-app, sau đó bạn sẽ tới bước chọn preset, bạn có thể dùng dấu mũi tên lên xuống để lựa chọn, với mình thì mình sẽ chọn là default. Sau đó bạn cứ nhấn enter và mở project và bắt đầu code thôi

    Cấu trúc project và phân tích components

    Trong folder src, chúng ta sẽ tạo 1 folder components để chứa những component sẽ được tạo ra.

    Trong file main.js, chúng ta sẽ viết như sau:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import App from './App.vue'
    import routes from './routes';
    import stores from './stores';
    
    Vue.config.productionTip = false
    Vue.use(VueRouter);
    
    const router = new VueRouter({
      routes
    })
    
    new Vue({
      router,
      stores,
      render: h => h(App),
    }).$mount('#app')
    

    Tới bước này thì bạn nhớ cài đặt thêm vue-routervuex cho nó nhé. Bạn có thể thấy là chúng ta đã import file routes và stores vào trong main.js để sử dụng. Nội dung trong file cũng rất đơn giản thôi, bạn sẽ define cho nó 3 route chính mà t sẽ sử dụng ở trong app: listNew, listInprogress và listDone, bạn có thể tham khảo nội dung file routes ở bên dưới:

    import ListNew from './components/ListNew.vue'
    import ListInprogress from './components/ListInprogress.vue'
    import ListDone from './components/ListDone.vue'
    
    export default  const routes = [
      {
        path: '/listNew',
        name: 'ListNew',
        component: ListNew
      },
      {
        path: '/listInprogress',
        name: 'ListInprogress',
        component: ListInprogress
      },
      {
        path: '/listDone',
        name: 'ListDone',
        component: ListDone
      },
    ];
    

    Trong file stores.js, chúng ta sẽ định nghĩa state, mutations, getters , actions cho app, bạn có thể tham khảo nội dung dưới đây,

    import Vue from 'vue'
    import Vuex from 'vuex'
    import io from 'socket.io-client';
    const socket = io('localhost:6969');
    Vue.use(Vuex);
    
    export default const store = new Vuex.Store({
      state: function () {
      const todolist = {
          listNew: [
              {
                  id: 0,
                  value: "Đi ngủ",
              },
          ],
          listInprogress: [
              {
                  id: 0,
                  value: "Làm việc",
              },
          ],
          listDone: [
              {
                  id: 0,
                  value: "Đi tè",
              },
          ]
      }
        return todolist;
      },
      mutations: {
          // function để add thêm task vào cho listNew
        addNew: (state, {value}) => state.listNew.push(value), //
        
        // Xóa task được chọn
        deleteTask: (state, {listType, index}) => state[listType].splice(index, 1
        
        // chuyển task qua giai đoạn tiếp theo
        transferTask: (state, {currentList, nextList, index }) => {
          const taskTransfered =  state[currentList].splice(index, 1);
          state[nextList].push(taskTransfered[0]);
        },
        
        // lưu lại những chỉnh sửa của task
        saveEdit: (state, {listType, value, index}) => state[listType][index] = value,
      }
    })
    actions: {}
    getters: {}
    

    Trong file App.vue, chúng ta sẽ tạo giao diện cơ bản cho app todolist,

    <template>
      <div id="app">
        <AddTodo />
        <div class='containerTab'>
          <router-link to="/listNew">List New</router-link>
          <router-link to="/listInprogress">List Inprogress</router-link>
          <router-link to="/listDone">List Done</router-link>
        </div>
        <div class='containerContent'>
          <router-view></router-view>
        </div>
      </div>
    </template>
    
    <script>
    import AddTodo from './components/AddTodo.vue'
    export default {
      name: 'app',
      components: {
        AddTodo,
      }
    }
    </script>
    
    <>

    Trong folder components, chúng ta sẽ tạo ra 4 file là AddTodo.vue, ListNew.vue, ListInprogress.vue và ListDone.vue

    Trong file AddTodo thực chất là 1 input để chúng ta nhập task mới để add vào ListNew, bạn có thể tham khảo code dưới đây

    <template>
      <div class="container">
        <input
          id='inputNew'
          placeholder="Công việc muốn thêm"
          v-model="inputNew"
          @keydown.enter='addNew(inputNew)'
        />
        <button
          v-on:click='addNew(inputNew)'
        >Thêm vào</button>
      </div>
    </template>
    
    <script>
    export default {
      name: 'AddTodo',
      methods: {
        addNew (value) {
          this.$stores.commit('addNew', {value})
          this.inputNew = ''
        },
      },
      data: function() {
        return {
          inputNew: '',
        }
      }
    }
    </script>
    
    <>

    Trong ListNew.vue, ListInprogress.vue và ListDone.vue lần lượt chính là 3 bảng thể hiện list task, về cơ bản UI của cả 3 folder đều giống hết nhau, vì vậy chúng ta có thể để phần >

    <template>
      <div>
        <div v-for='(item, index) in listNew' :key="item" class='listItem'>
          <p v-show='indexItemEdited !== index'>{{item}}</p>
          <input
            class="inputEdit"
            type="text"
            v-show='indexItemEdited === index' 
            :placeholder='item'
            v-model='item.index'
            @blur='saveEdit("listNew", $item[index], index)'
          />
          <div class='buttonSection'>
            <button 
              v-show='indexItemEdited !== index'
              @click='toggleEdit(index)'
            >
              Sửa
            </button>
            <button
              v-show='indexItemEdited === index'
              @click='toggleEdit(index), saveEdit("listNew", item, index)'
            >
              Lưu
            </button>
            <button
              @click='transferTask("listNew", "listInprogress", index)'
            >Làm</button>
            <button v-on:click='deleteTask("listNew", index)' >Xóa</button>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'ListNew',
      data: function() {
        return {
          indexItemEdited: -1,
          item: '',
        };
      },
      computed: {
        listNew() {
          return this.$stores.state.listNew;
        }
      },
      methods: {
        toggleEdit: function (index) {
          if(this.indexItemEdited === index) {
            return this.indexItemEdited = -1;
          }
          return this.indexItemEdited = index;
        },
        deleteTask: function (listType, index) {
          this.$stores.commit('deleteTask', {listType, index})
        },
        saveEdit: function (listType, value, index) {
          this.$stores.commit('saveEdit', {listType, value, index})
        },
        transferTask: function (currentList, nextList, index) {
          this.$stores.commit('transferTask', {currentList, nextList, index})
        }
      }
    }
    </script>
    

    riêng về css, bạn có thể thêm nó vào chung với css ở file App.js

    .listItem {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 10px;
      padding-left: 16px;
      margin-bottom: 2px;
      font-size: 16px;
      background: #4267b2;
      color: #fff;
    }
    .listItem:last-child {
      border-radius: 0 0 10px 10px;
      margin-bottom: 0;
    }
    .inputEdit {
      padding: 2.5px 10px;
      font-size: 16px;
      color: #4267b2;
      background: #ffffff;
    }
    .buttonSection {
      background: transparent;
    }
    .buttonSection > button {
      color: #4267b2;
      font-weight: bold;
      margin-right: 10px;
      background: #ffffff;
      border: none;
      padding: 5px 10px;
    }
    

    file ListInprogress:

    <template>
      <div>
        <div v-for='(item, index) in listInprogress' :key="item" class='listItem'>
          <p>{{item}}</p>
          <div class='buttonSection'>
            <button
              @click='transferTask("listInprogress", "listDone", index)'
            >Hoàn thành</button>
            <button v-on:click='deleteTask("listInprogress", index)' >Xóa</button>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'ListInprogress',
      computed: {
        listInprogress() {
          return this.$stores.state.listInprogress;
        }
      },
      methods: {
        deleteTask (listType, index) {
          this.$stores.commit('deleteTask', {listType, index})
        },
        transferTask (currentList, nextList, index) {
          this.$stores.commit('transferTask', {currentList, nextList, index})
        }
      }
    }
    </script>
    

    Riêng về file ListDone thì khá giống với ListInprogress, nên mình sẽ không để tham khảo ở đây, các bạn có thể xem nó như 1 bài tập nhỏ cho bản thân.

    Giờ bạn có thể yên tâm và chạy thử app của mình với lệnh là npm run server.

    Kết luận sơ sơ

    Trên đây là app todo cực kỳ đơn giản của mình để có thể ôn lại kiến thức đã học và giúp đỡ một số bạn gặp khó khăn trong việc tiếp cận với Vuejs. Với app trên bạn có thể cải thiện thêm bằng cách sử dụng và tìm hiểu thêm về các khái niệm như actions, getters , mapActions,... Sau đó có thể tạo 1 server json nho nhỏ để làm việc với api, bạn có thể sử dụng axios để xử lý với dữ liệu ở server.

    Nếu các bạn có hứng thú với bài viết của mình, xin hãy upvote và comment ý kiến của bạn về app hoặc bài viết. Nếu bài viết này có upvote trên 10 hoặc trong thời gian tới mình rảnh rỗi, sẽ phát triển tiếp app todo này với realtime bằng cách sử dụng , refactor code để app todo này càng hoàn thiện hơn.

    CÓ THỂ BẠN QUAN TÂM

    Bài Viết Cùng Chuyên Mục

    XEM THÊM
    thumbnail

    LPStack Server: Giải pháp thay thế XAMPP và MAMP năm 2026

    10.03.2026

    Bạn đã chán ngấy XAMPP hay MAMP chậm chạp? Khám phá LPStack Server – Môi trường Local Development siêu nhẹ của người Việt với Auto Vhost, Public Tunnel, chuyển đổi PHP 1-click và quản lý Database Native chuyên nghiệp

    thumbnail

    Hướng Dẫn Tạo Trò Chơi Cờ Caro Nâng Cao bằng HTML

    19.03.2025

    Chào các bạn! Trong bài viết này, chúng ta sẽ cùng nhau xây dựng một trò chơi Cờ Caro đơn giản nhưng có nhiều tính năng thú vị như giới hạn nước đi, pháo hoa khi chiến thắng, chọn chế độ chơi và đếm thời gian.

    thumbnail

    Grok AI: Giới thiệu chi tiết về chatbot của Elon Musk

    04.03.2025

    Grok là một chatbot AI tiên tiến, được phát triển bởi xAI, công ty do Elon Musk sáng lập. Ra mắt lần đầu vào tháng 11/2023, Grok được thiết kế để cạnh tranh với các mô hình AI nổi tiếng như ChatGPT

    thumbnail

    Hướng dẫn tạo Livechat trả lời bằng AI Grok của X

    04.03.2025

    Hướng dẫn kỹ thuật tạo Livechat AI bằng HTML, CSS, JavaScript và PHP Dưới đây là hướng dẫn từng bước để xây dựng một ứng dụng livechat AI đơn giản. Chúng ta sẽ có giao diện frontend (HTML, CSS, JS) và backend (PHP) xử lý tin nhắn.

    thumbnail

    Temu Affiliate là gì? Cách kiếm tiền với Temu mới nhất 2024

    23.10.2024

    Temu Affiliate là một chương trình tiếp thị liên kết mới mẻ được đưa ra bởi sàn thương mại điện tử Temu. Tham gia ⭐️ Chương trình tiếp thị liên kết Temu⭐️! Lên đến ????₫2.500.000.000 mỗi tháng

    Mục lục bài viết