# todomvc实现日程安排

官方演示链接 <http://todomvc.com/examples/vue/#/all>

sublimer代码折叠 `ctrl +shift+{`

取消折叠 `ctrl +shift+}`

## 1.启动案例

* clone仓库

  ```bash
  ```
* Vue代码模块化

  ```javascript
  //定义vue实例挂载到window对象的app属性
  //匿名函数 自调用
  (function(exports){
      exports.app=new Vue()
  })(windos)
  ```

## 2.业务拆分

* 点击全选或者全不选

  使用input标签绑定change事件，使得事件的完成状态与标签的选中状态相挂钩

  **注意联动切换**

  ```javascript
  <input id="toggle-all" class="toggle-all" type="checkbox" @change="handelToggleAll">

  //根据change事件循环改变事件的完成状态
  methods:{
      handelToggleAll(e){
                  var checked=e.srcElement.checked //获取全选的状态
                  this.todos.forEach(item =>{
                      item.completed=checked
                  })
              }
  }
  ```
* 有无事件时的显示状态

  根据数据的有无决定页脚的显示

  ```javascript
              <footer class="footer" v-show="todos.length">
                  <span class="todo-count">
                      <strong ></strong> 
                  </span>
                  <ul class="filters">
                      <li><a href="#/all" >All</a></li>
                      <li><a href="#/active" >Active</a></li>
                      <li><a href="#/completed" >Completed</a></li>
                  </ul>
                  <button class="clear-completed"> 
                  </button>
              </footer>
  ```
* 在事件添加按钮中绑定回车按钮，用于事件的添加

  ```javascript
  <input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" v-model="newTodos" @keyup.enter="handleNewTodoKeyDown">
  //事件处理函数
                  handleNewTodoKeyDown(){
                  //input 按下回车时添加新的数据
                  var value=this.newTodos && this.newTodos.trim()
                  if(!value){
                      return
                  }
                  this.todos.push(
                      {
                      id:this.todos.length+1,
                      title:value,
                      completed:false}
                      )
                  this.newTodos=''
              }
  ```
* 双击进入编辑状态
  * 使用中间变量对改变需要编辑的任务的样式
  * 在循环输出时，加上一个input标签用于接收修改后的内容，这里巧妙在style的设定

    ```javascript
    <li class="todo" v-for="todo in todos" :key="todo.id" :class="{completed: todo.completed, editing: editedTodo == todo}">
            <div class="view">
        <input class="toggle" type="checkbox" v-model="todo.completed">
        <label @dblclick="editTodo(todo)">{{todo.title}}</label>
        <button class="destroy" v-on:click="removeTodo(todo)"></button>
            </div>
        //用于修改的input
    <input class="edit" type="text" v-model="todo.title" >
    </li>

    当点击修改时，原始数据进入隐藏状态，而修改按钮进行显示状态
    这里主要得益于css选择器，当进入编辑状态时因为在li上增加了一个编辑类
    ```
  * 在vue中设计到的逻辑
    * esc按钮终止编辑
    * enter或者失去焦点blur时保存数据
    * 在双击按钮时，将原先的数据保存到变量`beforeEditeTitle`中

      ```javascript
      editTodo(todo){
                      this.beforeEditeTitle=todo.title
                      this.editedTodo=todo

                  },

                  cancleEdite(todo){
                      this.editedTodo = null;
                      todo.title=this.beforeEditeTitle
                  },

                  doneEdite(todo){
                      if(!this.editedTodo){
                          return
                      }
                      this.editedTodo=null
                      todo.title=todo.title.trim()
                      if(!todo.title){
                          this.removeTodo(todo)
                      }
                  }
      ```
* 显示未完成的数目

  使用计算属性对数组进行过滤，同时先定义好了一个钩子对象用于显示未完成的条目的搜寻

  ```javascript
  //钩子对象
  var filters={
      all:function(todos){
          return todos;
      },
      active:function(todos){
          return todos.filter(item=>!item.completed)
      },
      completed:function(todos){
          return todos.filter(item=>item.c)
      }
  }
  //计算属性
          computed:{
              reminds:function(){
                return filters.active(this.todos).length
              }
        }
  ```

  在后面加上复数的字符

  使用pluralize方法
* 联动切换

  使用计算属性进行操作，计算属性中get方法，当访问计算属性的时候自动的调用get方法

  ```javascript
  //使用get访问计算属性，对todos的状态进行检查
  toggleAllstat:{
                  get(){
                      //所有的都为true才为true
                      return this.todos.every(todo=>(todo.completed))
                  }
  }
  //将计算属性绑定到标签上
  <input id="toggle-all" class="toggle-all" type="checkbox" v-:checked="toggleAllstat">
  ```

  改进版本，使用v-model进行联动

  ```javascript
          computed:{
            reminds:function(){
                  return filters.active(this.todos).length
            },
              toggleAllstat:{
                get(){//访问计算属性时调用的方法
                      //所有的都为true才为true
                    return this.todos.every(todo=>(todo.completed))
                  },
                set(){ //当计算属性发生改变时进行调用
                  var checked=!this.toggleAllstat //获取变化后的值
                  this.todos.forEach(item =>{
                      item.completed=checked
                  })
                  }
              }
          }
  <input id="toggle-all" class="toggle-all" type="checkbox" v-model="toggleAllstat">
  ```
* 本地持久化

  * 使用window\.localStorage中的方法对数据对象进行存储
  * 对vue实例中的数据对象进行监视，调用对应的setItem方法存储到本地

    <https://cn.vuejs.org/v2/api/#watch>

  ```javascript
  //本地化对象
  var todoStorage={
      fetch:function(){
          return JSON.parse(exports.localStorage.getItem('todos-vuejs') || '[]');
      },
      save:function(todos){
          exports.localStorage.setItem('todos-vuejs',JSON.stringify(todos))
      }
  }
  data:{
              todos:todoStorage.fetch(),
        },
  ```

watch:{ todos:{ deep:true, //对引用类型数据进行深度监视 handler:todoStorage.save //默认将新的值放在函数第一个参数位置，旧值在第二个位置 } },

* 按条件显示条目
  * 定义一个钩子对象
  * 定义一个状态变量
  * 绑定点击事件,修改对应的状态变量

```javascript
    //钩子函数
    var filters={
        all:function(todos){
            return todos;
        },
        active:function(todos){
            return todos.filter(item=>!item.completed)
        },
        completed:function(todos){
            return todos.filter(item=>item.completed)
        }
  }

  //应用到页面的计算属性
                filterTodos:{
                  get(){
                        return filters[this.filterText](this.todos);
                  }
                }
```

​

* 使用自定义指定，获得焦点

  使用Vue.directive函数定义自定义指令，，然后将指令绑定到DOM元素上，尽可能的减少DOM的操作

  ```javascript
  // 注册全局指令
  Vue.directive("focus",{
      inserted:function(el,bind){ //在被绑定元素插入到父元素时，调用聚焦事件
          el.focus()
      }

  })
  ```
*
* ​


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zpliu.gitbook.io/booknote/vue/an-li-cao-zuo/03todomvc-shi-xian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
