前端培训VUE之demo2:todolist

1.store/types.js
/** * 包 含 多 个 mutation name */ export const RECEIVE_TODOS = ‘receive_todos’ export const ADD_TODO = ‘add_todo’ export const REMOVE_TODO = ‘remove_todo’ export const DELETE_DONE = ‘delete_done’ export const UPDATE_ALL_TODOS = ‘update_all_todos’
2.store/mutations.js
import {RECEIVE_TODOS, ADD_TODO, REMOVE_TODO, DELETE_DONE, UPDATE_ALL_TODOS} from ‘./types’
export default { [RECEIVE_TODOS] (state, {todos}) { state.todos = todos },
[ADD_TODO] (state, {todo}) { state.todos.unshift(todo) },
[REMOVE_TODO] (state, {index}) { state.todos.splice(index, 1) },
[DELETE_DONE] (state) { state.todos = state.todos.filter(todo => !todo.complete) },
[UPDATE_ALL_TODOS] (state, {isCheck}) { state.todos.forEach(todo => todo.complete = isCheck) }
}

3.store/actions.js
import storageUtil from ‘../util/storageUtil’ import {RECEIVE_TODOS, ADD_TODO, REMOVE_TODO, DELETE_DONE, UPDATE_ALL_TODOS} from ‘./types’
export default { readTodo ({commit}) { setTimeout(() => { const todos = storageUtil.fetch() // 提 交 commit 触 发 mutation 调 用 commit(RECEIVE_TODOS, {todos}) }, 1000) },
addTodo ({commit}, todo) { commit(ADD_TODO, {todo}) },
removeTodo ({commit}, index) { commit(REMOVE_TODO, {index}) },
deleteDone ({commit}) { commit(DELETE_DONE) },
updateAllTodos ({commit}, isCheck) { commit(UPDATE_ALL_TODOS, {isCheck}) }
}
4.store/getters.js
export default { todos (state) { return state.todos },

totalSize (state) { return state.todos.length },
completeSize (state) { return state.todos.reduce((preTotal, todo) => { return preTotal + (todo.complete ? 1 : 0) }, 0) },
isAllComplete (state, getters) { return getters.totalSize===getters.completeSize && getters.totalSize>0 }
}
5.store/index.js
import Vue from ‘vue’ import Vuex from ‘vuex’ import mutations from ‘./mutations’ import actions from ‘./actions’ import getters from ‘./getters’
Vue.use(Vuex)
const state = { todos: [] }
export default new Vuex.Store({ state, mutations, actions, getters })

6.components/app.vue
<template> <div class=”todo-container”> <div class=”todo-wrap”> <todo-header></todo-header> <todo-main></todo-main> <todo-footer></todo-footer> </div> </div> </template>
<script> import todoHeader from ‘./todoHeader.vue’ import todoMain from ‘./todoMain.vue’ import todoFooter from ‘./todoFooter.vue’ import storageUtil from ‘../util/storageUtil’
export default { created () { // 模 拟 异 步 读 取 数 据 this.$store.dispatch(‘readTodo’) },
components: { todoHeader, todoMain, todoFooter }
} </script>
<style> .todo-container { width: 600px; margin: 0 auto; }
.todo-container .todo-wrap { padding: 10px; border: 1px solid #ddd;
border-radius: 5px;
} </style>
7.components/todoHeader.vue
<template> <div class=”todo-header”> <input type=”text” placeholder=”请输入你的任务名称,按回车键确认” v-model=”title” @keyup.enter=”addItem”/> </div> </template>
<script type=”text/ecmascript-6″> export default { data () { return { title: null } }, methods: { addItem () { const title = this.title && this.title.trim() if (title) { const todo = { title, complete: false } this.$store.dispatch(‘addTodo’, todo) this.title = null } } } } </script>
<style> .todo-header input { width: 560px; height: 28px;

font-size: 14px; border: 1px solid #ccc; border-radius: 4px; padding: 4px 7px;
}
.todo-header input:focus { outline: none; border-color: rgba(82, 168, 236, 0.8); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } </style>
8.components/todoMain.vue
<template> <ul class=”todo-main”> <todo-item v-for=”(todo, index) in todos” :todo=”todo” :key=”index” :index=”index”></todo-item> </ul> </template>
<script type=”text/ecmascript-6″> import todoItem from ‘./todoItem’ import storageUtil from ‘../util/storageUtil’
export default {
components: { todoItem },
computed: { todos () { return this.$store.getters.todos } },
watch: { todos: {//
深 度 监 视 todos,
一 旦 有 变 化 立 即 保 存

handler: storageUtil.save, deep: true
} },
} </script>
<style> .todo-main { margin-left: 0px; border: 1px solid #ddd; border-radius: 2px; padding: 0px; }
.todo-empty { height: 40px; line-height: 40px; border: 1px solid #ddd; border-radius: 2px; padding-left: 5px; margin-top: 10px; } </style>
9.components/todoItem.vue
<template> <li :style=”{background: libg}” @mouseenter=”handleStyle(true)” @mouseleave=”handleStyle(false)”> <label> <input type=”checkbox” v-model=”todo.complete”/> <span>{{todo.title}}</span> </label> <button class=”btn btn-danger” v-show=”isShown” @click=”deleteItem”>删除</button> </li> </template>
<script type=”text/ecmascript-6″> export default {

props: [‘todo’, ‘index’], data () { return { isShown: false, libg: ‘#fff’ } }, methods: { handleStyle (isEnter) { if (isEnter) { this.isShown = true this.libg = ‘#ddd’ } else { this.isShown = false this.libg = ‘#fff’ } }, deleteItem () { const {todo, deleteTodo, index} = this if (window.confirm(`确定删除${todo.title}的评论吗?`)) { // deleteTodo(index) this.$store.dispatch(‘removeTodo’, index) } } }
} </script>
<style> li { list-style: none; height: 36px; line-height: 36px; padding: 0 5px; border-bottom: 1px solid #ddd; }
li label { float: left; cursor: pointer; }

li label li input { vertical-align: middle; margin-right: 6px; position: relative; top: -1px; }
li button { float: right; display: none; margin-top: 3px; }
li:before { content: initial; }
li:last-child { border-bottom: none; } </style>
10.components/todoFooter.vue
<template> <div class=”todo-footer”> <label> <input type=”checkbox” v-model=”isAllDone”/> </label> <span> <span>已完成{{completeSize}}</span> / 全部{{totalSize}} </span> <button class=”btn btn-danger” @click=”deleteDone” v-show=”completeSize>0″>清除已 完成任务</button> </div> </template>
<script> import {mapGetters, mapActions} from ‘vuex’ export default {
methods: mapActions([‘deleteDone’]),
computed: { isAllDone: { get () { return this.$store.getters.isAllComplete }, set (value) { //this.$emit(‘updateTodos’, value) this.$store.dispatch(‘updateAllTodos’, value) } }, …mapGetters([‘completeSize’, ‘totalSize’]) }
} /* const arr1 = [1, 3, 5] const arr2 = [4, …arr1, 7] const obj = { a: 1, b () {
}
} const obj2 = { c: 3, …obj }*/ </script>
<style> .todo-footer { height: 40px; line-height: 40px; padding-left: 6px; margin-top: 5px; }
.todo-footer label { display: inline-block; margin-right: 20px;

cursor: pointer;
}
.todo-footer label input { position: relative; top: -1px; vertical-align: middle; margin-right: 5px; }
.todo-footer button { float: right; margin-top: 5px; } </style>
11.util/storageUtil.js
var STORAGE_KEY = ‘todos’ export default { fetch () { return JSON.parse(localStorage.getItem(STORAGE_KEY) || ‘[]’) }, save (todos) { localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)) } }
12.base.css
body { background: #fff; }
.btn { display: inline-block; padding: 4px 12px; margin-bottom: 0; font-size: 14px;

line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); border-radius: 4px;
}
.btn-danger { color: #fff; background-color: #da4f49; border: 1px solid #bd362f; }
.btn-danger:hover { color: #fff; background-color: #bd362f; }
.btn:focus { outline: none; }
13.main.js
import Vue from ‘vue’ import App from ‘./components/app’ import store from ‘./store’
import ‘./base.css’
/* eslint-disable no-new */ new Vue({ el: ‘#app’, render: h => h(App), store })
想要了解跟多关于web前端培训课程内容欢迎关注尚硅谷web前端培训,尚硅谷除了这些技术文章外还有免费的高质量web前端培训训课程视频供广大学员下载学习


上一篇:
下一篇:
关于尚硅谷
教育理念
名师团队
学员心声
资源下载
视频下载
资料下载
工具下载
加入我们
招聘岗位
岗位介绍
招贤纳师
联系我们
电话:010-56253825
邮箱:info@atguigu.com
地址:北京市昌平区宏福科技园综合楼6层(北京校区)

 深圳市宝安区西部硅谷大厦B座C区一层(深圳校区)

上海市松江区谷阳北路166号大江商厦6层(上海校区)