目标

对Vuex、mockjs、Element_UI进行强化练习
拿下Vuex

写在前面

写在前面:本 demo 为Vue脚手架搭建的简洁版的ToDoList;主要用到技术栈:Vuex、mockjs、axios、Element_UI。所有数据均有 mockjs动态模拟;axios来发送请求;Vuex 来管理;页面以Element_UI来搭建。项目源码地址:https://github.com/cwen-jdoit/vuex_todolist

看一下效果吧

在这里插入图片描述

1. 步骤实现

1.1 初始化项目

用vue 脚手架,搭建项目,切记一定要安装 vuex

1.2 使用mock模拟数据
  1. 首先安装mock,用命令行 npm i mockjs --save-dev 或者可视化面板安装mockjs依赖
  2. 在项目根目录下新建mock文件夹,并新建mock.js文件(写入要使用的mock数据)
  3. main.js中导入mock.js

示例:

mock.js

//# 引入mock
const Mock = require('mockjs');
//# 获取list数据的接口
Mock.mock('/todolist', 'get', function(options) {
    let a = [];
    for (let i = 0; i < 5; i++) {
        let o = Mock.mock({
            _id: "@id()",
            title: '@string("lower",5)',
            completed: "@boolean"
        })
        a.push(o)
    }
    return a
});
//# 添加数据的接口
Mock.mock('/addtodo', 'post', function(options) {
    let o = JSON.parse(options.body);
    return Mock.mock({
        _id: "@id()",
        title: o.title,
        completed: false
    })
});

main.js导入mock.js

import '../mock/mock.js'

了解更多mock使用技巧:https://blog.csdn.net/cwq521o/article/details/106736474

1.3 编辑store数据

代码注释超详尽,此处略去概述

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        list: [],
        inputValue: '',
        viewKey: 'all'
    },
    mutations: {
        //# 切记只有mutations里面的函数才有权限修改state的数据
        // 初始化数据
        initList(state, list) {
            state.list = list
        },
        // 给inputValue赋值
        setInputValue(state, val) {
            state.inputValue = val
        },
        // 增加任务,并清空输入框
        addmyTodo(state, task) {
            state.list.push(task)
            state.inputValue = ''
        },
        // 删除任务
        deletemyTodo(state, id) {
            const index = state.list.findIndex(item => item._id === id)
            if (index !== -1) {
                state.list.splice(index, 1)
            }
        },
        // 修改完成状态
        modefyTodo(state, params) {
            const index = state.list.findIndex(item => item._id === params.id)
            if (index !== -1) {
                state.list[index].completed = params.completed
            }
        },
        // 清空已完成任务
        removeDone(state) {
            state.list = state.list.filter(item => item.completed === false)
        },
        // 按钮切换为viewKey赋值,切换高亮
        changeLight(state, key) {
            state.viewKey = key
        }
    },
    actions: {
        //# 获取todo列表
        async getList(context) {
            const { data: res } = await axios.get('/todolist');
            //# 只有mutations内的函数才可操作数据,所以此处调用函数赋值
            context.commit('initList', res);
        },
        //# 发送添加任务请求
        async addTodo(context) {
            const { data: res } = await axios.post('/addtodo', {
                title: context.state.inputValue
            });
            context.commit('addmyTodo', res)
        }
    },
    getters: {
        //# 返回未完成任务数
        doneTodo(state) {
            return state.list.filter(item => item.completed === false).length
        },
        //# 返回全部任务(对任务进行过滤返回)
        infolist(state) {
            if (state.viewKey === 'all') {
                return state.list
            } else if (state.viewKey === 'done') {
                return state.list.filter(item => item.completed === true)
            } else if (state.viewKey === 'nodone') {
                return state.list.filter(item => item.completed === false)
            }
        }
    }
})
1.4 重构App.vue

此处主要用到Element_UI 组件,实现页面的快速搭建。逻辑部分注释清晰

<template>
  <div id="app">
    <!-- 标题部分 -->
    <h1>ToDoList</h1>
    <!-- 输入框部分 -->
    <el-row class="add_text">
      <el-col :span="9" :offset="7">
        <div class="myinput">
          <input
            type="text"
            placeholder="请输入todo"
            :value="inputValue"
            @change="changeInput"
            @keyup.enter="todoAdd"
          />
        </div>
      </el-col>
      <el-col :span="1">
        <i class="el-icon-plus mycursor" style="color:green;font-size:19px" @click="todoAdd"></i>
      </el-col>
    </el-row>
    <!-- 展示任务部分 -->
    <div class="add_todo">
      <el-row v-for="(item,index) in infolist" :key="index">
        <el-col :span="1" :offset="7">
          <el-switch
            v-model="item.completed"
            active-color="#13ce66"
            inactive-color="#ff4949"
            @change="switchChange(item._id,item.completed)"
          ></el-switch>
        </el-col>
        <el-col :span="8">
          <label :class="item.completed ? 'already' : ''">{{item.title}}</label>
        </el-col>
        <el-col :span="1">
          <i
            class="el-icon-delete mycursor"
            style="color:red;font-size:19px"
            @click="deleteById(item._id)"
          ></i>
        </el-col>
      </el-row>
    </div>
    <!-- footer部分 -->
    <div class="todo_order">
      <el-row>
        <el-col :span="2" :offset="7" class="mystyle">
          <label>
            <strong>{{doneTodo}}</strong> nodone
          </label>
        </el-col>
        <el-col :span="4" :offset="1">
          <el-button
            size="mini"
            :type="viewKey === 'all' ? 'warning' : ''"
            icon="el-icon-coin"
            @click="changeList('all')"
          ></el-button>
          <el-button
            size="mini"
            :type="viewKey === 'done' ? 'success' : ''"
            icon="el-icon-check"
            @click="changeList('done')"
          ></el-button>
          <el-button
            size="mini"
            :type="viewKey === 'nodone' ? 'danger' : ''"
            icon="el-icon-close"
            @click="changeList('nodone')"
          ></el-button>
        </el-col>
        <el-col :span="1">
          <el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteDoneTodo">删除已完成</el-button>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script>
//# 导入list数据
import { mapState } from 'vuex';
//# 导入发送请求的方法
import { mapActions } from 'vuex';
//# 导入getters
import { mapGetters } from 'vuex';
//# 向外暴露
export default {
  name: 'app',
  data() {
    return {};
  },
  created() {
    //# 获取任务列表
    this.getList();
  },
  methods: {
    //# 拿到vuex中发送请求的函数
    ...mapActions(['getList', 'addTodo']),
    //# 监听输入框改变事件
    changeInput(e) {
      this.$store.commit('setInputValue', e.target.value);
    },
    //# 监听添加按钮,完成添加任务
    todoAdd() {
      if (this.inputValue.trim().length <= 0) {
        return this.$message.error('请输入内容');
      }
      this.addTodo();
      this.$message.success('已成功添加新任务');
    },
    //# 监听删除按钮,完成删除功能
    async deleteById(id) {
      // 弹出确认框(返回值为promise对象,所以用async,await)
      const confirmResult = await this.$confirm(
        '此操作将永久删除该任务, 是否继续?',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err);
      // 如果确认删除,返回字符串,confirm;否则返回cancel
      if (confirmResult !== 'confirm') {
        return this.$message.info('取消删除');
      }
      this.$store.commit('deletemyTodo', id);
      this.$message.success('删除任务成功');
    },
    //# 监听修改任务状态
    switchChange(id, completed) {
      const params = {
        id,
        completed
      };
      this.$store.commit('modefyTodo', params);
      this.$message.success('状态修改成功');
    },
    //# 监听清空已完成任务按钮
    async deleteDoneTodo() {
      const confirmResult = await this.$confirm(
        '此操作将永久删除该任务, 是否继续?',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err);
      if (confirmResult !== 'confirm') {
        return this.$message.info('取消了删除');
      }
      this.$store.commit('removeDone');
      this.$message.success('删除了全部的已完成');
    },
    //# 监听按钮切换事件
    changeList(key) {
      this.$store.commit('changeLight', key);
    }
  },
  computed: {
    //# 把数据写入计算属性中
    ...mapState(['inputValue', 'viewKey']),
    //# 把getters修饰的数据写入计算属性
    ...mapGetters(['doneTodo', 'infolist'])
  }
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
h1 {
  margin-left: 550px;
  font-size: 100px;
  color: pink;
  text-shadow: 0 6px 6px red;
}
.el-input__inner {
  padding: 0;
}
.add_text input {
  width: 100%;
  font-size: 18px;
  padding-left: 9px;
  border: none;
  outline: none;
}
.add_todo {
  margin-top: 18px;
}
.myinput {
  border-bottom: 1px solid red;
}
.todo_order {
  margin-top: 18px;
}
.mystyle {
  font-size: 19px;
  color: red;
}
.mycursor {
  cursor: pointer;
}
.el-row {
  margin-top: 21px;
}
.already {
  color: #ccc;
  text-decoration: line-through;
}
</style>

注意值得注意的是,vuex的思想,一定要确保数据只能由mutations 中的函数来修改,且函数都必须传递state 参数。了解更多Vuex:https://blog.csdn.net/cwq521o/article/details/107289221

奥利给
Logo

前往低代码交流专区

更多推荐