zoukankan      html  css  js  c++  java
  • vue学习笔记(八)组件校验&通信

    前言

    在上一章博客的内容中vue学习笔记(七)组件我们初步的认识了组件,并学会了如何定义局部组件和全局组件,上一篇内容仅仅只是对组件一个简单的入门,并没有深入的了解组件当中的其它机制,本篇博客将会带大家深入了解组件的其它知识,组件的校验,组件的通信等等。

    本章目标

    • 学会组件简单的校验
    • 学会父组件向子组件传递数据
    • 学会子组件向父组件传递数据

    父组件向子组件传递数据

    父组件向子组件传递数据实现的方式特别简单,只用使用props进行数据传递就可以了。

    语法:props['属性1',‘属性2’,...]

    我找了一张图给大家参考一下

    在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息

    (1)简单的父组件向子组件传递信息

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>父组件向子组件传递信息</title>
        </head>
        <body>
            <div id="app">
                <my-content :title='title' :content='content'></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        title:'标题',
                        content:'内容'
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            props:['title','content'],
                            template:`<div>
                                <h1>{{title}}</h1>
                                <p>{{content}}</p>
                            </div>`
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:显示标题和内容,最简单的父组件向子组件传递信息我们就实现了,但是里面还有其它的小知识点我们没有讲解到,而且后期开发都是使用vue-cli来实现父组件向子组件传递数据的,所以这个知识点下一篇博客会讲解到,不会搭建vue-cli项目的朋友可以参考这篇博客使用webstorm搭建vue-cli项目后续的许多文章都会使用vue-cli中的组件进行讲解,而不是通过简单的引入vue.js文件了,所以强烈推荐大家一定要学会搭建vue-cli项目。

    总结:父组件向子组件传递数据使用props

    (2)props传递整个对象

    假设父组件中的对象含有多个属性,我们每一个属性都需要进行传递,那么是不是需要绑定每一个属性呢?

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>props传递多个属性</title>
        </head>
        <body>
            <div id="app">
                <my-content :title="attr.title" :content1="attr.content1" :content2="attr.content2"></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        attr:{
                            title:'新闻主题',
                            content1:'新闻内容1',
                            content2:'新闻内容2',
                        }
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            props:['title','content1','content2'],
                            template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    现在这个实例所表现出来的就是一个对象里面有很多个属性,现在仅仅只有三个属性而已,我们的父组件绑定属性的时候就需要绑定三个属性,如果是100个或者1000个那么绑定组件的那个标签不是很长吗?和同事一起开发的话,你的同事看到那么长的代码肯定会怀疑人生的,所以为了解决这个问题我们将代码改写下面那样。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>props传递多个属性</title>
        </head>
        <body>
            <div id="app">
                <my-content  v-bind="attr"></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        attr:{
                            title:'新闻主题',
                            content1:'新闻内容1',
                            content2:'新闻内容2',
                        }
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            props:['title','content1','content2'],
                            template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    在这里我们使用v-bind将整个对象打包传递过去,这样一来就大大的减少了代码的冗余度了,那么你的同事肯定夸你小伙子不错,你就等着被领导表扬吧!(自己脑补出来的)

    data必须是函数

    为什么说data必须是一个函数呢?这个知识点在上一篇博客中没有提及到,现在的话我们来讨论一下,这个案例就足够说明了。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>data必须是函数</title>
        </head>
        <body>
            <div id="app">
                <my-content></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                Vue.component('myContent',{
                    data:{
                        msg:'hello world'
                    },
                    template:'<span>{{msg}}</span>',
                });
                let vm=new Vue({
                    el:'#app'
                })
            </script>
        </body>
    </html>

    结果:

     控制台显示vue.js给出的警告也是提出data必须是一个函数,好的既然规定data必须是一个函数,那我们就按照它说的来做。看看结果如何

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>data必须是函数</title>
        </head>
        <body>
            <div id="app">
                <my-content></my-content>
                <my-content></my-content>
                <my-content></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                var data={
                    count:1
                }
                Vue.component('myContent',{
                    data:function(){
                        return data;
                    },
                    template:'<button @click="count+=1">{{count}}</button>',
                });
                let vm=new Vue({
                    el:'#app'
                })
            </script>
        </body>
    </html>

     

    现在的话,我们的data是一个函数,但是解决一个问题的同时新的问题又出现了,点击任意一个按钮的时候发现其它按钮的值都会发生改变,这是因为我们引用了同一个对象,我们知道对象是引用传递的,所以为了改变这一种情况,我们让每个组件内部都有自己的状态而不会去干涉其它组件。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>data必须是函数</title>
        </head>
        <body>
            <div id="app">
                <my-content></my-content>
                <my-content></my-content>
                <my-content></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                Vue.component('myContent',{
                    data(){
                        return{
                            count:1
                        }
                    },
                    template:'<button @click="count+=1">{{count}}</button>',
                });
                let vm=new Vue({
                    el:'#app'
                })
            </script>
        </body>
    </html>

    结果:

     我们在data中使用return返回新的对象,这样一来每一个组件都有自己本身的状态了,从而不会去影响其它的组件。

    组件的校验

    组件的校验从字面上看就是对父组件向子组件传递的信息中,子组件对父组件传递过来的信息进行验证,一方面是为了数据的安全性,另一方面给他人使用的时候也可以限制他人传递过来的数据的验证。

    Vue.component('example', {
      props: {
        // 基础类型检测 (`null` 意思是任何类型都可以)
        propA: Number,
        // 多种类型
        propB: [String, Number],
        // 必传且是字符串
        propC: {
          type: String,
          required: true
        },
        // 数字,有默认值
        propD: {
          type: Number,
          default: 100
        },
        // 数组/对象的默认值应当由一个工厂函数返回
        propE: {
          type: Object,
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            return value > 10
          }
        }
      }
    })

    type可选:

    • Sting
    • Number
    • Boolean
    • Function
    • Object
    • Array

    (1)示例一

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>组件的校验示例一</title>
        </head>
        <body>
            <div id="app">
                <my-content :name="name" :age="age" :sex="sex"></my-content>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        name:'小明',
                        age:18,
                        sex:''
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            props:{
                                name:{
                                    type:Number,
                                    required:true,
                                },
                                age:{
                                    type:Number,
                                    default:20,
                                },
                                sex:{
                                    type:String,
                                    default:''
                                }
                            },
                            template:'<div><span>{{name}}</span><span>{{age}}</span><span>{{sex}}</span></div>'
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:

    我们对name做了验证规定,name的类型必须是Number,而传递过来的却是String,所以vue.js给出了警告,对name属性也要求是必须传递的参数,required:true,对sex给定默认值,当我们没有传递sex的时候,子组件中的sex默认值是女的,所以有了组件的这一校验,大大提高的数据的安全性。

    (2)示例二

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>组件的校验示例二</title>
        </head>
        <body>
            <div id="app">
                <my-content name="喜马拉雅" :size="8848" :is-boy="false" address="中国西藏"></my-content>
            </div>
            <script type="text/template" id="template1">
                <div>姓名:{{name}}身高:{{size}}是否是男生:{{isBoy}}位置:{{address}}重量:{{weight.ton}}亿吨</div>
            </script>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                Vue.component('myContent',{
                    template:'#template1',
                    props:{
                        name:{
                            type:String,    //类型
                            required:true,    //规定必填
                        },
                        size:Number,    //规定整形
                        isBoy:Boolean,    //规定布尔值
                        age:[Number,String],//    多种类型
                        address:{
                            type:String,
                            default:'中国',
                            validator:function(value){
                                return value.indexOf('中国')>=0
                            }
                        },
                        weight:{
                            type:Object,
                            default:function(){
                                return {ton:999999999}
                            }
                        },
                    }
                    
                })
                let vm=new Vue({
                    el:'#app',
                    data:{
                        
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:

    子组件向父组件传递数据

    我们知道,父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,应该怎样做?那就是自定义事件!每个 Vue 实例都实现了事件接口(Events interface),即:

    • 使用 $on(eventName) 监听事件
    • 使用 $emit(eventName) 触发事件

    接下来我们一步一步对子组件向父组件传递数据进行讲解,先来看下一个特别简单的示例,这个需求是这样的,当我们改变子组件的count的时候,父组件的count也需要改变

    (1)子组件实现功能

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>子组件向父组件传递数据</title>
        </head>
        <body>
            <div id="app">
                <my-content :count="count"></my-content>
                父组件的count:<span>{{count}}</span>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        count:1
                    },
                    methods:{
                        
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            data(){
                                return{
                                    ownCount:this.count
                                }
                            },
                            props:['count'],
                            template:'<div>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                            methods:{
                                handleClick(){
                                    this.ownCount++;
                                }
                            }
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    我们通过父组件向子组件传递了count值,然后子组件中的count值在点击之后会发生改变,但是这仅仅实现了子组件的值改变,并没有实现父组件中的count改变

    (2)向父组件传递信息

    需要向父组件传递信息的话,我们就需要子组件通知父组件,然后父组件在做相应的处理,而需要通知父组件我们就i需要用到this.$emit('事件名称',值)。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>子组件向父组件传递数据</title>
        </head>
        <body>
            <div id="app">
                <my-content :count="count" @add="handleAdd"></my-content>
                父组件的count:<span>{{count}}</span>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        count:1
                    },
                    methods:{
                        handleAdd(count){
                            this.count=count;
                        }
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            data(){
                                return{
                                    ownCount:this.count
                                }
                            },
                            props:['count'],
                            template:'<div>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                            methods:{
                                handleClick(){
                                    this.ownCount+=10;
                                    this.$emit('add',this.ownCount);
                                }
                            }
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:

    我们在子组件点击按钮的时候添加了this.$emit()来通知父组件,然后将需要注册的事件和每次改变的值传递了过去,这时父组件注册子组件传递过来的事件和值,然后将父组件中的值替换子组件传递过来的就可以了。

    (3)优化子组件向父组件传递信息

    其实我们可以做到让父组件来控制子组件中count值的变化,假设我们每次让子组件增加10,我们先来一个小案例

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>子组件向父组件传递数据</title>
        </head>
        <body>
            <div id="app">
                <my-content :count="count" @add="handleAdd" v-bind="info"></my-content>
                父组件的count:<span>{{count}}</span>
                <button @click="handleClick">点击</button>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        count:1,
                        info:{
                            name:'',
                            age:18
                        }
                    },
                    methods:{
                        handleAdd(count){
                            this.count=count;
                        },
                        handleClick(){
                            this.info.name=''
                        }
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            data(){
                                return{
                                    ownCount:this.count
                                }
                            },
                            props:['count','name','age'],
                            template:'<div><span>姓名:{{name}}</span><br/>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                            methods:{
                                handleClick(){
                                    this.ownCount+=10;
                                    this.$emit('add',this.ownCount);
                                }
                            }
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:

     

    当我们点击按钮的时候发现父组件传递给子组件的姓名发生了改变,那么我们只要改变父组件中的count的值,那么子组件中count的值也会发生改变

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>子组件向父组件传递数据</title>
        </head>
        <body>
            <div id="app">
                <my-content :count="count" @add="hanldeAdd"></my-content>
                父组件中的count<span>{{count}}</span>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                let vm=new Vue({
                    el:'#app',
                    data:{
                        count:1
                    },
                    methods:{
                        hanldeAdd(count){
                            this.count+=count;
                        }
                    },
                    computed:{
                        
                    },
                    components:{
                        'myContent':{
                            data(){
                                return{
                                    //ownCount=this.count;
                                }
                            },
                            props:['count'],
                            template:'<div>子组件中的count<span>{{count}}</span><button @click="handleClick">add</button></div>',
                            methods:{
                                handleClick(){
                                    this.$emit('add',10)
                                }
                            }
                        }
                    }
                    
                })
                
            </script>
        </body>
    </html>

    这样一来父子组件的简单通信就全部讲完了,接下来为了巩固一下父子组件之前通信的知识,我们来做一个任务清单

    总结:子组件向父组件传递信息this.$emit('事件名称',值)

    (4)任务清单

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>任务清单</title>
        </head>
        <body>
            <div id="app">
                任务:<input type="text" v-model="newTask" @keyup.enter="addNew" placeholder="请输入您要完成的任务" />
                <ul>
                    <li is="todoImte" v-for="(item,index) of tasks" :title="item" @remove="removeItem(index)"></li>
                </ul>
            </div>
            <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
            <script type="text/javascript">
                Vue.component('todoImte',{
                    props:['title'],
                    template:"<li>{{title}}<button @click='$emit("remove")'>X</button></li>"
                });
                let vm=new Vue({
                    el:'#app',
                    data:{
                        newTask:'',
                        tasks:['买一本书','写一次博客','和朋友一起吃饭']
                    },
                    methods:{
                        addNew(){
                            this.tasks.unshift(this.newTask);
                            this.newTask='';
                        },
                        removeItem(index){
                            if(confirm('确定要删除吗?')){
                                this.tasks.splice(index);
                            }
                        }
                    },
                    computed:{
                        
                    }
                    
                })
                
            </script>
        </body>
    </html>

    结果:

     

    任务清单中,首先有个添加任务的框,然后通过addNew方法将任务添加到任务清单中,子组件中通过this.$emit()告诉父组件执行相应的方法,任务清单中,我们可以添加任务清单也可以删除任务清单,添加任务清单的话,没有涉及组件通信,二删除任务清单的时候,子组件通知父组件需要删除那个任务,然后将需要删除任务的索引传递过去,父组件根据传递过来的index进行删除。

    总结

    本篇博客主要讲了三个知识点,组件的校验,父组件向子组件传递信息(通过props),子组件向父组件传递信息(通过this.$emit),本篇博客讲解的内容也比较简单,但是我认为这仅仅也还是组件的开始,下一遍博客我们将会讲解vue-cli中的组件通信,毕竟这个才是重点,现在的组件通信也才是入门。欢迎大家在博客下方评论,我们一起交流。

  • 相关阅读:
    MySql 用户 及权限操作
    MAC 重置MySQL root 密码
    在mac系统安装Apache Tomcat的详细步骤[转]
    Maven:mirror和repository 区别
    ES6 入门系列
    转场动画CALayer (Transition)
    OC 异常处理
    Foundation 框架
    Enum枚举
    Invalid App Store Icon. The App Store Icon in the asset catalog in 'xxx.app' can’t be transparent nor contain an alpha channel.
  • 原文地址:https://www.cnblogs.com/jjgw/p/11876826.html
Copyright © 2011-2022 走看看