模仿todolist 的功能
2018-06-13 本文已影响0人
bby365
基础实现
刚开始学习vue,做一个简单的todolist , 用到 v-for
v-on
v-model
整体功能比较简单,直接说遇到的问题:怎样删除点击的li ?
首先想到的是this.items.splice(e.target.id,1)
这种方法需要在每个li上面添加一个id,因为items 是个数组,需要转成一个对象数组,也就是:
items:['first','two','three']
变成:
items: [
{
message:'first',
id:0
},
{
message:'two',
id:0
} ]
这样写感觉有点太麻烦,而且新增li,也麻烦,那就换一种。
第二种想法:是渲染li 时,直接绑定 id 属性:
<li v-for="item in items" :id = "count">
然后,每次点击新增时,count++
,但是,count改变所有的li的id属性都会改,所以这种想法失败;同时,初始化时,所有的li 的id属性都一样,因为没有点击,所以count不会变。
第三种: e.target.innerHTML
这种想法,就是itmes 去查找点击的文本,获取到index值,然后再有splice去删除当前的点击的li。
测试遇到一个坑:每次点击返回index值都是 -1,发现是因为有空格,所以需要e.target.innerHTML.trim()
这样就完成了功能。
// html
<div id="app">
<input v-model="message" placeholder="edit me" type='text' @keyup.enter = "addInfo"/>
<button v-on:click='addInfo'> 提交</button>
<p>新任务:</p>
<ul v-on:click='addPlan'>
<li v-for="item in items" >
{{item}}
</li>
</ul>
<p>已完成:</p>
<ul >
<li v-for="plan in plans">
{{plan}}
</li>
</ul>
</div>
// js
var vm = new Vue({
el:'#app',
data:{
items:['first','two','three'],
plans:[],
message:''
},
methods:{
addInfo: function(){
if(!this.message) return;
this.items.push(this.message);
this.message='';
},
addPlan:function(e){
var value = e.target.innerHTML.trim()
var index = this.items.indexOf(value);
this.items.splice(index,1)
this.plans.push(value)
}
}
})
组件化改造
首先改造按钮组件,需要解决两个问题:1.组件中使用v-model
,2.按钮的点击事件传值;
- 按钮组件
Vue.component('button-add',{
props:['value'],
template:`
<div>
<input v-bind:value="value"
v-on:input="$emit('input',$event.target.value)"
placeholder="edit me" type='text' >
<button v-on:click='$emit("add-info")'> 提交</button>
</div>
`
});
// 全局中引用如下:
<button-add
v-model="message"
v-on:add-info='addInfo'>
</button-add>
遇到的问题:
1.怎么触发事件
2.组件上怎么使用v-model事件
- 列表组件
Vue.component('list-info',{
props:['items'],
template:`
<div>
<ul v-on:click='$emit("add-plan",$event)'>
<li v-for="item in items" >
{{item}}
</li>
</ul>
</div>
`
})
//全局中引用如下:
<list-info
:items='items'
v-on:add-plan='addPlan'>
</list-info>
其实,可以只把 li 改写成组件就行,因为刚学vue,所以故意把这个整体改写成组件。
遇到的问题:
控制台一直报错:target undefined,这是因为全局中的addPlan中使用了 e.target ,但是组件中没有传递event ,调试了很久,后来知道了原因 :
<ul v-on:click='$emit("add-plan",$event)'> $emit 需要传参。
改进:
1.关于 删除当前点击的元素,不用e.target.innerHTML 。
1. li 中 增加一个 ID属性
<li
:id='index'
v-for="(item,index) in items" >
{{item}}
</li>
2. 同时将id 值传递给父组件:
v-on:click='$emit("add-plan",$event.target.id)'
3. 全局 addPlan 改写如下:
addPlan:function(index){
// var value = e.target.innerHTML.trim()
// var index = this.items.indexOf(value);
var value = this.items.splice(index,1)
this.plans.push(value.toString())
}
这种方法比之前简单多了,主要数组遍历时,可以拿到index
程序源文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<button-add
v-model="message"
v-on:add-info='addInfo'>
</button-add>
<p>新任务:</p>
<list-info
:items='items'
v-on:add-plan='addPlan'>
</list-info>
<p>已完成:</p>
<ul >
<li v-for="plan in plans">
{{plan}}
</li>
</ul>
</div>
<script>
Vue.component('button-add',{
props:['value'],
template:`
<div>
<input v-bind:value="value"
v-on:input="$emit('input',$event.target.value)"
placeholder="edit me" type='text' >
<button v-on:click='$emit("add-info")'> 提交</button>
</div>
`
});
Vue.component('list-info',{
props:['items'],
template:`
<div>
<ul v-on:click='$emit("add-plan",$event.target.id)'>
<li
:id='index'
v-for="(item,index) in items" >
{{item}}
</li>
</ul>
</div>
`
})
var vm = new Vue({
el:'#app',
data:{
items:['first','two','three'],
plans:[],
message:''
},
methods:{
addInfo: function(){
if(!this.message) return;
this.items.push(this.message);
this.message='';
},
addPlan:function(index){
// var value = e.target.innerHTML.trim()
// var index = this.items.indexOf(value);
var value = this.items.splice(index,1)
this.plans.push(value.toString())
}
}
})
</script>
</body>
</html>