vue学习笔记のtodolist的实现
通过三方力量,对vue有了初步的了解,通过数据直接影响视图。通过vue实现todolist任务来巩固相关知识点。Todolist需要实现的主要功能有:任务的添加,回车添加(v-model、v-on)、删除(v-on)、选定重编辑(@dblclick)及取消重编辑(按esc)、对已完成任务、未完成任务及所有任务的列表切换显示(computed、v-show、v-if、v-bind、v-for、active)、存取数据(localStorage、watch)。
添加任务:
在<input>输入框中输入内容,按回车,则下面的任务列表中会出现刚刚添加的内容。该功能利用函数在methods中实现,调用push()方法(与数组中push()方法不太一样)。在methods中定义一个addTodo()方法实现,并在<input>标签中通过v-on指令绑定该函数。即当我们向<input>输入内容后按回车键触发该函数,前面的勾选框默认false不选中,此时会向列表项中插入一条任务,即一个对象,然后把输入框清空。title值通过v-model实现双向数据绑定。
删除任务:
直接点击任务列表后面的叉即可删除任务。根据任务内容找到list对象中的下标,然后通过splice()方法(与数组中对应方法不太一样)将其删除。
双击修改任务:
双击任务内容,可以改变任务内容,即title的值,将当前编辑的值赋值给title,然后在<label>标签中通过@dblclick绑定该修改函数edtorTodo(),同时在类名todo的<li>标签上,动态绑定一个class为editing,并为其指定修改之后的值edtorTodos,通过这个class来改变任务列表及相对应修改title的输入框的隐藏与显示,通过v-model检测title的改变并进行绑定。
输入框内取消修改:
在输入框内输入修改内容后,若不想修改了,则可按esc返回到之前的内容状态。这里在methods里定义了一个取消修改的函数cancelTodo(),定义一个beforeTitle保存之前的内容,然后将beforeTitle值赋给当前title。同时,通过@keyup.esc绑定cancelTodo()函数。
所有任务、未完成任务、完成任务的切换及计算:
通过计算属性computed根据isChecked值动态计算出对应list中任务个数。通过filter过滤、watch及hash值实现对应项的切换功能。
(1-我们可以给window对象通过addEventListener绑定一个 hashchange事件,回调函数就是获得这个hash值,然后把这个hash值赋给Vue实例中的visibility属性,这个visibility默认是全部显示的。2-通过一个计算属性filteredList来根据visibility的值动态返回不同的状态的list,然后html中v-for指令就不是直接渲染list了,而是通过这个filteredList筛选出来的list,如果在输错hash值的情况下,我们可以判断hash不存在的情况下,全都返回hash值为all的结果,这样就达到了我们想要的效果了。
)
实现刷新页面时列表项内容依然存在,即列表项内容的存储:
这里用localStorage,利用其save()与fetch()实现数据的存取,即通过localStorage.setItem()实现存储,localStorage.getItem()实现读取。将获取的本粗存储的值赋给list,即可实现列表项内容不丢失。通过watch的深监控来监控list内数据的值并作出相应处理。
实现该任务用到的知识点有:
- 将vue.js框架通过<script>标签引入
- v-for指令:根据一组数组的选项列表进行渲染
语法:
value,key in items
value,key of items
- 变异方法:
vue提供一组方法,对数组进行操作时候,会触发视图更新
push() pop() shift() unshift() splice() sort() reverse()
- 事件处理器
v-on指令:用来监听dom事件触发代码
语法:v-on:eventName=”eventHandle”
指令简写: @
事件处理函数:写在methods中统一管理
事件对象:在事件处理函数中获取;内联事件处理函数执行,传入事件对象。$event
- 事件修饰符:
事件处理函数只有纯粹的逻辑判断,不处理dom事件的细节,如阻止冒泡、取消默认行为、判断按键
修饰符的位置:v-on:eventName.修饰符
修饰符:.stop .prevent .capture .self .once
按键修饰符:
.enter .tab .delete .esc .space .up .down .left .right .ctrl .alt .shift .meta .键值
执行事件处理函数时可以进行传参
<input placeholder="勇敢自信youcan; 提示:+回车即可添加任务" class="task-input" type="text" v-model="todo" v-on:keyup.enter="addTodo(123,$event)" /> new Vue({ el:".main", data:{ list:list, todo:"" }, methods:{ //统一管理事件处理函数 addTodo:function(data,ev){ /*//添加任务//向list中添加一项任务//事件处理函数中的this指向的是当前这个根实例*/ this.list.push({ /*title:ev.target.value*/ title:this.todo //替换上面的语句,减少dom操作 }); this.todo=" "; //数据更新视图 } } });
- 条件渲染:
v-show指令:根据表达式的值,决定显示或隐藏元素。
语法:v-show=”表达式”
元素会被渲染在页面中只根据表达式的值进行css切换
- 动态绑定class:
class也为元素的属性,可以使用v-bind:class
语法:
:class=”{className:表达式}” // 表达式值为true,添加className,否则不添加
:class=”[className,className]”
v-bind指令:为元素动态绑定class,不同的条件下绑定不同的class,从而实现不同的样式显示。
- 自定义指令:
除了vue内置的指令,可以自己设置指令
选项对象的directives属性{
directives:{}
}
钩子函数:
update被绑定元素所在的模板更新时调用
钩子函数中参数:
el:指令所绑定的元素,可以用来直接操作dom
binding:一个对象
value:指定的绑定值
- 计算属性
模板是为了描述视图的结构,模板中放入太多逻辑,导致模板太重,难以维护。
在计算一个属性时,vue.js更新它的依赖列表并缓存结果,只有当其中一个依赖发生了变化,缓存的结果才有效。通过计算属性可以实现对数据的过滤筛选。
语法:
在选项对象中
{
…
computed:{}
}
- v-model指令:实现对数据的双向绑定
- 存取localStorage中的数据
- 通过监控hash值变化来决定显示哪一部分
- watch的深监控与浅监控
var list=[ { title:"勇敢勇敢再勇敢", isChecked:false //false表示未选中,任务未完成 }, { title:"坚强自信youcan", isChecked:true //true,选中,任务完成 } ] watch:{ //监控功能 /* list:function(){ //监控list这个属性,当值发生变化时就会执行后面的函数 store.save("miaov-new-class",this.list); }//浅监控*/ list:{ handler:function(){ store.save("miaov-new-class",this.list); }, deep:true //深监控 } }
html核心代码:
<body> <div class="page-top"> <div class="page-content"> <h2>任务计划列表</h2> </div> </div> <div class="main"> <h3 class="big-title">添加任务</h3> <input placeholder="勇敢自信youcan; 提示:+回车即可添加任务" class="task-input" type="text" v-model="todo" v-on:keyup.enter="addTodo" /> <ul class="task-count" v-show="list.length"> <li>{{ noCheckeLength }}个任务未完成</li><!--渲染数据--> <li class="action"> <a :class="{active:visibility==='all'}" href="#all">所有任务</a> <a href="#unfinished" :class="{active:visibility==='unfinished'}">未完成的任务</a> <a href="#finished" :class="{active:visibility==='finished'}">完成的任务</a> </li> </ul> <h3 class="big-title">任务列表</h3> <div class="tasks"> <span class="no-task-tip" v-show="!list.length">还没有添加任何任务</span> <ul class="todo-list"> <li class="todo " :class="{completed:item.isChecked,editing:item===edtorTodos}" v-for="item in filteredList"> <div class="view"> <input class="toggle" type="checkbox" v-model="item.isChecked" /> <label @dblclick="edtorTodo(item)">{{item.title}}</label> <button class="destroy" @click="deleteTodo(item)"></button> </div> <input v-focus="edtorTodos===item" class="edit" type="text" v-model="item.title" @blur="edtorTodoed(item)" @keyup.enter="edtorTodoed(item)" @keyup.esc="cancelTodo(item)" /> </li> </ul> </div> </div>
js核心代码:
var store={ //封装一个对象//存取localStorage中的数据 save(key,value){ //es6函数写法 localStorage.setItem(key,JSON.stringify(value)); //将数据转换为json形式的字符串 }, fetch(key){ return JSON.parse(localStorage.getItem(key))||[]; //获得的数据是json字符串,需要用json.parse解析一下,若没取到就返回空 } } //取出所有的值 //到localStorage中取数据 var list=store.fetch("miaov-new-class"); //过滤的时候分三种情况:all、finished、unfinished var filter={ all:function(list){ return list; }, finished:function(list){ return list.filter(function(item){ return item.isChecked; }) }, unfinished:function(){ return list.filter(function(item){ return !item.isChecked; }) } } var vm=new Vue({ el:".main", data:{ list:list, todo:"", edtorTodos:'' ,//记录正在编辑的数据 beforeTitle:'' ,//记录一下正在编辑的数据的title visibility:"all" //通过这个属性值的变化对数据进行筛选 }, watch:{ //监控功能 list:{ handler:function(){ store.save("miaov-new-class",this.list); }, deep:true //深监控 } }, computed:{ noCheckeLength:function(){ return this.list.filter(function(item){ return !item.isChecked }).length }, filteredList:function(){ //找到了过滤函数就返回过滤后的数据,如果没有则返回所有数据 return filter[this.visibility] ? filter[this.visibility](list) : list; } }, methods:{ //统一管理事件处理函数 addTodo:function(){ /*//添加任务 //向list中添加一项任务 //事件处理函数中的this指向的是当前这个根实例*/ this.list.push({ /*title:ev.target.value*/ title:this.todo , //替换上面的语句,减少dom操作 isChecked:false }); this.todo=''; //数据更新视图 }, deleteTodo:function(todo){ //删除任务 var index=this.list.indexOf(todo); this.list.splice(index,1); }, edtorTodo:function(todo){ //编辑任务 console.log(todo); this.edtorTodos=todo;//用数据记录一下现在正在编辑的信息, // 编辑任务的时候,记录一项编辑这条任务的title,方便取消编辑的是好重新给之前的title this.beforeTitle=todo.title; }, edtorTodoed:function(todo){ //编辑任务成功 this.edtorTodos=""; }, cancelTodo:function(todo){ //取消编辑任务 /*console.log(123);*/ todo.title=this.beforeTitle; this.beforeTitle=''; //让div显示出来,input框隐藏,可以选择将正在编辑的信息置为空 this.edtorTodos=''; } }, directives:{ "focus":{ update(el,binding){ /* console.log(el); console.log(binding);*/ if(binding.value){ el.focus();//当选中某个input时自动获得焦点 } } } } }); function watchHashChange(){ var hash=window.location.hash.slice(1); /*console.log(hash);*/ vm.visibility=hash; } watchHashChange(); window.addEventListener("hashchange",watchHashChange);
结果:
初次录屏,有点失败啊,捂脸。。。。。。
遇到的问题:
1-网页开始定义的文字及列表后面的叉删除符显示异常
解决方法:
html的head中定义:
<meta
http-equiv="Content-Type"
content="text/html; charset=utf-8"
/>
;
同时
在css开头定义:@charset "utf-8";
2- {{message}}直接显示,而没有渲染成绑定的数据
数据没有传进去,初步判断为es6与es5模式的混用,如let声明、var声明及函数的简写
3-在所有任务、未完成任务、完成任务三个显示框上,点击哪个下面对应的列表项就显示哪个,但红色的框框始终显示在所有任务上
原来问题出在css :active选择器上啊。:active选择器用于选择活动链接,当在一个链接上点击时,其将成为活动链接即被激活的。此外,:link选择器用于设置对未被访问页面的链接的样式;:visited选择器用于设置指向已访问页面的链接的样式;:hover选择器用于设置鼠标指针浮动在链接上时的样式。
<li class="action">
<a :class="{active:visibility==='all'}" href="#all">所有任务</a>
<a href="#unfinished" :class="{active:visibility==='unfinished'}">未完成的任务</a>
<a href="#finished" :class="{active:visibility==='finished'}">完成的任务</a>
</li>
.active {
border: 1px solid rgba(175, 47, 47, 0.2);
}
4-在所有任务页面,当删除列表项内容时,下面的列表项内容会立即消失,但是在未完成任务与已完成任务页面,当点击删除列表项内容时,列表项内容不会立即消失,当刷新页面或点击别处再点回来时其下被删除的列表项内容才会被删除,这里的问题出现在哪里呢?
有待解决。。。。。。
源码可参考:https://github.com/sunshineqt/vue