模仿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>  
上一篇下一篇

猜你喜欢

热点阅读