一点点前言
这是一个经典的实现数据双向绑定的例子,其中着重围绕“一切以数据驱动”这个思想理念来讲解,知识点挺多。概括下是以下三点
- 数据双向绑定
- 本地localStorege数据存取
- 数据更新监控
-
computed
计算数据条目 -
directives
自定义指令 - window的hash值应用筛选
直接上效果图!~
出静态
- 首先写好静态页面以及样式;
- 适时也可以造一些伪数据来做调试支撑;
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 对象的每一个属性。
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-model
和 v-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
:
控制台输出形参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);