Vue props数据传递

前面的话

组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信。组件接受的选项大部分与 Vue实例一样,而选项props是组件中非常重要的一个选项。在Vue中,父子组件的关系可以总结为 props down,events up。父组件通过props向下传递数据给子组件,子组件通过events给父组件发送消息。这篇文章将介绍组件使用props传递数据。在这里插入图片描述

父子级组件

通常父组件的模板中包含子组件,父组件要正向地向子组件传递数据或参数,子组件接受到后根据参数的不同来渲染不同或执行操作。这个正向传递数据的过程就是通过props来实现的。

以下两种父子级组件的写法是错误的:

[第一种]

     <div id="app">
        <parent>
            <child></child>
            <child></child>
        </parent>
     </div>

这种写法当子组件注册到父组件时,Vue.js会编译好父组件的模板,模板的内容已经决定了父组件将要渲染的HTML代码" < div class=“parent”>我是父组件</ div>", < parent> …</ parent>运行时它的一些子标签只会被当做普通的HTMl来执行,不是标准的HTML标签,会被浏览器直接忽视掉。

[第二种]

同理:在父组件标签之外使用子组件也是错误的

  <div id="app1">
        <parent></parent>
        <child></child>
    </div> 

[正确写法]

  <div id="app2">
        <parent></parent>
    </div>  
 <script>
  var childNode = {
        template: `
            <div class="child">我是子组件</div>
        `
    }
    var parentNode = {
        template:
            `<div class="parent">我是父组件
                <child></child>
                <child></child>
            </div>
            
            `,           
        components: {
            'child': childNode
        }       
    }
    var app2 = new Vue({
        el:"#app2",
        components:{
            'parent': parentNode
        }
    })
</script>

在这里插入图片描述

静态props

使用props传递数据包括静态和动态两种形式,先介绍静态props 。

在组件中,使用选项props来声明需要从父级接受的数据,props的值可以是字符串数组,也可以是对象。

例如: 构造一个数组,接受一个来自父级的数据message,子组件要显式地使用props选项来声明它想获得的数据

<div id="app3">
        <parent-companent></parent-companent>
</div> 
<script>
	var child = {
        template: "<div>{{ message}}</div>",
        // 显式的声明要获取的数据
        props: ['message']
    }
    var parent = {
        template:
        // 从父组件传递数据message给子组件
        `
        <div class="parent">
            <child-component message="aaa"></child-component>
            <child-component message="bbb"></child-component>
        </div>
        `,
        components: {
            'child-component': child
        }
    }
    var app3 = new Vue({
        el: "#app3",
        components: {
            'parent-companent': parent
        }
    })
</script> 

在这里插入图片描述
[全局注册式]

<div id="app4">
   <my-component warning-text="提示信息"></my-component>
</div> 
<script>
		 Vue.component('my-component',{
        props: ['warningText'],
        template: '<div> {{warningText}}</div>'
    })
    var app4 = new Vue({
        el: '#app4',
    })
</script>

在这里插入图片描述
注意: 如果要传递多个数据,直接在props数组中添加项即可

命名规则

对于props声明的属性来说,在父级HTML模板中,属性名需要使用中划线的写法:

  var parentNode = {
            tempalte: `
            <div class="parent">
                <child my-message="aaa"></child>
                <child my-message="bbb"></child>
            </div> `,
        components: {
            'child': childNode
        }
        }

子级Props属性声明时,使用小驼峰或者中划线写法都可以;而子级HTML模板使用从父级传来的变量时,需要使用对应的小驼峰写法。

    var childNode = {
           // HTML模板中使用小驼峰写法
           template: '<div>{{myMessage}}</div>'
           // 声明时使用小驼峰或者中划线写法都可
           props: ['myMessage'] 
          // 或者: props: ['my-message']
       }

动态props

有时候,传递数据并不是直接写死的,而是来自父级的动态数据,这时可以使用指令v-bind来动态绑定props 的值,当父组件的数据变化时,也会传递给子组件。

 <div id="app5">
        <input type="text" v-model="parentMessage">
        <!--动态绑定数据message  -->
        <parent-component :message="parentMessage"></parent-component>
 </div> 
 <script>
 var app5 = new Vue({
        el: '#app5',
        data: {
            parentMessage: ''
        },
        components: {
            'parent-component': {
                // 从父级获取来数据message
                props: ['message'],
                template: `
                    <div class="parent">{{message}}
                        <child-component :my-message="data1"></child-component>
                        <child-component :my-message="data2"></child-component>
                    </div>
                `,
                data(){
                    return {
                        'data1': 'aaa',
                        'data2': 'bbb'
                    }
                },
                // 子组件
                components: {
                    'child-component': {
                        // 从父级传递来的数据“myMessage”
                        props: ['myMessage'],
                        template:  `
                            <div class="child">{{ myMessage }}</div>
                        `
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述
这里用v-model绑定了父级的数据parentMessage,当通过输入框任意输入时,子组件接受props“message”也会实时响应并更新组件模板。组件child-component接受props"my-Message"(父组件parent-component返回的数据data1与data2也会实时响应。

传递类型

如果你要直接传递数字、布尔值、数组、对象,而且不使用v-bind指令,传递的仅是字符串类型。

[例如]

    <div id="app6">
        <parent-component></parent-component>
    </div> 
  <script>
		 var childNode = {
        props: ["message"],
        template:  `
            <div>{{message}}的类型是{{type}}</div>
        `,
        // 监听属性返回message的数据类型
        computed: {
            type() {
                return typeof this.message
            }
        }
    }
    var app6 = new Vue({
        el: '#app6',
        components:{
            'parent-component': {
                template: `
                    <div class="parent">
                    <child-component :message="1"></child-component>
                    </div>
                `,
                components: {
                'child-component': childNode
            }
            }           
        }
    })
</script>

不加v-bind指令时:
在这里插入图片描述
加v-bind之后:
在这里插入图片描述
这个例子中子组件从父组件传递过来的数据messge=“1”,用计算属性监听message的类型。本来的用意是1的类型为number类型,但是这里是String类型。当加上v-bind指令时,类型就是number类型 。

单项数据流

Vue2.x与Vue1.x比较大的一个改变就是,Vue2.x通过props传递数据时单向的,也就是父组件数据变化时会传递给子组件但反过来不行。之所以这样设计,是尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态。

每次父组件更新时,子组件的所有prop都会更新为最新值。这意味着不应该在子组件 内部改变prop。如果这么做了,Vue会在控制台给出警告。

[例如]

   <div id="app7">
         <parent-component></parent-component>
     </div>  
  <script>
	 var childNode = {
        props: ['childMsg'],
        template: `
        <div class="child">
            <span>子组件</span>
            <input v-model="childMsg">
            <p>{{childMsg}}</p>
        </div>
        `
    }
    var app7 = new Vue({
        el: "#app7",
        components: {
            'parent-component': {
                template: `
                    <div class="parent">
                        <span>父组件</span>
                        <input v-model="msg">
                        <p>{{ msg }}</p>
                        <child :child-msg="msg"></child>
                    </div>
                `,
                components:{
                    'child': childNode
                },
                data() {
                    return {
                        'msg':'match'
                }
            }           
        }
        }
    })
</script>

在这里插入图片描述
当父组件数据变化时,子组件数据会相应变化;而修改子组件数据时,父组件数据不变,并在控制台显示警告

[修改prop数据]

业务中会经常遇到两种需要改变prop数据的情况。
1:prop作为初始值传入,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改。
2:prop作为需要被转变的原始值传入。

注意: JS中对象与数组时引用类型,指向同一个内存空间,props选项的数据是一个对象或者数组,在子组件内部改变它会影响父组件的状态。

[第一种情况]

可以在组件data内再声明一个局部变量,引用父组件的prop. 但这种局部的变量只接受prop的初值,当父组件prop发生变化时,子组件无法随着父组件的更新而改变

<div id="app8">
         <parent-component></parent-component>
 </div>
 <script>
	 var childNode = {
        props: ['childMsg'],
        // 使用data保存prop的初始值
        data() {
            return {
                newChildMsg: this.childMsg
            }
        },
        template:   `
        <div class="child">
            <span>子组件</span>
            <input v-model="newChildMsg">
            <p>{{newChildMsg}}</p>
        </div>
        `
    }
    var parentNode = {
        template:  `
            <div class="parent">
                <span>父组件</span>
                <input v-model="msg">
                <p>{{msg}}</p>
                <child-component :child-msg="msg"></child-component>
            </div>
        `,
        components: {
            'child-component': childNode
        },
        data() {
            return {
                'msg': "match"
            }
        }
    }
    var app8 = new Vue({
        el: '#app8',
        components: {
            'parent-component': parentNode
        }
    })
</script>

在这里插入图片描述

上面的例子子组件除了渲染prop初始值以外,父组件无论怎么改变子组件都不改变;子组件变化,父组件也不改变。

[第二种情况]

可以定义一个计算属性,处理prop的值并返回。

  <div id="app9">
        <parent-component></parent-component>
  </div>  
  <script>
	var childNode = {
        props:['childMsg'],
        template: `
            <div class="child">
                <span>子组件</span>
                <input v-model="newChildMsg">
                <p>{{ newChildMsg}}</p>  
            </div>
        `,
        computed: {
            newChildMsg: function()  {
                // childMsg的值改变newChildMsg的值也会跟着改变
                return this.childMsg
            },
        }

    }
    var parentNode = {
        template:  `
            <div class="parent">
                <span>父组件</span>
                <input v-model="msg">
                <p>{{msg}}</p> 
                <child-component :child-msg="msg"></child-component>   
            </div>
        `,
        data(){
            return {
                'msg': "match"
            }
        },
        components: {
            'child-component': childNode
        }
    }
    var app9 = new Vue({
        el:'#app9',
        components: {
            'parent-component': parentNode
        }
    })
</script>

在这里插入图片描述
因为采用的是计算属性,所以子组件的数据无法手动修改.父组件的值改变后,子组件的值会随之而改变。

[watch]

最稳妥的方法是用data声明一个变量存储prop的初始值,并使用watch来观察prop的值的变化。发生变化时更新变量的值。

   <div id="app10">
        <parent-component></parent-component>
    </div>
  <script>
	 var childNode = {
        props: ['childMsg'],
        template: `
            <div class="child">
                <span>子组件</span>
                <input v-model="temp">
                <p>{{temp}}</p>
            </div>
        `,
        data() {
            return {
                temp: this.childMsg
            }
        },
        watch: {
            // 监听数据childMsg的变化
             childMsg: function() {
                this.temp = this.childMsg;
            }
        }
    }
    var parentNode = {
        template: `
            <div class="parent">
                <span>父组件</span>
                <input v-model="message">
                <p>{{ message }}</p>
                <child-component :child-msg="message"></child-component>
            </div>
        `,
        components: {
            'child-component': childNode
        },
        data(){
            return {
                'message': 'macth'
            }
        }
    }
    var app10 = new Vue({
        el: '#app10',
        components: {
            'parent-component': parentNode
        }
    })
</script>

上例中子组件的数据即可随着父组件数据的变化而变化,又可以手动改写子组件的数据,且不影响父组件的状态。

数据验证

前面介绍的props选项的值都是一个数组,一开始介绍过,除了数组外,还可以是对象,当prop需要 验证的时候,就需要对象写法

  Vue.component('my-component',{
        props: {
            // 必须是数字类型
            propA: Number,
            // 必须是字符串类型或数字类型
            propB: [String, Number],
            // 布尔值,如果没有定义,默认值就是true
            propC: {
                type: Boolean,
                default: true
            },
            // 数字而且必传
            propD: {
                type: Number,
                required: true
            },
            // 如果是数组或对象,默认值必须是一个函数来返回
            propE: {
                type: Array,
                default: function() {
                    return [];
                }
            },
            // 自定义一个验证函数
            propF: {
                validator: function (value) {
                    return value > 10
                }
            }
        }
    });

一般的当你的组件需要提供给别人使用时,推荐都进行数据验证,比如某个数据必须是数字类型,如果传入 字符串,就会在控制台弹出警告。

下面的例子,如果传入子组件的message不是数字,则抛出警告 :

 <div id="app11">
        <parent-component></parent-component>
    </div>
 <script>
	var childNode = {
        props:  {
            'message': Number
        },
        template:  `
            <div>{{ message }}</div>
        `
    }
    var parentNode = {
        template: `
            <div class="parent">
                <child :message="msg"></child>    
            </div>
        `,
        components: {
            'child': childNode
        },
        data() {
            return{
                msg:  '123'
            }
        }
    }
    var app11 = new Vue({
        el: '#app11',
        components: {
            'parent-component':  parentNode
        }
    })
</script>
    

传入数字123时,则无警告提示。传入字符串’123’时,结果如下所示 :
在这里插入图片描述
[一个自定义验证函数]

 <div id="app12">
        <parent-component></parent-component>
    </div>
    <script>
	   var childNode = {
        props:  {
            'message':{
                validator: function(value) {
                 return value > 10
             }
            }
        },
        template:  `
            <div>{{ message }}</div>
        `
    }
    var parentNode = {
        template: `
            <div class="parent">
                <child :message="msg"></child>    
            </div>
        `,
        components: {
            'child': childNode
        },
        data() {
            return{
                msg:  9
            }
        }
    }
    var app12 = new Vue({
        el: '#app12',
        components: {
            'parent-component':  parentNode
        }
    })
</script>

当传入的数小于10,控制台弹出警告 :
在这里插入图片描述
参考:
《Vue.js实战》
https://www.cnblogs.com/xiaohuochai/p/7356084.html

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值