第一个Vue的demo => toDoList。没网2天了,课程没跟上。localstorage部分就没学了。暂时完成到这个版本。之后更新保持,先放demo页面链接。
http://xzchen.github.io/project/vue/todolist/
运行效果图
html 分为header、doing、done三部分。
header里面包括一个input通过指令v-model=createToDo与实例里data.createTodo的值进行双向绑定。用来创建doingList,
doing和done主体部分都是一个ul列表,通过指令v-for来渲染DOM。
doing||done下的tip功能由指令v-show通过控制元素的display来控制显隐。
与v-if的其一差别在于v-if每次切换会被销毁和重建。
每个li的children == [input,p,span];
1. 其中type=checkbox的input通过v-model=doing.flag来保证checkbox在样式上永远保证未勾选状态并且在doing和done下对于数据进行切换。
2. 其中p的childNodes == [doing||done.text, input];
2.1 doing||done.text来显示文本内容。
2.2通过给v-bind:class={showEditInput:doing === editText}** 来控制能编辑p[0]的p.input空间的显隐。
2.3其中p.input 又通过自定义指令v-focus=”editText === doing”使得光标在input出现后就自动聚焦和v-on:blur=editText =”和v-on:keyup.13=editText=’ ‘ v-on:keyup.esc=doing.text = oldText;editText = ” “适时提交修改||未修改的数据。
3.其中span在v-on:click=”deleteList(done, doneLists)”执行删除list的方法
核心HTML代码。
<div id="toDoList">
<!-- v-model指令对于表单控件进行双向绑定,方便进行数据的修改 -->
<input type="text"
v-on:keyup.13="fnCreateToDo()"
v-on:blur="fnCreateToDo()"
id="createToDo"
placeholder="增加要完成的todo,回车键入">
<div>
<!-- 此处通过v-show控制两个p标签的display进行提示 -->
<p v-show="!doingLists.length">没有待完成的任务</p>
<p v-show="doingLists.length">正在进行<span>{{doingLists.length}}</span></p>
<ul>
<li v-for="doing in doingLists" >
<input type="checkbox" name="" v-on:click = "doingToDone(doing)" v-model="doing.flag">
<p v-bind:title="doing.text" v-on:click="showEditInput(doing)">
{{doing.text}}
<input type="text" v-bind:class="{showEditInput:doing === editText}" v-focus="editText === doing" v-on:blur="editText = ''" v-model="doing.text" v-on:keyup.13="editText = ''" v-on:keyup.esc="doing.text = oldText;editText = ''">
<!-- blur清空editText,因为本来通过input的v-model使得doing的text的值是改变了,而editText又是和doing共用1个内存。修改1个对象,另外1个对象的值也跟着改变。但是清空1个对象,另外个对象还是存在。所以清空editText的值,doing的值不变 -->
</p>
<span v-on:click = "deleteList(doing, doingLists)"></span>
</li>
</ul>
</div>
//done部分结构一样。写到着想到可能可以用template写。
</div>
JS部分
new Vue({
el:"#toDoList",
data:{
createToDo:"v-model执行双向绑定,根据这里的数据去添加到doingLists数组里",
editText: "", //获得当前要编辑doing||list。是doingLists||doneLists数组下某一个对象
oldText: "", //取消编辑前,记录之前存储的内容
doingLists:[
{
text: "doingLists和doneLists数组里包含的都是多个json对象。键text的值存放的是文本",
flag: false
}
methods:{
fnCreateToDo(){
//这里的this指的是当前Vue实例
if(this.createToDo.trim()) { //如果不是添加的空任务就确认push到doingLists数组
var json = {
text: this.createToDo.trim(),
flag: false
}
this.doingLists.push(json);
this.createToDo = "";
}
},
//勾选某个li下的checkbox就会再doing和done之间进行数据交换。其实就是数组的操作
doingToDone(doing) {
doing.flag = false; //保证checkbox仍然是未勾选状态
this.doneLists.push(this.doingLists.splice(this.doingLists.indexOf(doing), 1)[0]) //因为返回的是一个数组,取第一个的就成。不然格式不对。
},
deleteList(list, lists){
lists.splice(lists.indexOf(list), 1);
},
showEditInput(list) {
//对象的复制是引用空间,这里值得注意。
this.editText = list;
this.oldText = list.text;
}
},
directives: {
"focus": {
update(el, binding) {
//如果元素上绑定的表达式为真 editText === doing || done;
if (binding.value) {
el.focus();
}
}
}
}
})