原教程:https://juejin.im/post/5c3e9f946fb9a049f06a85ff#comment
按照dalao教的方法一步一步写的一个简单的vue实例,算是帮自己熟悉一下vue的基本指令和操作吧。
因为是个简单的例子,所有代码就直接写在了一个html文件里,也没加样式。
全部代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Todo</title>
<style>
.completed {
text-decoration: line-through;
}
.selected {
color: red;
}
.hide{
color: red;
display: inline;
}
.empty{
border-color: red;
}
p{
display: none;
}
#todo-app{
border: gray 2px solid;
padding: 50px;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
}
</style>
</head>
<body>
<div id="todo-app">
<div>
<input type="button"
@click="allCompleted"
v-if="leftTodosCount!==0"
value="全部标为完成"/>
<input type="text"
v-bind:class='{empty:!ifempty}'
v-model="newTodoTitle"
@keyup.enter="addTodo"
placeholder="添加 todo"/>
<p v-bind:class='{hide:!ifempty}'>请输入内容</p>
</div>
<!-- todo list -->
<ul>
<li v-for='todo in filteredTodos' :key='todo.id'>
<span
@dblclick="editeTodo(todo)"
:class="{completed: todo.completed}">{{ todo.title }}</span>
<input
@click="markAsCompleted(todo)"
v-if="!todo.completed"
type="button" value="标为完成">
<input
@click="markAsUncompleted(todo)"
v-if="todo.completed"
type="button" value="标为未完成">
<input type="button"
@click="deleteTodo(todo)"
value="删除">
<input type="text"
v-if="editedTodo!==null && editedTodo.id===todo.id"
v-model="todo.title"
@keyup.enter="editDone(todo)"
@keyup.esc="cancelEdit(todo)"
v-focus="true"
value="编辑 todo..."/>
<span v-if="editedTodo!==null && editedTodo.id===todo.id" style="color: gray">回车键保存,esc键取消更改</span>
</li>
</ul>
<!-- end todo list -->
<div>
<span>剩余 {{leftTodosCount}} 项未完成 ---</span>
<span>筛选:
<input type="button"
@click="intention='all'"
:class="{selected:intention==='all'}"
value="全部">
<input type="button"
@click="intention='ongoing'"
:class="{selected:intention==='ongoing'}"
value="进行中">
<input type="button"
@click="intention='finished'"
:class="{selected:intention==='finished'}"
value="已完成">
<input type="button"
@click="deleteCompletedTodos"
v-if="finishedTodosCount!==0"
value="清除已完成">
<input type="button"
@click="deleteAllTodos"
value="清除全部">
<input type="button"
@click="undo"
v-if="deletedTodos.length!==0"
value="撤销删除">
</span>
</div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
<script>
var STORAGE_KEY = 'vue2.x-todo';
//本地储存组件
var todoStorage ={
fetch:function () {
var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
todos.forEach(function (todo,index) {
todo.id = index;
});
todoStorage.uid = todos.length;
return todos;
},
save:function (todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
}
};
let id=0;
var app = new Vue({
el: '#todo-app',
data: function () {
return {
todos: todoStorage.fetch(),
deletedTodos: [],
newTodoTitle:'',
checkEmpty:false,//是否检测输入栏为空
editedTodo:null,//暂存编辑前的todo
intention:'all',//当前查看的状态,默认为全显示
}
},
//======================================================================================================
//侦听属性
watch:{
todos:{
handler: function (todos) {
todoStorage.save(todos)
},
deep:true
}
},
//======================================================================================================
//基本方法
methods: {
addTodo: function () {
if (!this.newTodoTitle == '') {
this.todos.push({id: todoStorage.uid++, title: this.newTodoTitle, completed: false});
this.newTodoTitle = '';
this.checkEmpty = false;
}
else {
this.checkEmpty = true;
}
},
deleteTodo: function (todo) {
if (todo.title === '') {
this.deletedTodos.push({todo: this.editedTodo, pos: todo.id});
}
else {
this.deletedTodos.push({todo: todo, pos: todo.id});
}
this.todos.splice(this.todos.indexOf(todo), 1);
},
editeTodo: function (todo) {
this.editedTodo = {id: todo.id, title: todo.title, completed: todo.completed}
},
markAsCompleted: function (todo) {
todo.completed = true;
},
markAsUncompleted: function (todo) {
todo.completed = false;
},
undo: function () {
if (!this.deletedTodos.length == 0) {
let a = this.deletedTodos.pop();
this.todos.splice(a.pos, 0, a.todo)
}
},
editDone: function (todo) {
if (todo.title === '') {
this.deleteTodo(todo);
}
this.editedTodo = null;
},
cancelEdit: function (todo) {
todo.title = this.editedTodo.title;
this.editedTodo == null;
},
allCompleted:function () {
this.todos.map(
todo => todo.completed = true
)
},
deleteAllTodos:function () {
if(confirm("此操作不可恢复,确定要全部清除吗?")){
this.todos=[];
}
},
deleteCompletedTodos:function () {
if(confirm("此操作不可恢复,确定要清除全部完成项目吗?")){
this.todos=this.todos.filter(todo=>!todo.completed)
}
}
},
//===========================================================================================
//钩子函数,自动聚焦编辑栏
directives:{
focus:{
inserted:function (el) {
el.focus()
}
}
},
//======================================================================================================
//计算属性
computed:{
ifempty:function () {
if(this.checkEmpty) {
return this.newTodoTitle.length;
}
return 1;
},
leftTodos:function(){
return this.todos.filter(todo=> !todo.completed)
},
leftTodosCount:function () {
return this.leftTodos.length
},
finishedTodos:function(){
return this.todos.filter(todo=>todo.completed)
},
finishedTodosCount:function(){
return this.finishedTodos.length
},
filteredTodos:function () {
if(this.intention==='ongoing'){
return this.leftTodos
}
else if(this.intention==='finished'){
return this.finishedTodos
}else{
return this.todos
}
}
}
})
</script>
</body>
</html>