Vue & todoList实例
Vue实例化进程 & todoList程序的简单实现,通过使用todoList程序来完成任务清单的记录和管理,需要实现如下几个核心功能
- 通过表单完成内容输入以输出到todoList任务项
- 删除单个任务项条目,鼠标移入删除按钮显移出隐
- 任务条目已完成状态,添加删除线的效果示以区别
- 统计任务条目的完成量以及总量,实现全选、全不选以及相应条目的删除操作
- 增加存储方案,完成内容数据的本地存储化操作,以分离程序的开发模式寄存
静态页面
- 主题信息项
- 任务条目项
- 任务统计项
- 内容输出项
拆分组件
- 创建入口文件main.js
- 创建主页面文件App.vue
- 按照页面结构功能,拆分静态页面并创建相互独立的模块化组件文件,同时在主页面引入各个组件
拆分样式
根据所拆分的组件按需拆分样式,化整为零
初始化页面
在添加交互之前,须运行项目文件,查看页面是否可以达到初始化的效果,若没有,须依步检查各个组件的结构和样式,修复错误
添加页面交互
- 创建数据来源todotasks,该属性须传递给listItem组件使用,以实现todoList应用的初始化显示
- 通过input添加数据并且输出到todoList任务项
- 鼠标移入移出时删除按钮的显示效果和删除单个todoList任务项
- todoList任务条目的全选、全不选,和相应的删除操作
数据本地存储化
通过localStorage完成在本地的数据存储,在该todoList中的数据来源于todotasks
在localStoage存储的数据以key:value的形式存在
写入数据到localStorge
watch:{
todotasks:{
deep:true,
handler(sourceData){
window.localStorage.setItem('singleTask',JSON.stringify(sourceData))
}
}
}
从localStorge读取数据
data(){
return {
todotasks:JSON.parse(window.localStorage.getItem('singleTask')||'[]')
}
}
the fact for using components
- main.js
// main.js
import Vue from 'vue'
import App from './App'
Vue.config.productionTip=false
new Vue({
el:'#app',
components:{
App
},
template:'<App/>'
})
- App.vue
// App.vue
<template>
<div id='todoList'>
<div id='list_head'>
<span id='day'>My Day</span>
<span id='date'>{{currTime}}</span>
</div>
<listTask :todotask='todotasks' :deleteTask='deleteTask'/>
<listTotal :todotask='todotasks' :allSelectTasks='allSelectTasks' :deleteSelectTasks='deleteSelectTasks'/>
<listInput :addTodo='addTodo'/>
</div>
</template>
<script>
import listTask from './components/listTask'
import listTotal from './components/listTotal'
import listInput from './components/listInput'
export default {
name:'App',
data(){
return {
todotasks:JSON.parse(window.localStorage.getItem('singleTask')||'[]'),
/*[
{todo:'keep practice and enough patient', done:false},
{todo:'make different and never giving up',done:true},
]*/
currTime:new Date().toLocaleDateString()+' '+new Date().toLocaleTimeString()
}
},
components:{
listTask,
listTotal,
listInput
},
methods:{
addTodo(todoItem){
this.todotasks.unshift(todoItem)
},
deleteTask(index){
this.todotasks.splice(index,1)
},
deleteSelectTasks(){
this.todotasks=this.todotasks.filter(todoItem=>!todoItem.done)
},
allSelectTasks(checked){
this.todotasks.forEach(todoItem=>todoItem.done=checked)
}
},
watch:{
todotasks:{
deep:true,
handler(sourceData){
window.localStorage.setItem('singleTask',JSON.stringify(sourceData))
}
}
}
}
</script>
<style>
* {
margin:0;
padding:0;
}
#todoList {
width:500px;
padding:20px;
border:1px solid rgb(210, 210, 210);
margin:60px auto;
box-sizing:border-box;
position:relative;
}
#list_head {
margin-bottom:45px;
}
#list_head>#day {
font-weight:bold;
font-size:18px;
}
#list_head>#date {
float:right
}
</style>
- listTask.vue
// listTask.vue
<template>
<div id='list_task'>
<ul>
<listItem v-for='(i,index) in todotask' :key='index' :i='i' :index='index' :deleteTask='deleteTask'/>
</ul>
</div>
</template>
<script>
import listItem from './listItem'
export default {
props:{
todotask:Array,
deleteTask:Function
},
components:{
listItem
}
}
</script>
<style>
#list_task {
margin:25px 0;
}
#list_task>ul {
list-style:none;
}
</style>
- listItem.vue
// listItem.vue
<template>
<li class='task_item' @mouseenter="handle(true)" @mouseleave='handle(false)' :style='{backgroundColor:backColor}'>
<label>
<input type='checkbox' name='task_item' v-model='i.done'/>  
<span :class='{active:i.done}'>{{i.todo}}</span>
</label>
<button class='item_btn' v-show='btnShow' @click='deleteItem'>Delete Here</button>
</li>
</template>
<script>
export default {
props:{
i:Object,
index:Number,
deleteTask:Function
},
data(){
return {
backColor:'rgb(255,255,255)',
btnShow:false
}
},
methods:{
handle(isflow){
if(isflow){
this.btnShow=true
}else{
this.btnShow=false
}
},
deleteItem(){
const{i,index,deleteTask}=this
if(window.confirm(`是否删除${i.todo}?`)){
deleteTask(index)
}
}
},
}
</script>
<style scoped>
.task_item {
box-sizing:border-box;
height:40px;
margin:20px 0;
border-bottom:1px solid rgb(225, 225, 225);
padding-bottom:12px;
}
.active {
text-decoration:line-through;
}
.item_btn {
position:absolute;
width:120px;
height:28px;
border:none;
outline:none;
background-color:rgb(224, 106, 106);
color:rgb(250, 235, 235);
cursor:pointer;
right:20px;
}
</style>
- listTotal.vue
// listTotal.vue
<template>
<div id='list_total'>
<input type='checkbox' name='total_task' id='total_task' v-model='isCheckAll'/>  
<label for='total_task'>Selected {{totalComplate}} , Total {{todotask.length}}</label>
<button id='btn' v-show='totalComplate' @click='deleteSelectTasks'>Delete Task</button>
</div>
</template>
<script>
export default {
props:{
todotask:Array,
allSelectTasks:Function,
deleteSelectTasks:Function,
},
computed:{
totalComplate(){
return this.todotask.reduce((preTotal,todoItem)=>preTotal+(todoItem.done?1:0),0)
},
isCheckAll:{
get(){
return this.totalComplate===this.todotask.length && this.totalComplate>0
},
set(value){
this. allSelectTasks(value)
}
}
}
}
</script>
<style>
#list_total {
margin-top:55px;
}
#list_total #btn {
position:absolute;
width:120px;
height:28px;
border:none;
outline:none;
background-color:rgb(224, 106, 106);
color:rgb(250, 235, 235);
cursor:pointer;
right:20px;
}
</style>
- listInput.vue
// listInput.vue
<template>
<div id='list_input'>
<input type='text' name='list_input' class='list_input' v-model='todo' @keyup.enter='addContent' placeholder="Start Your New Day , Mange Your Time , Make It Better"/>
</div>
</template>
<script>
export default {
props:{
addTodo:Function
},
data(){
return {
todo:''
}
},
methods:{
addContent(){
const todo=this.todo.trim()
if(!todo){
alert('please input information')
return
}
const todoItem={
todo,
done:false
}
this.addTodo(todoItem);
this.todo=''
}
}
}
</script>
<style>
#list_input {
width:460px;
margin-top:40px;
}
#list_input .list_input {
box-sizing:border-box;
width:460px;
height:50px;
outline:none;
border:1px solid rgb(225,225, 225);
padding:0 15px;
}
</style>
the fact for focusing method , just taking App
- main.js
// main.js
import Vue from 'vue'
import App from './App'
import './pattern.css'
Vue.config.productionTip=false
new Vue({
el:'#app',
template:'<App></App>',
components:{
App:App
}
})
- App.vue
// App.vue
<template>
<div id='todoList'>
<div id='list_head'>
<span id='day'>My Day</span>
<span id='date' v-text='currtime'></span>
</div>
<div id='list_task'>
<ul>
<li class='task_item' v-for='(every) in todotasks' @mouseenter='handle(true)' @mouseleave='handle(false)'>
<label>
<input type='checkbox' name='task_item' v-model='every.done'/>
<span :class='{active:every.done}'>{{every.todo}}</span>
</label>
<button class='item_btn' v-show='btnShow' @click='deleteTasks' >Delete Here</button>
</li>
</ul>
</div>
<div id='list_total'>
<label @click='allSelectTasks'>
<input type='checkbox' name='total_task' v-model='isCheckAll'/>
<span>Selected {{totalComplate}} , Total {{todotasks.length}}</span>
</label>
<button id='btn' @click='deleteAllSelect' v-show='deleteAll' >Delete Task</button>
</div>
<div id='list_input'>
<input type='text' name='list_input' class='listInput' placeholder="Start Your New Day , Mange Your Time , Make It Better" v-model='inputData' @keydown.enter='addContent'/>
</div>
</div>
</template>
<script>
export default {
data(){
return {
todotasks:JSON.parse(window.localStorage.getItem('singleTask'||'[]')),
currtime:new Date().toLocaleDateString()+' '+new Date().toLocaleTimeString(),
btnShow:false,
deleteAll:false,
inputData:'',
sele:false
}
},
computed:{
totalComplate(){
return this.todotasks.reduce((preTotal,todoItem)=>preTotal+(todoItem.done?1:0),0)
},
isCheckAll:{
get(){
return this.totalComplate===this.todotasks.length && this.totalComplate>0
},
set(value){
this. allSelectTasks(value)
}
}
},
methods:{
handle(isenter){
if(isenter){
this.btnShow=true
}else{
this.btnShow=false
}
},
addContent(){
const todoItems={
todo:this.inputData,
done:false
}
if(!this.inputData){
alert('please input information!')
return
}
this.todotasks.unshift(todoItems)
this.inputData=''
},
deleteTasks(index){
if(confirm('Do you delete this item')){
this.todotasks.splice(index,1)
}
},
allSelectTasks(checked){
this.todotasks.forEach(every=>every.done=checked)
},
deleteAllSelect(){
this.todotasks=this.todotasks.filter(item=>!item.done)
},
},
watch:{
totalComplate:function(){
if(this.totalComplate>0){
this.deleteAll=true
}else{
this.deleteAll=false
}
},
todotasks:{
deep:true,
handler(sourceData){
window.localStorage.setItem('singleTask',JSON.stringify(sourceData))
}
}
}
}
</script>
<style scoped>
</style>
the result
数组方法
Array methods
unshift() ,在数组前端添加任意个项返回新数组的长度
splice() ,splice是一个强大的方法,可以实现删除、插入、替换
filter() , 它利用指定的函数,指定规则并返回新的数组,适用于查询符合某些条件的数组项
map() ,使用该方法使原数组在每一项的基础上运行传入函数,返回一个新的数组
forEach(),对数组中的每一项运行传入的回调函数,该方法没有返回值
reduce() ,该方法从数组的第一项开始,遍历到最后,迭代数组的所有项
String methods
trim() ,该方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果
let a=' night '
let ai=a.trim()
let an=[3,4,8,56,556,'slogn']
an.unshift('78','red')
an.splice(0,2)
let ant=an.filter(item=>item>8)
let any=an.map(item=>item*3)
an.forEach(item=>{console.log(item+1)})
let ano=an.reduce(function(prev,cur,index,Array)=>{return prev+cur})
Date函数
toLocaleDateString() , 以特定市区的方式显示年/月/日/星期几
toLocalTimeString() , 以特定于实现的方式显示时/分/秒