zoukankan      html  css  js  c++  java
  • Vue.js 章7:组件、使用props传递数据、父子组件通信

    这一章感觉要学好久了...

    <body>
        <!-- 组件:Vue.js最核心、设计最精彩的功能,也是最难掌握的(555) -->
        <!-- 组件:提高重用性,让代码能够复用 -->
        <div id="app1">
            <my-component-01></my-component-01>
            <my-component></my-component>
        </div>
    
        <!-- 在某些情况下,组件的模板会受到html的限制,如table标签内规定只允许是tr、td、th这些表格元素,
        所以直接在table标签内使用组件是无效的,这种情况下可以使用特殊的is属性来挂载组件 -->
        <div id="app2">
            <table>
                <tbody is = 'my-component-table'>
    
                </tbody>
            </table>
        </div>
    
        <div id="app3">
            <my-component-02></my-component-02>
        </div>
    
        <div id="app4">
            <my-component-03></my-component-03>
            <my-component-03></my-component-03>
            <my-component-03></my-component-03>
            <my-component-03></my-component-03>
            <my-component-03></my-component-03>
        </div>
    </body>
    <script>
        // 组件需要注册之后才能使用,有全局注册(任何Vue实例都可以使用)以及局部注册两种方式
        // 全局注册,注册的组件需要在初始化根实例之前注册了组件;
        // 局部注册,通过使用组件实例选项注册,可以使组件仅在另一个组件或者实例的作用域中可用:
        Vue.component('my-component-01',{
            template:'<div>这是第一个组件的内容</div>'
            //组件内容
        });
        Vue.component("my-component-table",{
            template:'<div>这是塞进表格组件里的内容</div>'//渲染时会将tbody替换
        });
        var childCompo = {
            template:'<div>这是第一个局部注册组件的内容</div>'
        };
        var app1 = new Vue({
            el:"#app1",
            components:{
                'my-component':childCompo
            }
        });
    
        var app2 = new Vue({
            el:"#app2"
        });//注意了,使用组件时要确保已经将元素挂载到Vue实例
    
        //组件还可以像vue实例那样使用其他选项,比如data、computed、methods等,但在使用data时有区别:
        //data必须是函数,将数据return出去
        Vue.component('my-component-02',{
            template:'<div>{{ message }}</div>',
            data() {
                return {
                    message:'组件内容,这里的data是函数'
                }
            },
        });
    
        var app3 = new Vue({
           el:"#app3" 
        });
    
    
        //js的对象是引用关系(值传递和引用传递的相关知识),如果return的对象引用了外部的一个对象,那么这个对象就是共享的
        //任何一方修改都会同步
        var dataObj = {
            counter:0
        };
        Vue.component('my-component-03',{
            template:'<button v-on:click="counter++">记录点击次数:{{ counter }}</button>',
            // data:function(){
            //     return {
            //         dataObj//上面那个对象
            //     }
            // }会报错的写法
            data:function(){
                return dataObj
            },
            // data:function(){
            //     return {
            //         counter:0
            //     }
            // }
        })
        var app4 = new Vue({
           el:"#app4", 
        });
    
        //如果这样,每点击一个按钮,所有按钮的计数次数都会+1,改写为96~100行的形式
        //原理:给每个组件返回一个新的data对象
    </script>

    重难点是后面两个部分,使用props传递数据、父子组件通信

    <body>
        <div id="app1">
            <my-component-01 message-from="来自父组件的数据"></my-component-01>
        </div>
    
        <div id="app2">
            <input type="text" v-model="parentMessage">
            <my-component-02 :message = "parentMessage"></my-component-02>
        </div>
    
        <div id="app3">
            <my-component-03 message="[1,2,3]"></my-component-03>
            <my-component-03 :message="[1,2,3]"></my-component-03>
            <!-- 直接传递数字、布尔值、数组、对象而不使用v-bind那么传递过去的只会是字符串!例如上面两个组件中的message.length,一个是7,一个是3 -->
        </div>
    
        <div id="app4">
            <my-component-04 :init-count="1"></my-component-04>
            <my-component-04 :width="200"></my-component-04>
        </div>
    
        <div id="app5">
            <input type="text" v-model="parentMessage">
            <my-component-05 :prop_a = "parentMessage"></my-component-05>
        </div>
    
        <div id="app6">
            <p>总计:{{ total }}</p>
            <my-component-06
                @increase = "handleGetTotal"
                @reduce = "handleGetTotal"></my-component-06>
            </my-component-06>
        </div>
    
        <div id="app7">
            <p>app7:{{ total }}</p>
            <my-component-07 v-model = "total"></my-component-07>
        </div>
    
        <div id="app8">
            <p>app8:{{ total }}</p>
            <my-component-08 v-model="total"></my-component-08>
            <button @click = "handleReduce">-1</button>
        </div>
    </body>
    <script>
        Vue.component('my-component-01',{
            //使用props声明需要从父级接收的数据
            props:['messageFrom'],//如果要传递多个数据,直接在props数组中添加项即可
            //注意短横杠分隔命名与驼峰式命名
            template:'<div>{{ messageFrom }}</div>',
        });
        var app1 = new Vue({
            el:"#app1"
        });
    
        //上面是写死的数据,但大多数情况传递的数据是来自父级的动态数据,此时应使用v-bind动态绑定
        Vue.component('my-component-02',{
            props:['message'],
            template:'<div>子组件:{{ message }}</div>'
        });
        var app2 = new Vue({
           el:"#app2",
           data:{
               parentMessage:''
               //数据传递:pM更改-->v-model更改-->message值更改(:message = "parentMessage")-->props中的message-->子组件中的message
           } 
        });
    
        Vue.component('my-component-03',{
            props:['message'],
            template:'<div>{{ message.length }}</div>',
            data:function(){
                console.log(this,this.message);
                return {messages:this.message};
            }
        });
        var app3 = new Vue({
           el:"#app3",
            
        });
    
        //业务中经常会遇到的两种改变prop的情况:
        //1.父组件传递初始值,子组件将其保存起来,在自己的作用域下任意传值与修改,
        //2.另一种情况:prop作为需要进行转变的初始值传入
        Vue.component('my-component-04',{
            props:['initCount','width'],
            template:'<div>
            <p>{{ count }}</p>
            <div :style="style"></div>
            </div>',
            data:function(){
                return {
                    count:this.initCount,//在组件初始化时会获取来自父组件的initCount,之后就与之无关了
                }//返回的必须是一个数据对象哈小老弟
            },
            computed: {
                style:function(){
                    return {
                        this.width + 'px'
                        //这里会得到:style="200px"
                    }
                }
            },
        });
        var app4 = new Vue({
           el:"#app4", 
        });
    
        //数据验证,当某个数据不符合输入类型时会在控制台弹出警告
        Vue.component('my-component-05',{
            props:{
                //数字类型限定
                prop_a:Number,
                // propA:[Number,String],
                //布尔值限定,默认为true,必须传入
                propB:{
                    type:Boolean,
                    default:true,
                    // required:true
                },
                //默认值必须是一个函数来返回
                propC:{
                    default:function(){
                        return [];
                    }
                },
                //自定义验证函数
                propD:{
                    validator:function(value){
                        return value > 500;
                    }
                }
            },
            template:'<div>子组件只能是数字:{{ prop_a }}</div>',
        })
        var app5 = new Vue({
           el:"#app5",
            data:{
                parentMessage:0
            }
        });
    
    
        //当子组件需要向父组件传递数据时需要用到自定义事件以及$emit()方法
        Vue.component('my-component-06',{
            template:'
            <div>
                <button @click="handleIncrease()">+1</button>
                <button @click="handleReduce">-1</button>
            </div>',
            data:function(){
                return {
                    counter:0
                }
            },
            methods: {
                handleIncrease:function(){
                    this.counter++;
                    this.$emit('increase',this.counter);
                },
                handleReduce:function(){
                    this.counter--;
                    this.$emit('reduce',this.counter);
                }
            },
        });
        //分析一下数据的传递:
        //1,total最初为0
        //点击+1键:触发组件06methods中的handleIncrease方法,counter++,通过$emit()方法(第一个参数是自定义,第二个是可不填或多填的参数)
        //父组件上的v-on监听到increase事件,触发handleGetTotal()方法,同时$emit()方法的第二个参数被传入handleGetTotal()
        //this.total=totalNum,即新的counter值
        //v-on还可以用于监听原生的dom事件,但需要加上.native修饰符
        //eg:<m-c @click.native="handleClick"></m-c>
        var app6 = new Vue({
           el:"#app6",
           data:{
               total:0
           },
           methods:{
               handleGetTotal:function(totalNum){
                    this.total = totalNum;
               }
           }
        });
    
        Vue.component('my-component-07',{
            template:'
            <button @click = "handleClick">+1</button>',
            data:
                function(){
                    return {
                        counter:0
                    }
                },
            methods: {
                handleClick:function(){
                    this.counter++;
                    this.$emit('input',this.counter);
                }
            },
        });
        // 这一块的数据流动有点奇怪,我尽力分析一下:
        // 点击按钮  触发handleClick事件---counter++,并将事件名称input与当前counter值传递给父组件,
    
        // 注意,在前面几章有一个知识点,v-model实际上是一个语法糖,从前面复制过来并加上些详细点的解释:
        // v-model你可以理解成是value的更高级,:value(v-bind)属于数据单向绑定(从script到html的单向),v-model属于双向绑定
        // v-model官方给出的说法是:这其实是一个简写的形式,v-model实际执行的是下面的绑定:
        // <input type="text" v-bind:value="dataA" v-on:input="dataA = $event.target.value" />
        // (会根据在不同的表单控件上执行不同的作用,如option与button)
        // 在本例(app7)中则是:<input type="text" v-bind:value="total" v-on:input ="total = $event.target.value" />
        //然后更新total值后就会影响视图如{{ total }}辣~
        // 接前面对于数据流动的分析:子组件将input事件传递给父组件后,相当于组件07上触发了
        //input事件,使得v-model="total"获得更新,继而更新{{ total }}
    
        //前面碰到的例子都是这样写的:<input v-model="a">
        //                          <p>{{ a }}</p>
        var app7 = new Vue({
           el:"#app7",
           data:{
               total:0
           } 
        });
    
        Vue.component('my-component-08',{
            props:['value'],
            template:'<input :value = "value" @input = "updateValue">',
            methods:{
                updateValue:function(event){
                    this.$emit('input',event.target.value);
                }
            }        
        });
        var app8 = new Vue({
           el:"#app8",
           data:{
               total:0
           },
           methods:{
               handleReduce:function(){
                   this.total--;
               }
           }
        });
        //这一部分的数据变化方向:
        //1:点击-1按钮,执行handleReduce方法,total--,直接反馈到视图中的{{ total }}与v-model="total"(双向绑定)
        //2.输入值,执行updateValue方法,同时更新value(记得前面说的v-model是个语法糖以及实际展现)
        //value被更新,子组件获取的是实时的value,也会获得更新
    </script>

    一个需要注意点的地方:

    app5、组件05部分:

    如果规定了类型,那么一开始传入的值就必须是符合类型要求的,否则会报错

  • 相关阅读:
    聊天demo SignalR
    通过NSXMLParser来解析XML
    项目中遇到的问题
    iOS网络: 把Array和Dictionaries序列化成JSON对象
    通过 NSURLConnection 发送 HTTP GET /HTTP POST /HTTP DELETE /HTTP PUT 请求
    iOS网络: 通过NSMutableURLRequest修改一个URL的请求
    iOS网络: NSURLConnection进行同步下载
    iOS网络: NSURLConnection进行异步请求
    swipe Rotation Pan Press Tap Pinch
    手势识别1:
  • 原文地址:https://www.cnblogs.com/linbudu/p/10857963.html
Copyright © 2011-2022 走看看