Vue & todoList实例

Vue实例化进程 & todoList程序的简单实现,通过使用todoList程序来完成任务清单的记录和管理,需要实现如下几个核心功能

  1. 通过表单完成内容输入以输出到todoList任务项
  2. 删除单个任务项条目,鼠标移入删除按钮显移出隐
  3. 任务条目已完成状态,添加删除线的效果示以区别
  4. 统计任务条目的完成量以及总量,实现全选、全不选以及相应条目的删除操作
  5. 增加存储方案,完成内容数据的本地存储化操作,以分离程序的开发模式寄存

静态页面

  1. 主题信息项
  2. 任务条目项
  3. 任务统计项
  4. 内容输出项

拆分组件

  1. 创建入口文件main.js
  2. 创建主页面文件App.vue
  3. 按照页面结构功能,拆分静态页面并创建相互独立的模块化组件文件,同时在主页面引入各个组件

拆分样式

根据所拆分的组件按需拆分样式,化整为零

初始化页面

在添加交互之前,须运行项目文件,查看页面是否可以达到初始化的效果,若没有,须依步检查各个组件的结构和样式,修复错误

添加页面交互

  1. 创建数据来源todotasks,该属性须传递给listItem组件使用,以实现todoList应用的初始化显示
  2. 通过input添加数据并且输出到todoList任务项
  3. 鼠标移入移出时删除按钮的显示效果和删除单个todoList任务项
  4. 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'/>&nbsp&nbsp
      <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'/>&nbsp&nbsp
    <label for='total_task'>Selected&nbsp{{totalComplate}}&nbsp, Total&nbsp{{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&nbsp{{totalComplate}}&nbsp, Total&nbsp{{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

todo

数组方法

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() , 以特定于实现的方式显示时/分/秒

posted @ 2021-02-05 10:49  Serenpity  阅读(148)  评论(0编辑  收藏  举报