基于vue实现todos案例

540 阅读1分钟

案例介绍

  1. 使用@vue/cli脚手架搭建vue项目
  2. 将todos案例组件化开发
    1. TodoHeader.vue组件:todos头部模块
    2. TodoMain.vue组件:todos主体模块
    3. TodoFooter.vue组件:todos尾部模块
  3. 运用到的技术点
    1. Vue组件化开发
    2. 组件通信
    3. 计算属性
    4. watch侦听器
    5. localStorage本地存储

注意:有更简单的写法,此案例只是为了练习底层写法

效果图

todos.gif

实现代码

1. 根组件

<template>
  <div id="app">
    <section class="todoapp">
      <TodoHeader :todos="list" @addtodo="addtodoFn" @isAllChange="isAllChangeFn"></TodoHeader>
      <TodoMain :todos="showTodos" @delTodo="delTodoFn"></TodoMain>
      <TodoFooter :todos="list" @statusChange="statusChangeFn" @chearDone="clearDoneFn"></TodoFooter>
    </section>
  </div>
</template>

<script>
// 1.0 样式引入
import "./styles/base.css";
import "./styles/index.css";

// 2. 引入组件
import TodoHeader from "./components/TodoHeader";
import TodoMain from "./components/TodoMain";
import TodoFooter from "./components/TodoFooter";
export default {
  name: "App",
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter,
  },
  data() {
    return {
      list: JSON.parse(localStorage.getItem('todoList')) || [],
      todoStatus: 'all'
    }
  },
  created() {
    console.table(this.list);
  },
  computed: {
    // 通过响应书状态 根据待办事项的不同状态切换展示
    showTodos() {
      if (this.todoStatus === 'done') {
        return this.list.filter(item => item.isDone === true);
      } else if (this.todoStatus === 'undone') {
        return this.list.filter(item => item.isDone === false);
      } else {
        return this.list;
      }
    },
  },
  methods: {
    // 添加待办事项
    addtodoFn(val) {
      console.log('1');
      this.list.push({
        id: Date.now(),
        name: val,
        isDone: false
      })
      console.log(this.list);
    },
    // 删除待办事项处理函数
    delTodoFn(id) {
      this.list = this.list.filter(item => item.id !== id);
    },
    // 切换状态
    statusChangeFn(status) {
      this.todoStatus = status
    },
    // 清除已完成事项功能
    clearDoneFn() {
      console.log('22');
      this.list = this.list.filter(item => item.isDone === false);
    },
    // 根据子组件传递的是否全选状态, 设置待办事项选中状态 
    isAllChangeFn(val) {
      console.log('22');
      this.list.forEach(item => item.isDone = val);
    }
  },
  watch: {
    list: {
      deep: true,
      handler() {
        localStorage.setItem('todoList', JSON.stringify(this.list))
      }
    }
  }
};
</script>

<style>
</style>

2. 头部组件

<template>
  <header class="header">
    <h1>todos</h1>
    <input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll" >
    <label for="toggle-all"></label>
    <input
      class="new-todo"
      placeholder="输入任务名称-回车确认"
      autofocus
      
      @keyup.enter="enterFn"
      v-model.trim="inputTodo"
    />
  </header>
</template>

<script>
export default {
  name: 'TodoHeader',
  props: ['todos'],
  data() {
    return {
      inputTodo: '',
    }
  },
  computed: {
    isAll: {
      get() {
        return this.todos.every(item => item.isDone === true);
      },
      set(val) {
        console.log(val);
        this.$emit('isAllChange', val)
      }
    }
  },
  methods: {
    enterFn() {
      // 检测输入框不能为空
      if (this.inputTodo === '') {
        return alert('蠢东西不输入东西怎么给你返回东西')
      }
      console.log('22');
      // 触发父组件自定义事件,通知父组件
      this.$emit('addtodo',this.inputTodo);
      this.inputTodo = '';
    }
  }
 
}
</script>

3. 尾部组件

<template>
  <footer class="footer">
    <span class="todo-count">剩余<strong>{{ undoneNum }}</strong></span>
    <ul class="filters" @click="changeStatus">
      <li>
        <a @click="todoStatus = 'all'" :class="{selected: todoStatus === 'all'}" href="javascript:;" >全部</a>
      </li>
      <li>
        <a @click="todoStatus = 'undone'" :class="{selected: todoStatus === 'undone'}" href="javascript:;">未完成</a>
      </li>
      <li>
        <a @click="todoStatus = 'done'" :class="{selected: todoStatus === 'done'}" href="javascript:;" >已完成</a>
      </li>
    </ul>
    <button @click="clearDoneBtn" class="clear-completed" >清除已完成</button>
  </footer>
</template>

<script>
export default {
  name: 'TodoFooter',
  props: ['todos'],
  data() {
    return {
      todoStatus: 'all',
    }
  },
  computed: {
    undoneNum() {
      return this.todos.filter(item => item.isDone === false).length;
    }
  },
  methods: {
    // 切换状态过滤待办事项列表, 通知父组件处理
    changeStatus(e) {
      if (e.target.tagName === 'A') {
        console.log(this.todoStatus);
        this.$emit('statusChange', this.todoStatus)
      }
    },
    // 清除已完成点击事件, 通知父元素进行数据处理
    clearDoneBtn() {
      this.$emit('chearDone');
    }
  }
}
</script>