html文件:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Template • TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<section class="todoapp" id="app">
<header class="header">
<h1>todos</h1>
<input class="new-todo" placeholder="What needs to be done?" autofocus v-on:keydown.enter="add" v-my-focus>
</header>
<!-- This section should be hidden by default and shown when there are todos -->
<template v-if="todos.length">
<section class="main">
<!-- <input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-on:change="handleToggleAllChange"
v-bind:checked="toggleAll"> -->
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-model="toggleAll">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<!-- 任务项有三种状态
已完成 completed
未完成 无样式
编辑 edit -->
<li v-bind:class="{completed: item.completed, editing: currentEditing === item ? true : false}" v-for="(item,index) in filterTodos()">
<div class="view">
<input class="toggle" type="checkbox" v-model="item.completed">
<!-- 注册双击事件 dblclick-->
<label v-on:dblclick="dblclick(item)">{{ item.title }}</label>
<button class="destroy" v-on:click="remove(index)"></button>
</div>
<input class="edit" v-bind:value="item.title" v-on:keyup.enter="keyupSave(item, index, $event)" v-on:blur="keyupSave(item, index, $event)" v-on:keyup.esc="escDontSave(item)" v-todo-focus="currentEditing === item">
</li>
</ul>
</section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer class="footer">
<!-- This should be `0 items left` by default -->
<span class="todo-count"><strong>{{ count }}</strong> item left</span>
<!-- Remove this if you don't implement routing -->
<ul class="filters">
<li>
<a v-bind:class="{selected: todosText===''}" href="#/">All</a>
</li>
<li>
<a v-bind:class="{selected: todosText==='active'}" href="#/active">Active</a>
</li>
<li>
<a v-bind:class="{selected: todosText==='completed'}" href="#/completed">Completed</a>
</li>
</ul>
<!-- Hidden if no completed items are left ↓ -->
<!-- 只要有一个被选中就显示 -->
<button class="clear-completed" v-if="todos.some(item => item.completed)" v-on:click="clearCompleted">Clear completed</button>
</footer>
</template>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
<!-- Remove the below line ↓ -->
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
<!-- Change this out with your name and url ↓ -->
<p>Created by <a href="http://todomvc.com">you</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<!-- Scripts here. Don't remove ↓ -->
<!-- // <script src="node_modules/todomvc-common/base.js"></script> -->
<script src="node_modules/vue/dist/vue.js"></script>
<script src="js/app.js"></script>
</body>
</html>
app.js文件
;(function () {
var todos = [
{
id: 1,
ttle: '吃饭'
},
{
id: 2,
ttle: '睡觉'
},
{
id: 3,
ttle: '打豆豆'
}
]
// 自定义指令实现刷新自动聚焦
// 自定义聚焦指令不能放在bind钩子函数里,不会执行
Vue.directive('my-focus', {
// bind (el) {
// el.focus()
// },
inserted (el) {
el.focus()
}
})
// 自定义指令实现双机自动聚焦
Vue.directive('todo-focus', {
update (el) {
el.focus()
},
})
//var的形式在web端是不能访问的,需要挂载到window上
window.app = new Vue({
el: '#app',
data: {
todos: JSON.parse(window.localStorage.getItem('todos') || '[]'),
/*message: 'jj'*/
currentEditing: '',
todosText: ''
},
watch: {
//监视data里面某个数据的变化,只要一变化就执行,变化时做业务定制处理
//引用类型只能监视一层,无法监视内部成员的变化
todos: {
//当监视到todos改变的时候会自动调用handler方法
//监视的谁val就是谁
//oldVal是变化之后的值
handler (val, oldVal) {
window.localStorage.setItem('todos', JSON.stringify(val))
},
//深度监视,只有这样才能监视到对象里面属性的变化
deep: true,
//无论变化与否,上来就执行一次
immediate: true
}
},
methods: {
add: function (e) {
//不用双向绑定,这个回车事件是由input表单绑定的,事件对象指向表单
//事件对象指向绑定这个事件的对象
//e.target.value指向表单输入的内容
console.log(e.target.value)
// 0、注册按下回车事件
// 1、获取文本框内容
var value = e.target.value.trim()
// 2、数据校验
if (!value) {
return false
}
// 3、添加到todos里面
var member = {
id: this.todos.length ? this.todos[this.todos.length - 1].id + 1 : 1,
title: value,
completed: true
}
this.todos.push(member)
e.target.value = ''
},
handleToggleAllChange: function (e) {
var change = e.target.checked
this.todos.forEach(function (item, i) {
item.completed = change
})
},
remove: function (id) {
this.todos.splice(id, 1)
},
dblclick: function (item) {
this.currentEditing = item
},
keyupSave: function (item, index, e) {
var value = e.target.value.trim()
if (!value.length) {
//当文本框中的内容为空,敲回车时删除这个文本框
this.todos.splice(index, 1)
} else {
// 当文本框不为空按enter键时,保存修改的值,并且清除这个文本框
item.title = value
this.currentEditing = null
}
},
escDontSave: function (item) {
console.log('111')
this.currentEditing = null
},
clearCompleted: function () {
// for循环实现
// for(var i = 0; i < this.todos.length; i++) {
// if (this.todos[i].completed) {
// console.log(1)
// this.todos.splice(i, 1)
// //前面的被删了,后面的所有元素索引要减1,因为前面的被删了,后面的索引都变了
// i--
// }
// }
// 错误方法,不能再foreach里面删除数组元素,因为删除一个后面的索引变了
// this.todos.forEach(function (item, i) {
// if (item.completed) {
// todos.splice(i, 1)
// }
// })
// 简单粗暴的方法,数筛选,给todos重新赋值,把符合条件的放进去
this.todos = this.todos.filter(item => !item.completed)
},
// 通过hash的值来改变要渲染的内容
filterTodos: function () {
switch(this.todosText) {
case 'active' :
return this.todos.filter(t => !t.completed)
break;
case 'completed' :
return this.todos.filter(t => t.completed)
break;
default:
return this.todos
break
}
}
},
//computed为计算行为的属性,这里面的方法不管调用几次,都只会执行一次
//因为执行一次过后结果被存储起来了
//本质上是方法,但是只能当属性来调用,就像data里面参数调用的方法一样
computed: {
//一个函数作为get方法,被调用时默认执行get方法
//简写方式
// count () {
// return this.todos.filter(item => !item.completed).length
// }
// 两个方法的方式
//app.count 执行get方法
//app.count = 124 执行set方法,但用get方法访问时,它的值没变
count: {
get () {
return this.todos.filter(item => !item.completed).length
},
set () {
console.log('set方法被调了!')
}
},
// toggleAll: {
// get () {
// return todos.every(t => t.completed)
// }
// }
// 在computed里面实现全部选项的选中和不选中
toggleAll: {
//计算属性知道它依赖了todos,当todos发生变化时,计算属性会自动重新计算
get () {
return todos.every(t => t.completed)
},
// 在set里面访问this.toggleAll会调用这个方法的get方法
set () {
var checked = !this.toggleAll
// 有一个没选中,点击时就让它全中,如果已经全中了,点击就让它全不中
this.todos.forEach(item => {
item.completed = checked
}
)
}
}
}
})
window.onhashchange = function () {
app.todosText = window.location.hash.substr(2)
}
onhashchange()
})()