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

要实现的功能

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

单条添加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) { //添加todovar val = e.valueif (val === "") {return} //如果输入内容为空则立即返回this.todoLists = this.todoLists.concat({//使用concat这个api添加todovalue: 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

<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) { //删除单条todothis.todoLists.splice(index, 1)//使用splice的apiwindow.localStorage.setItem("content",JSON.stringify(todoLists)) //以JSON格式存储数据//localStorage存储数据
},

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

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

```<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失去焦点事件


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已完成

class="icon-down el-icon-arrow-down" //使用element库做向下箭头icon
v-show="todoLists.length&gt;0" //通过todoLists控制是否显示向下箭头icon
@click="selectAllTodos"&gt;&lt;/span&gt; //全部已完成事件

selectAllTodos() { //设置所有todo为已完成,使用map的api通过todo的isChecked属性操作this.todoLists.map(todo =&gt; todo.isChecked = todo.isChecked ? false : true)
}

待办todos数量显示

&lt;div class="data_times" v-show="times === 0"&gt; //times为0显示item,大于0显示items,细节注定成败 &lt;span&gt;{{times}}&lt;/span&gt;&amp;nbsp item left &lt;/div&gt; &lt;div class="data_times" v-show="times &gt; 0"&gt; &lt;span&gt;{{times}}&lt;/span&gt;&amp;nbsp items left&lt;/div&gt;


computed: {times() { //使用计算属性计算待办todos的次数 let todoArr = this.todoListslet times = 0for (let i = 0; i &lt; todoArr.length; i++) {if (todoArr[i].isChecked === false) {times++}}return times}
},

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

清除全部已完成todos

```<div class="data_clearTodos"
@click="clearTodos"
v-show="times < todoLists.length"> //如果待办事件次数小于总todoLists长度就显示“clear completed”
<a href="#">clear completed</a>
</div>

<div class="data_clearTodos"
@click="clearTodos"
v-show="times === todoLists.length"> //如果待办事件次数等于总todoLists长度就显示“clear completed”
<a href="#"></a>
</div>


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筛选

```<li class="content_todoList"
v-show="defaultShow || (whichShow?list.isChecked:!list.isChecked)">

<div class="data_status">
<a href="#"
:class="{active: index === dataStatusIndex}" //动态class实现tab切换
v-for="(item ,index) in dataStatus" v-for循环
@click="switchStatus(index)" //切换不同tab显示内容
:key="index">
{{item}}
</a>
</div>


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
}
},


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

<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>
```

    &lt;div id="app"&gt;&lt;header class="header"&gt;todos&lt;/header&gt;&lt;div class="content"&gt;&lt;span class="icon-down el-icon-arrow-down" v-show="todoLists.length&gt;0" @click="selectAllTodos"&gt;&lt;/span&gt;&lt;input type="text" class="todos_add" placeholder="What needs to be done?" @keyup.enter="addTodo($event.target)" ref="currentInput"&gt;&lt;ul class="content_todoLists"&gt;&lt;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)"&gt;&lt;input type="checkbox" class="checkBox" v-model="list.isChecked"&gt;&lt;div class="content_todoList_main" @dblclick="toEdit(list)" v-show="!list.isEditing" :class="{deleted:list.isChecked}"&gt;{{list.value}}&lt;/div&gt;&lt;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)"&gt;&lt;span class="el-icon-close content_todoList_delete" :class="{show: list.isActive}" @click="deleteTodo(index)"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="data" v-show="todoLists.length&gt;0"&gt;&lt;div class="data_times" v-show="times === 0"&gt;&lt;span&gt;{{times}}&lt;/span&gt;&amp;nbspitem left&lt;/div&gt;&lt;div class="data_times" v-show="times &gt; 0"&gt;&lt;span&gt;{{times}}&lt;/span&gt;&amp;nbspitems left&lt;/div&gt;&lt;div class="data_status"&gt;&lt;a href="#" :class="{active:index === dataStatusIndex}" v-for="(item,index) in dataStatus" @click="switchStatus(index)" :key="index"&gt;{{item}}&lt;/a&gt;&lt;/div&gt;&lt;div class="data_clearTodos" @click="clearTodos" v-show="times &lt; todoLists.length"&gt;&lt;a href="#"&gt;clear completed&lt;/a&gt;&lt;/div&gt;&lt;div class="data_clearTodos" @click="clearTodos" v-show="times === todoLists.length"&gt;&lt;a href="#"&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/body&gt;

&lt;script&gt;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.todoListslet times = 0for (let i = 0; i &lt; 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) { //添加todovar val = e.valueif (val === "") {return} //如果输入内容为空则立即返回this.todoLists = this.todoLists.concat({ //使用concat这个api添加todovalue: 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) { //删除todothis.todoLists.splice(index, 1)window.localStorage.setItem("content", JSON.stringify(this.todoLists)) //以json格式存储数据},switchStatus(index) { //试下下方三个状态切换,略麻烦this.dataStatusIndex = indexif (this.dataStatus[index] === "Active") {this.defaultShow = falsethis.whichShow = false} else if (this.dataStatus[index] === "Completed") {this.defaultShow = falsethis.whichShow = true} else if (this.dataStatus[index] === "All") {this.defaultShow = true}},clearTodos() { //清空已完成的todoListsthis.todoLists = this.todoLists.filter(todo =&gt; todo.isChecked === false)window.localStorage.setItem("content", JSON.stringify(this.todoLists)) //以json格式存储数据},selectAllTodos() { //设置所有todo为已完成this.todoLists.map(todo =&gt; 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设为空数组}})
&lt;/script&gt;

原文地址:https://segmentfault.com/a/1190000013026721

转载于:https://www.cnblogs.com/lalalagq/p/9951729.html

Vue官网todoMVC示例相关推荐

  1. Vue官网提供表单验证cnpm i vee-validate@2 --save

    Vue官网提供表单验证 使用步骤: 1:安装vee-valadite,别安装最新版本@2 2:在plugins文件夹中创建一个validate.js[专门注册vee-valadite] 3:注册插件 ...

  2. 重磅:Vue 官网竟然有免费的中文视频教程了

    loonggg 读完需要 2 分钟 速读仅需1分钟 关注我很久的读者应该都知道,这两年我一直在创业,当然了,作为程序员创业来讲,其实有时候真的不得不自己去干很多活.虽然我是移动端开发出身,但是这两年其 ...

  3. Arduinojson官网序列化示例教程

    Arduinojson官网序列化示例教程 Arduinojson官方示例程序: #include <ArduinoJson.h>void setup() {// Initialize Se ...

  4. Arduinojson官网反序列化示例教程

    Arduinojson官网反序列化示例教程 官方反序列化示例程序: 程序源码: #include <ArduinoJson.h>void setup() {// Initialize se ...

  5. Vue 官网学习笔记

    VUE介绍 vue git 地址:https://github.com/vuejs/vue/projects Vue 官网教程地址:https://cn.vuejs.org/v2/guide/inst ...

  6. Vue官网所说的低侵入式含义

    人生天地之间,若白驹之过隙,忽然而已 提出问题 在观看vue官网当中,在深入响应式系统出现一段话: Vue 最标志性的功能就是其低侵入性的响应式系统.组件状态都是由响应式的 JavaScript 对象 ...

  7. Angular官网教程示例知识点总结

    Angular官网教程示例知识点总结 1.背景 2.知识点 2.1 应用的外壳 2.1.1 使用 Angular CLI 创建初始的应用结构 2.1.2 启动应用服务器 2.1.3 双花括号表达式 2 ...

  8. Vue官网学习(模板语法:一、{{}}双大括号语法)

    Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据.所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析 ...

  9. 003-读书笔记-Vue官网 计算属性与监听器

    1.计算属性 1-1 计算属性概述 计算属性也是 Vue 实例的属性,和 data 方法中返回的对象中的属性是等同的存在.通常来说,计算属性可以简单理解: 计算属性其实就是 Vue 实例的一个属性 计 ...

最新文章

  1. 想要高效在线办公,建议你“百度如流”一下:项目管理、协作文档都来了,还有AI翻译和速记等黑科技...
  2. 无法加载Dll”ArcGISVersion.dll”:0x8007007E
  3. Scapy学习笔记二
  4. CEO 赠书 | 决策是一个技术活,如何做「对」的事?
  5. python 可视化项目_python3项目之数据可视化
  6. 互斥与同步——local_irq_enable与local_irq_disable
  7. TypeScript 3.7 发布,带来 Optional Chaining 等特性
  8. Shiro 支持三种方式的授权
  9. gitlab创建分支上传文件_环境搭建:gitLab平台的搭建和简单使用
  10. ImageView显示灰色图片
  11. jquery衬衣产品内容详情页
  12. 选股策略你都会吗,这些选股策略你看懂了吗?
  13. 快讯:预装Ubuntu 11.10小电脑南非开卖
  14. Kubernetes部署(七):k8s项目交付----(4)日志收集
  15. Windows10计算机无法启动,Win10电脑无法开机提示Windows boot manager
  16. 2022年全球市场智能室内空气质量检测仪总体规模、主要生产商、主要地区、产品和应用细分研究报告
  17. 老农移石故事的启示分享
  18. org.quartz
  19. 瑞萨RH850 CS+环境下设置堆和栈空间
  20. 怎么样用计算机解锁密码忘了,电脑开机密码忘记了怎么办,详细教您如何解决忘记电脑开机密码...

热门文章

  1. 百度地图相关问题总结
  2. Android App Build Workflow
  3. Android Telephony分析(四) ---- TelephonyManager详解
  4. Android平台类加载流程源码分析
  5. JZOJ 5701. 【gdoi2018 day2】第一题 谈笑风生(magic)
  6. JZOJ 3596. 【CQOI2014】和谐矩阵
  7. JZOJ 3875. 【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)
  8. python边缘检测代码_Python中的边缘检测
  9. Android宫格动态列,Android实现宫格图片连续滑动效果
  10. 鸿蒙手机系统开发大会,鸿蒙OS+EMUI10,华为开发者大会的创新与看点