我是靠谱客的博主 标致海燕,这篇文章主要介绍Vue官网todoMVC示例代码,现在分享给大家,希望可以做个参考。

这个示例是模仿官网示例样式和功能用我自己的方式写的,基本上没有看官网的源码,只参考自定义指令。让我们一步步来探讨一下。官网demo

要实现的功能

  1. 单条添加todo
  2. 单条删除todo
  3. 双击编辑todo
  4. 单条todo已完成相应样式状态改变
  5. 全部todo是已完成相应样式状态改变
  6. 清除全部已完成todos
  7. 待办todos数量显示
  8. 所有todos,已完成todos,未完成todos筛选

单条添加todo

复制代码
1
2
3
<input type="text" class="todos_add" placeholder="What needs to be done?" @keyup.enter="addTodo($event.target)" //绑定enter事件 ref="currentInput">//操作input元素使enter一下之后清空输入框内容
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
data() {//一些初始化数据 return { todolists: [], dataStatus: ["All", "Active", "Completed"], dataStatusIndex: 0, whichShow: true, defaultShow: true } }, addTodo(e) { //添加todo var val = e.value if (val === "") {return} //如果输入内容为空则立即返回 this.todoLists = this.todoLists.concat({//使用concat这个api添加todo value: val, //输入内容 isEditing: false, //是否在编辑状态 isActive: false, //删除X图标是否激活 isChecked: false //是否已完成 }) this.$refs.currentInput.value = "" //按下enter添加todo之后把输入框value清零 window.localStorage.setItem("content",JSON.stringify(this.todoLists))//使用localStorage以JSON格式存储数据 },

把每条todo的对应状态都存在同一个对象当中,在操作改变todo状态的时候不会被统一处理,使得每条todo都有单独的状态。

单条删除todo

复制代码
1
2
3
4
5
6
7
8
9
<li class="content_todoList" v-for="(list,index) in todoLists" @mouseover="list.isActive = true" //鼠标移入todo改变对应todo的isActive状态 @mouseleave="list.isActive=false" //鼠标移出todo改变对应todo的isActive状态 <span class="el-icon-close content_todoList_delete" :class="{show: list.isActive}" //动态绑定class使鼠标移动到某一todo显示X图标 @click="deleteTodo(index)"> //绑定删除单条todo事件 </span> </li>
复制代码
1
2
3
4
deleteTodo(index) { //删除单条todo this.todoLists.splice(index, 1)//使用splice的api window.localStorage.setItem("content",JSON.stringify(todoLists)) //以JSON格式存储数据//localStorage存储数据 },

在每个li元素上绑定了鼠标移入和移除的事件来动态的改变每个todo的isActive,然后再使用isActive动态显示class。

双击编辑todo&&单条todo已完成

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<input type="checkbox" class="checkBox" v-model="list.isChecked">//双向绑定isChecked <div class="content_todoList_main" @dblclick="toEdit(list)" //双击事件 v-show="!list.isEditing" //切换元素 :class="{deleted:list.isChecked}"> //动态绑定class该表已完成todo样式 {{list.value}} </div> <input type="text" class="content_todoList_main main_input" v-model="list.value" //双向绑定可输入value v-show="list.isEditing" //切换元素 v-todo-focus="list.value" //自定义指令,双击之后自动focus对焦 @blur="unEdit(list)"> //绑定blur失去焦点事件
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
methods: { toEdit(obj) { //使添加的todothing可编辑 obj.isEditing = true }, unEdit(obj) { //使添加的todothing不可编辑 obj.isEditing = false }, } directives: { //自定义focus指令,需要一个binding参数做判断 "todo-focus": function (el, binding) { if (binding.value) { el.focus() } } }

通过每个todo里的isEditing属性控制show和是否可编辑两个状态,双击div之后改变当前todo的isEditing为true,从而显示为input,input失去焦点之后再通过blur事件改为false。

通过todo的idChecked来控制是否已完成,从而动态改变样式。

全部todos已完成

复制代码
1
2
3
4
<span class="icon-down el-icon-arrow-down" //使用element库做向下箭头icon v-show="todoLists.length>0" //通过todoLists控制是否显示向下箭头icon @click="selectAllTodos"></span> //全部已完成事件
复制代码
1
2
3
selectAllTodos() { //设置所有todo为已完成,使用map的api通过todo的isChecked属性操作 this.todoLists.map(todo => todo.isChecked = todo.isChecked ? false : true) }

待办todos数量显示

复制代码
1
2
3
4
5
<div class="data_times" v-show="times === 0"> //times为0显示item,大于0显示items,细节注定成败 <span>{{times}}</span>  item left </div> <div class="data_times" v-show="times > 0"> <span>{{times}}</span>  items left</div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
computed: { times() { //使用计算属性计算待办todos的次数 let todoArr = this.todoLists let times = 0 for (let i = 0; i < todoArr.length; i++) { if (todoArr[i].isChecked === false) { times++ } } return times } },

使用了计算属性对todoLists计算,用for循环刷选出idChecked为true的累加,最后返回times。

清除全部已完成todos

复制代码
1
2
3
4
5
6
7
8
9
10
11
<div class="data_clearTodos" @click="clearTodos" v-show="times < todoLists.length"> //如果待办事件次数小于总todoLists长度就显示“clear completed” <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >clear completed</a> </div> <div class="data_clearTodos" @click="clearTodos" v-show="times === todoLists.length"> //如果待办事件次数等于总todoLists长度就显示“clear completed” <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ></a> </div>
复制代码
1
2
3
4
clearTodos() { //清空已完成的todoLists,使用filter的api进行筛选 this.todoLists = this.todoLists.filter(todo => todo.isChecked === false) window.localStorage.setItem("content",JSON.stringify(this.todoLists)) //以json格式存储数据 },

如果待办todos的times小于todoLists长度,就证明有已完成的todo,就可以显示“clear completed”,如果相等就说明没有已完成的todo。

三种状态筛选

所有todos,已完成todos,未完成todos筛选

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
<li class="content_todoList" v-show="defaultShow || (whichShow?list.isChecked:!list.isChecked)"> <div class="data_status"> <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" :class="{active: index === dataStatusIndex}" //动态class实现tab切换 v-for="(item ,index) in dataStatus" v-for循环 @click="switchStatus(index)" //切换不同tab显示内容 :key="index"> {{item}} </a> </div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
switchStatus(index) { //通过if条件判断操作 this.dataStatusIndex = index if (this.dataStatus[index] === "Active") { this.defaultShow = false this.whichShow = false } else if (this.dataStatus[index] === "Completed") { this.defaultShow = false this.whichShow = true } else if (this.dataStatus[index] === "All") { this.defaultShow = true } },

我这里是同时if条件句判断操作,有点麻烦,目前还没有想出来其他方案。在li元素使用三元运算符和或运算符进行操作显示不同状态的todos。

完整代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<style> * { padding: 0; margin: 0; box-sizing: border-box; } input { outline: none; } ul, li, ol { list-style: none; } #app { width: 800px; height: 900px; margin: 0 auto; text-align: center; background-color: rgb(245, 245, 245); padding: 24px 0; } #app .header { font-size: 48px; } .content { width: 72%; margin: 0 auto; box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.25); position: relative; } .icon-down { position: absolute; font-size: 24px; top: 16px; left: 16px; cursor: pointer; } #app .content .todos_add { width: 100%; height: 56px; padding: 16px 56px; font-size: 24px; border: 1px solid transparent; } .content_todoLists { position: relative; z-index: 3; } .content_todoList { display: flex; flex-direction: row; border-top: 1px solid #ccc; font-size: 24px; padding: 8px; background-color: white; align-items: center; } .checkBox { width: 20px; height: 20px; margin-left: 10px; } .content_todoList_main { flex: 1; text-align: left; margin-left: 16px; font-size: 20px; padding: 6px 0; } .main_input { position: relative; z-index: 1; } .content_todoList_delete { position: absolute; right: 16px; color: rgb(252, 55, 55); font-weight: 500; display: none; cursor: pointer; } .show { display: block; } .deleted { text-decoration-line: line-through; color: #bbb; } .show:hover { color: rgb(255, 0, 0); font-weight: 700; } ::-moz-placeholder { color: rgb(221, 218, 218); } ::-webkit-input-placeholder { color: rgb(221, 218, 218); } :-ms-input-placeholder { color: rgb(221, 218, 218); } .data { display: flex; justify-content: space-between; padding: 8px; font-size: 14px; font-weight: 300; color: rgb(145, 145, 145); } a { text-decoration: none; color: rgb(145, 145, 145); } .data_times { width: 73px; } .data_clearTodos { width: 142px; } .data_status a { display: inline-block; border: 1px solid transparent; border-radius: 2px; padding: 1px 4px; margin: 0 2px; } .data_status a:hover { border-color: #bbb; } .data_clearTodos a:hover { text-decoration-line: underline; } .active { box-shadow: 0 0 1px black; } </style>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<body> <div id="app"> <header class="header">todos</header> <div class="content"> <span class="icon-down el-icon-arrow-down" v-show="todoLists.length>0" @click="selectAllTodos"> </span> <input type="text" class="todos_add" placeholder="What needs to be done?" @keyup.enter="addTodo($event.target)" ref="currentInput"> <ul class="content_todoLists"> <li v-for="(list,index) in todoLists" class="content_todoList" @mouseover="list.isActive = true" @mouseleave="list.isActive=false" v-show="defaultShow || (whichShow?list.isChecked:!list.isChecked)"> <input type="checkbox" class="checkBox" v-model="list.isChecked"> <div class="content_todoList_main" @dblclick="toEdit(list)" v-show="!list.isEditing" :class="{deleted:list.isChecked}"> {{list.value}} </div> <input type="text" class="content_todoList_main main_input" v-model="list.value" v-show="list.isEditing" v-todo-focus="list.value" @blur="unEdit(list)"> <span class="el-icon-close content_todoList_delete" :class="{show: list.isActive}" @click="deleteTodo(index)"></span> </li> </ul> <div class="data" v-show="todoLists.length>0"> <div class="data_times" v-show="times === 0"> <span>{{times}}</span> item left </div> <div class="data_times" v-show="times > 0"> <span>{{times}}</span> items left </div> <div class="data_status"> <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" :class="{active:index === dataStatusIndex}" v-for="(item,index) in dataStatus" @click="switchStatus(index)" :key="index"> {{item}} </a> </div> <div class="data_clearTodos" @click="clearTodos" v-show="times < todoLists.length"> <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >clear completed</a> </div> <div class="data_clearTodos" @click="clearTodos" v-show="times === todoLists.length"> <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ></a> </div> </div> </div> </div> </body> <script> let vm = new Vue({ el: "#app", data() { return { todoLists: [], dataStatus: ["All", "Active", "Completed"], dataStatusIndex: 0, whichShow: true, defaultShow: true } }, computed: { times() { //使用计算属性计算待办todos的次数 let todoArr = this.todoLists let times = 0 for (let i = 0; i < todoArr.length; i++) { if (todoArr[i].isChecked === false) { times++ } } return times } }, methods: { toEdit(obj) { //使添加的todo可编辑 obj.isEditing = true }, unEdit(obj) { //使添加的todo不可编辑 obj.isEditing = false }, addTodo(e) { //添加todo var val = e.value if (val === "") { return } //如果输入内容为空则立即返回 this.todoLists = this.todoLists.concat({ //使用concat这个api添加todo value: val, //输入内容 isEditing: false, //是否在编辑状态 isActive: false, //删除X图标是否激活 isChecked: false //是否已完成 }) this.$refs.currentInput.value = "" //按下enter添加todo之后把输入框value清零 window.localStorage.setItem("content", JSON.stringify(this.todoLists)) //使用localStorage以JSON格式存储数据 }, deleteTodo(index) { //删除todo this.todoLists.splice(index, 1) window.localStorage.setItem("content", JSON.stringify(this.todoLists)) //以json格式存储数据 }, switchStatus(index) { //试下下方三个状态切换,略麻烦 this.dataStatusIndex = index if (this.dataStatus[index] === "Active") { this.defaultShow = false this.whichShow = false } else if (this.dataStatus[index] === "Completed") { this.defaultShow = false this.whichShow = true } else if (this.dataStatus[index] === "All") { this.defaultShow = true } }, clearTodos() { //清空已完成的todoLists this.todoLists = this.todoLists.filter(todo => todo.isChecked === false) window.localStorage.setItem("content", JSON.stringify(this.todoLists)) //以json格式存储数据 }, selectAllTodos() { //设置所有todo为已完成 this.todoLists.map(todo => todo.isChecked = todo.isChecked ? false : true) } }, directives: { //自定义focus指令 "todo-focus": function (el, binding) { if (binding.value) { el.focus() } } }, created() { let myStorage = window.localStorage.getItem('content') this.todoLists = JSON.parse(myStorage) || [] //因为todoLists初始值是null,使用或运算符,如果为null设为空数组 } }) </script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

最后

以上就是标致海燕最近收集整理的关于Vue官网todoMVC示例代码的全部内容,更多相关Vue官网todoMVC示例代码内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(1341)

评论列表共有 0 条评论

立即
投稿
返回
顶部