Vue任务列表实例

2017-06-03  本文已影响0人  我是白夜

一点点前言

这是一个经典的实现数据双向绑定的例子,其中着重围绕“一切以数据驱动”这个思想理念来讲解,知识点挺多。概括下是以下三点

直接上效果图!~

最终效果

出静态

  1. 首先写好静态页面以及样式;
  2. 适时也可以造一些伪数据来做调试支撑;
var list = [{
    title: "测试文字1111111",  //清单列表文本
    isChecked: false        //勾选状态
}, {
    title: "测试文字2222222",
    isChecked: true
}];

添加指令

v-for

<li class="todo" :class="{completed:item.isChecked,editing:item === editorText}" v-for="item in filterList">
  
<!--"item in filterList"也可以写成"item of filterList"--> 
<li class="todo" :class="{completed:item.isChecked,editing:item === editorText}" v-for="item of filterList">

v-on

<!--
    @keyup.13  效果等价于@keyup.enter   触发enter键
    @keyup.esc   触发esc键 
    @blur                触发表单失焦事件
-->
<input placeholder="例如:吃饭睡觉打豆豆;  提示:+回车即可添加任务" class="task-input" type="text" v-model="todo" @keyup.13="addTodo" />

<input class="edit" type="text" v-focus="item === editorText" @keyup.13="editorCompleted(item)" @keyup.esc="editorCancel(item)" @blur="editorCompleted(item)" v-model="item.title" />

<button class="destroy" @click="deleteTodo(item)"></button>
  <!-- 串联修饰符 -->
  <button @click.stop.prevent="doThis"></button>
  <!-- 键修饰符,键别名 -->
  <input @keyup.enter="onEnter">
  <!-- 键修饰符,键代码 -->
  <input @keyup.13="onEnter">
  <!-- 点击回调只会触发一次 -->
  <button v-on:click.once="doThis"></button>
//可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
//栗子 可以使用 v-on:keyup.f1
Vue.config.keyCodes.f1 = 112

v-model

<input placeholder="例如:吃饭睡觉打豆豆;  提示:+回车即可添加任务" class="task-input" type="text" v-model="todo" @keyup.13="addTodo" />

<input class="toggle" type="checkbox" v-model="item.isChecked" />

<input class="edit" type="text" v-focus="item === editorText" @keyup.13="editorCompleted(item)" @keyup.esc="editorCancel(item)" @blur="editorCompleted(item)" v-model="item.title" />

v-show

 <ul class="task-count" v-show="list.length">
   
<span class="no-task-tip" v-show="!list.length">还没有添加任何任务</span>  

v-bind

 <li class="action">
   <!--active  与当前hash值绑定添加-->
   <a href="#all" :class="{active:visibility===`all`}">所有任务</a>
   <a href="#unfinished" :class="{active:visibility===`unfinished`}">未完成的任务</a>
   <a href="#finished" :class="{active:visibility===`finished`}">完成的任务</a>
</li>

选项参数

el

el: ".main" //挂载元素

data:

 data: {
   list: list, //数据
   todo: "", //输入表单内数据
   editorText: "", //记录正在编辑的状态
   beforeText: "", //临时记录编辑之前的内容以便后期撤销编辑使用
   visibility: "all" // 通过该属性来进行数据筛选
 }

computed

计算属性在模板内的表达式是非常便利的,但是它们实际上只用于简单的运算。在模板中放入太多的逻辑会让模板过重且难以维护

Example:

不推荐:

<!--
在这种情况下,模板不再简单和清晰。在意识到这是反向显示 message 之前,你不得不再次确认第二遍。
当你想要在模板中多次反向显示 message 的时候,问题会变得更糟糕。
这就是对于任何复杂逻辑,你都应当使用计算属性的原因。
-->
<li>{{list.filter(function(item){ return !item.isChecked }).length}} 个未完成 </li

推荐

<li>{{noCheckedLength}}个任务未完成</li>
computed: { //计算
  // 筛选出未完成isChecked为false的数量
  unCheckedLength() {
    return this.list.filter(function(item) {
      return !item.isChecked;
    }).length;
  },
    //过滤hash值
    filterList: function() {
      var filter = {
        all: function() { // 过滤显示数据
          return list; //返回所有数据
        },
        unfinished: function() {
          return list.filter(function(item) {
            return !item.isChecked; //返回未完成数据
          });
        },
        finished: function() {
          return list.filter(function(item) {
            return item.isChecked; //返回已完成数据
          });
        }
      };

      // 当hash值不符合过滤条件时,显示所有
      return filter[this.visibility] ? filter[this.visibility](list) : list;
    }
}

watch:

 watch: {
   // 监控list属性,有数据变动时触发

   //浅监控:不会监控到对象的属性一层
   // list: function() { 
   //     store.save("todo-Key", this.list);
   // }

   //深监控:"下探"到对象属性一层,使用{}对象包裹方法
   list: {
     handler: function() {
       store.save("todo-Key", this.list);
     },
       // deep需要设置为true
       deep: true
   }
 }

methods:

新增任务-addTodo()

addTodo(todo) { //添加任务
  // 此处为了isRepeat里的this指向,所以用'thisTodo'缓存
  var thisTodo = this.todo,
      isRepeat = this.list.some(function(item) {
        //判断是否是重复
        return item.title == thisTodo;
      });

  if (thisTodo) {
    if (isRepeat) {
      alert("任务重复");
      return false;
    } else {
      this.list.unshift({
        title: thisTodo,
        isChecked: false
      });
    }
  } else {
    alert("请输入任务");
    return false;
  }
  this.todo = ""; //回车之后清空输入框
}

移除任务-deleteTodo()

 deleteTodo(todo) { //删除任务
   var index = this.list.indexOf(todo);
   this.list.splice(index, 1);
}

编辑任务-editorTodo()

 editorTodo(todo) { //编辑任务
   //临时记录该任务的title,方便后续撤销赋值
   this.beforeText = todo.title;
   this.editorText = todo;
 }

编辑完成-editorCompleted()

etitorCompleted(todo) {
  this.editorText = "";
}

撤销编辑-editorCancel()

 editorCancel(todo) {
   todo.title = this.beforeText;
   this.beforeText='';  //注销临时数据
   this.editorText = '';  //显示div,隐藏input
 }

directives

除了默认设置的核心指令( v-modelv-show ),Vue 也允许注册自定义指令

// 自定义指令
directives: {
  // 注册一个自定义局部指令 v-focus
  "focus": { //"focus"--自定义key值,自动聚焦,在标签内调用时要加前缀"v-"

    // 钩子函数update(),被绑定的元素所在的模版更新时自行调用
    update(el, binding) {
      //el指向的是元素
      if (binding.value) {
        el.focus(); //自动获取焦点
      }
    }
  }
}

控制台输出形参el

el

控制台输出形参binding

binding

本地存储

//存取localStorage中的数据
var store = {
    save(key, value) { // 保存数据
        // 将value值转换为json的字符串格式
        localStorage.setItem(key, JSON.stringify(value));
    },
    fetch(key) { //取出数据
        return JSON.parse(localStorage.getItem(key)) || [];
    }
};

hash过滤

watchHashChange(); //函数默认自运行

//监控hash更改
function watchHashChange() {
    //截取hash值的“#”前缀
    var hash = location.hash.slice(1);

    //hash值与过滤保持条件一致,视图更新
    vm.visibility = hash;
}

window.addEventListener('hashchange', watchHashChange);
上一篇 下一篇

猜你喜欢

热点阅读