组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。
-
也就是props是子组件访问父组件数据的唯一接口。
-
一个组件可以直接在模板里面渲染data里面的数据(双大括号)。
-
子组件不能直接在模板里面渲染父元素的数据。
-
如果子组件想要引用父元素的数据,那么就在prop里面声明一个变量(比如a),这个变量就可以引用父元素的数据。然后在模板里渲染这个变量(前面的a),这时候渲染出来的就是父元素里面的数据。
-
属性是驼峰式命名,在html中替换成短横线分割式命名
-
prop类型可以是字符串,数字、boolear、数组、对象
传递静态或动态 Prop
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
<script>
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
</script>
单向数据流:props是单向绑定
-
当父组件的属性变化时,将传导给子组件,但是反过来不会。
-
每次父组件更新时,子组件的所有 prop 都会更新为最新值。
-
不要在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。
在两种情况下,我们很容易忍不住想去修改 prop 中数据:
Prop 作为初始值传入后,子组件想把它当作局部数据来用;
Prop 作为原始数据传入,由子组件处理成其它数据输出。对这两种情况,正确的应对方式是:
定义一个局部变量,并用 prop 的值初始化它:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
- 定义一个计算属性,处理 prop 的值并返回:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,
如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态
<div id="app3">
<my-component :object='object'></my-component>
</div>
<script src="http://vuejs.org/js/vue.min.js"></script>
<script>
//
var mycom = Vue.component('my-component', {
//添加一个input改变子组件的childOject,那么父元素的object也会被改变,但是Vue没有报错!
template: '<p>{{ object.name }} is {{ object.age }} years old.<br><input v-model="childObject.name" type="text"></p>',
props: ['object','school'],
data: function () {
// 子组件的childObject 和 父组件的object 指向同一个对象
return {
childObject: this.object
}
}
});
var app3 = new Vue({
el: '#app3',
data: {
object:{
name: 'Xueying',
age: '21',
},
school:'SCUT',
},
})
</script>
prop验证
- 为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
Vue.component('my-component',
{ props:
{ // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
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 ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } })
eg:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue Study</title>
</head>
<body>
<div id="app">
<foo-component :foo-message="fooMessage"></foo-component>
</div>
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
var fooComponent = {
props: {
fooMessage: Number
},
template: '<div> {{ fooMessage }} </div>'
};
var vm = new Vue({
components: {
'foo-component': fooComponent
},
el: '#app',
data: {
fooMessage: 123
}
});
</script>
</body>
</html>
type接受多个类型:当参数是多种类型的其中一个的时候,使用数组来表示
var fooComponent = {
props: {
fooMessage: [Number, String]
},
template: '<div> {{ fooMessage }} </div>'
};
- type能够指定的类型
- 当type的类型为Array或者Object的时候default必须是一个函数:
- required可以使用required选项来声明这个参数是否必须传入
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue Study</title>
</head>
<body>
<div id="app">
<foo-component :foo-message="fooMessage"></foo-component>
</div>
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
var fooComponent = {
props: {
fooMessage: {
type: Number,
required: true
}
},
template: '<div> {{ fooMessage }} </div>'
};
var vm = new Vue({
components: {
'foo-component': fooComponent
},
el: '#app',
data: {
fooMessage: 256
}
});
</script>
</body>
</html>
String
Number
Boolean
Function
Object
Array
Symbol
非Prop的特性
- 什么是prop的特性?
—指传向一个组件,但是该组件没有添加到props中如何在子组件访问
Vue.component('test-prop', {
// 在组件props中只定义了param1
props: ['param1'],
inheritAttrs: false, // 详情见 ↓ 附录1
template: '<div></div>',
mounted() {
console.log(this.param1); // 值1
console.log(this.param2); // undefined
console.log(this.$attrs); // 返回父作用域中非 prop 的特性 (class 和 style 除外)的对象集合
console.log(this.$attrs.param1); // undefined
console.log(this.$attrs.param2); // 值2
console.log(this.$listeners); // 返回父作用域中的 (不含 .native 修饰器的) v-on 事件集合
console.log(this.$listeners.event1); // fn1
console.log(this.$listeners.event2); // undefined
this.$emit('event1');
}
})
<test-prop
param1="值1"
param2="值2"
v-on:event1="fn1"
v-on:event2.native="fn2"></test-prop>
<!-- 此时 传入的param2 即为 非 prop 的特性 -->
通过 $attrs 及 $listeners 属性可以降低在不使用Vuex以及事件总线的情况下,组件跨级props以及事件传递的复杂度。
$parent
p a r e n t 也 可 以 用 来 访 问 父 组 件 的 数 据 。 而 且 子 组 件 可 以 通 过 parent 也可以用来访问父组件的数据。而且子组件可以通过 parent也可以用来访问父组件的数据。而且子组件可以通过parent 来直接修改父组件的数据,不会报错!
<blog-post :object1="obj" :obj1="'hhhhh'"></blog-post>
</div>
<script>
Vue.component('blog-post', {
props: ['title','object1'],
template: '<p>{{ object1.name }} is {{ object1.age }} years old.<br><input v-model="childObject.name" type="text">,</p>',
data:function () {
return {childObject:this.object1}
},
mounted(){
console.log(this.object1);
console.log(this.$attrs.obj1);
console.log(this.$parent.text);
}
})
new Vue({
el:'.app',
data:{
text:'12345',
obj:{
name:'xiaomei',
age:'21'
}
}
})