This time I will bring you a detailed explanation of the use of Vue's todoMVC. What are the precautions for using Vue's todoMVC? The following is a practical case, let's take a look.
This example is written in my own way by imitating the style and function of the official website example. Basically, I did not look at the source code of the official website, only referring to the custom instructions. Let’s explore it step by step. Official website demo
Function to be realized
Single add todo
Single delete todo
Double-click to edit todo
A single todo has been completed and the corresponding style status has changed
All todos have been completed Corresponding style status changes
Clear all completed todos
Display the number of todos to be done
Filter all todos, completed todos, unfinished todos
##Add a single todo
<input type="text" class="todos_add" placeholder="What needs to be done?" @keyup.enter="addTodo($event.target)" //绑定enter事件 ref="currentInput">//操作input元素使enter一下之后清空输入框内容
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格式存储数据 },
Single deletion of todo
<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>
deleteTodo(index) { //删除单条todo this.todoLists.splice(index, 1)//使用splice的api window.localStorage.setItem("content",JSON.stringify(todoLists)) //以JSON格式存储数据//localStorage存储数据 },
Double-click to edit todo&&single todo has been completed
<input type="checkbox" class="checkBox" v-model="list.isChecked">//双向绑定isChecked <p class="content_todoList_main" @dblclick="toEdit(list)" //双击事件 v-show="!list.isEditing" //切换元素 :class="{deleted:list.isChecked}"> //动态绑定class该表已完成todo样式 {{list.value}} </p> <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失去焦点事件
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() } } }
All todos have been completed
<span class="icon-down el-icon-arrow-down" //使用element库做向下箭头icon v-show="todoLists.length>0" //通过todoLists控制是否显示向下箭头icon @click="selectAllTodos"></span> //全部已完成事件
selectAllTodos() { //设置所有todo为已完成,使用map的api通过todo的isChecked属性操作 this.todoLists.map(todo => todo.isChecked = todo.isChecked ? false : true) }
The number of todos to do is displayed
<p class="data_times" v-show="times === 0"> //times为0显示item,大于0显示items,细节注定成败 <span>{{times}}</span>  item left </p> <p class="data_times" v-show="times > 0"> <span>{{times}}</span>  items left</p>
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 } },
Clear all completed todos
<p 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> </p> <p 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> </p>
clearTodos() { //清空已完成的todoLists,使用filter的api进行筛选 this.todoLists = this.todoLists.filter(todo => todo.isChecked === false) window.localStorage.setItem("content",JSON.stringify(this.todoLists)) //以json格式存储数据 },
Three status filtering
All todos, completed todos, unfinished todos filtering<li class="content_todoList" v-show="defaultShow || (whichShow?list.isChecked:!list.isChecked)"> <p 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> </p>
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 } },
ternary operator operator and the or operator on the li element to display todos in different states.
Complete code
<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>
<body> <p id="app"> <header class="header">todos</header> <p 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"> <p class="content_todoList_main" @dblclick="toEdit(list)" v-show="!list.isEditing" :class="{deleted:list.isChecked}"> {{list.value}} </p> <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> <p class="data" v-show="todoLists.length>0"> <p class="data_times" v-show="times === 0"> <span>{{times}}</span> item left </p> <p class="data_times" v-show="times > 0"> <span>{{times}}</span> items left </p> <p 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> </p> <p 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> </p> <p 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> </p> </p> </p> </p> </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>
Angular2 parent-child component communication method
Javascript code optimization detailed explanation
The above is the detailed content of Detailed explanation of the use of Vue's todoMVC. For more information, please follow other related articles on the PHP Chinese website!