Vue任务列表实例

一点点前言

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

  • 数据双向绑定
  • 本地localStorege数据存取
  • 数据更新监控
  • computed计算数据条目
  • directives自定义指令
  • window的hash值应用筛选

直接上效果图!~

最终效果

出静态

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

添加指令

v-for

  • **用途: **根据一组数据的选项列表进行渲染
  • 语法: value, key in items | value, key of items
  • 方法: vue提供一组内部实现的方法,对数组进行操作的时候,会触发视图更新,用法和方法名同原生js一致
  • API
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
<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

  • 用途:用来监听DOM事件触发代码
  • 语法: `v-on:eventName="eventHandle"
  • 简写: @
  • 事件处理函数:写在methods{}中统一管理
  • 事件对象: 在事件处理函数中获取,内联事件处理函数执行,传入事件对象$event
  • 事件修饰符:事件处理函数只有纯粹的逻辑判断,不处理DOM事件的细节。例如:阻止冒泡、取消默认行为、判断按键等。
  • API
<!--
    @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>
  • .stop -调用event.stopPropagation()
  • .prevent - 调用 event.preventDefault()
  • .capture -添加事件监听器时使用capture模式
  • .self -只当事件是从侦听器绑定的元素本身触发时才触发回调
  • .{keyCode|keyAlias} -只当事件是从特定键触发时才触发回调
  • .native -监听组件根元素的原生事件
  • .once - 只触发一次回调
  • .left - 只当点击鼠标左键时触发(v2.2.0)
  • .right - 只当点击鼠标右键时触发(v2.2.0)
  • .middle - 只当点击鼠标中键时触发(v2.2.0)
  • .passive - 以{passive:true}模式添加侦听器(v2.3.0)
  <!-- 串联修饰符 -->
  <button @click.stop.prevent="doThis"></button>
  <!-- 键修饰符,键别名 -->
  <input @keyup.enter="onEnter">
  <!-- 键修饰符,键代码 -->
  <input @keyup.13="onEnter">
  <!-- 点击回调只会触发一次 -->
  <button v-on:click.once="doThis"></button>
  • 按键修饰符
    • .enter
    • .tab
    • .delete
    • .esc
    • .space
    • .up
    • .down
    • .ctrl
    • .alt
    • .shift
    • .meta
//可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
//栗子 可以使用 v-on:keyup.f1
Vue.config.keyCodes.f1 = 112

v-model

  • 类型: 随表单控件类型不同而不同。
  • 限制:
    • <input>
    • <select>
    • <textarea>
    • components
  • 用法: 在表单控件或组件上创建双向绑定。
  • API
<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

  • 类型: any
  • 用法:
    根据表达式之真假值,切换元素的 display CSS 属性。
    当条件变化时该指令触发过渡效果。
  • API
 <ul class="task-count" v-show="list.length">
   
<span class="no-task-tip" v-show="!list.length">还没有添加任何任务</span>  

v-bind

  • 缩写: :
  • API
 <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

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

  • 选项数据
  • 类型:{ [key: string]: Function | { get: Function, set: Function } }
  • 详细:
    • 计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。

    • 计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。

    • 注意,不应该使用箭头函数来定义计算属性函数 (例如 aDouble: () => this.a * 2)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

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:

  • 选项数据

  • 类型:{ [key: string]: string | Function | Object }

  • 详细:

    一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

  • API

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

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

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

methods:

  • 选项参数
  • **类型:****{ [key: string]: Function }
  • 详细:methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this自动绑定为 Vue 实例。
  • 事件处理函数中的this指向的是当前根实例new Vue
  • API

新增任务-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 也允许注册自定义指令

  • 选项参数

  • 钩子函数(可选)

    • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
  • 钩子函数参数

    • el: 指令所绑定的元素,可以用来直接操作 DOM 。
    • binding: 一个对象,包含以下属性:
    • value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2

    案例里所应用到的,添加focus效果

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

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

控制台输出形参el

el

控制台输出形参binding

binding


本地存储

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

hash过滤

  • 定义和用法:hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。
watchHashChange(); //函数默认自运行

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

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

window.addEventListener('hashchange', watchHashChange);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279

推荐阅读更多精彩内容

  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,921评论 4 129
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 4,994评论 0 29
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,127评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,111评论 18 139
  • 下载安装搭建环境 可以选npm安装,或者简单下载一个开发版的vue.js文件 浏览器打开加载有vue的文档时,控制...
    冥冥2017阅读 5,986评论 0 42