Vue props数据传递
前面的话组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信。组件接受的选项大部分与Vue实例一样,而选项props是组件中非常重要的一个选项。在Vue中,父子组件的关系可以总结为props down,events up。父组件通过props向下传递数据给子组件,子组件通过events给父组件发送消息。这篇文章将介绍组件使用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
更多推荐
所有评论(0)