首页 > 编程 > JavaScript > 正文

Vue官网todoMVC示例代码

2019-11-19 14:27:47
字体:
来源:转载
供稿:网友

这个示例是模仿官网示例样式和功能用我自己的方式写的,基本上没有看官网的源码,只参考自定义指令。让我们一步步来探讨一下。官网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) { //添加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

 <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存储数据},

在每个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" //双向绑定可输入valuev-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已完成

<span class="icon-down el-icon-arrow-down" //使用element库做向下箭头iconv-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)}

待办todos数量显示

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

<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>
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="#" 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>
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。

完整代码

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表