Detailed interpretation of todoMVC code in Vue
This article mainly introduces the Vue official website todoMVC sample code. Now I will share it with you and give you a reference.
This example is written in my own way by imitating the official website sample style and function. Basically I didn’t look at the source code of the official website, I only referred 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
}
},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>How to implement multi-page development in vue2.0
How to implement drag verification using jQuery and vue Code function
Details introduction to several JavaScript coding specifications (detailed tutorial)
The above is the detailed content of Detailed interpretation of todoMVC code in Vue. For more information, please follow other related articles on the PHP Chinese website!
Hot AI Tools
Undresser.AI Undress
AI-powered app for creating realistic nude photos
AI Clothes Remover
Online AI tool for removing clothes from photos.
Undress AI Tool
Undress images for free
Clothoff.io
AI clothes remover
AI Hentai Generator
Generate AI Hentai for free.
Hot Article
Hot Tools
Notepad++7.3.1
Easy-to-use and free code editor
SublimeText3 Chinese version
Chinese version, very easy to use
Zend Studio 13.0.1
Powerful PHP integrated development environment
Dreamweaver CS6
Visual web development tools
SublimeText3 Mac version
God-level code editing software (SublimeText3)
Hot Topics
1378
52
How to add functions to buttons for vue
Apr 08, 2025 am 08:51 AM
You can add a function to the Vue button by binding the button in the HTML template to a method. Define the method and write function logic in the Vue instance.
How to reference js file with vue.js
Apr 07, 2025 pm 11:27 PM
There are three ways to refer to JS files in Vue.js: directly specify the path using the <script> tag;; dynamic import using the mounted() lifecycle hook; and importing through the Vuex state management library.
How to use watch in vue
Apr 07, 2025 pm 11:36 PM
The watch option in Vue.js allows developers to listen for changes in specific data. When the data changes, watch triggers a callback function to perform update views or other tasks. Its configuration options include immediate, which specifies whether to execute a callback immediately, and deep, which specifies whether to recursively listen to changes to objects or arrays.
How to use bootstrap in vue
Apr 07, 2025 pm 11:33 PM
Using Bootstrap in Vue.js is divided into five steps: Install Bootstrap. Import Bootstrap in main.js. Use the Bootstrap component directly in the template. Optional: Custom style. Optional: Use plug-ins.
How to return to previous page by vue
Apr 07, 2025 pm 11:30 PM
Vue.js has four methods to return to the previous page: $router.go(-1)$router.back() uses <router-link to="/" component window.history.back(), and the method selection depends on the scene.
Vue realizes marquee/text scrolling effect
Apr 07, 2025 pm 10:51 PM
Implement marquee/text scrolling effects in Vue, using CSS animations or third-party libraries. This article introduces how to use CSS animation: create scroll text and wrap text with <div>. Define CSS animations and set overflow: hidden, width, and animation. Define keyframes, set transform: translateX() at the beginning and end of the animation. Adjust animation properties such as duration, scroll speed, and direction.
How to query the version of vue
Apr 07, 2025 pm 11:24 PM
You can query the Vue version by using Vue Devtools to view the Vue tab in the browser's console. Use npm to run the "npm list -g vue" command. Find the Vue item in the "dependencies" object of the package.json file. For Vue CLI projects, run the "vue --version" command. Check the version information in the <script> tag in the HTML file that refers to the Vue file.
How to use function intercept vue
Apr 08, 2025 am 06:51 AM
Function interception in Vue is a technique used to limit the number of times a function is called within a specified time period and prevent performance problems. The implementation method is: import the lodash library: import { debounce } from 'lodash'; Use the debounce function to create an intercept function: const debouncedFunction = debounce(() => { / Logical / }, 500); Call the intercept function, and the control function is called at most once in 500 milliseconds.


