目录
组件数据存放一
组件对象也有一个 data 属性(也可以有 methods 等属性),只是这个 data 属性必须是一个函数而且这个函数返回一个对象,对象内部保存着数据:
<div id="app" >
<my-component></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component', {
template: `<div>{{ msg }}</div>`,
data() {
return {
msg : 'hello vue',
}
}
})
const app = new Vue({
el: '#app'
})
</script>
为什么是一个函数呢?
首先,如果不是一个函数,Vue 直接就会报错。
其次,原因是在于 Vue 让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
如何进行父子组件间的通信呢?Vue 官方提到,通过 props
向子组件传递数据,可以通过事件向父组件发送消息。
真实的开发中,Vue 实例和子组件的通信和父组件和子组件的通信过程是一样的。
props
基本用法
在组件中,使用选项 props 来声明需要从父级接收到的数据。
props 的值有两种方式:
字符串数组:数组中的字符串就是传递时的名称。
对象:对象可以设置传递时的类型,也可以设置默认值等。
<div id="app">
<my-component :msg="msg"></my-component>
</div>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data:{
msg:'hello vue',
},
components:{
'my-component': {
props: ['msg'],
template:`<div>
<p>{{ msg }}</p>
</div>`
}
}
})
</script>
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
<div id="app">
<my-component :my-msg="msg"></my-component>
</div>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data:{
msg:'hello vue',
},
components:{
'my-component': {
props: ['myMsg'],
template:`<div>
<p>{{ myMsg }}</p>
</div>`
}
}
})
</script>
props
数据验证
props
可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值等等。
props
高级选项
props 高级选项 | 作用 | 说明 |
---|---|---|
type | 会检查该 prop 是否是给定的类型,否则抛出警告 | 可以是下列原生构造函数中的一种:String 、Number 、Boolean 、Array 、Object 、Date 、Function 、Symbol 、任何自定义构造函数、或上述内容组成的数组 |
default | 为该 prop 指定一个默认值 | 如果该 prop 没有被传入,则换做用这个值,对象或数组的默认值必须从一个工厂函数返回 |
required | 定义该 prop 是否是必填项,默认为false | 在非生产环境中,如果这个值为true 且该prop 没有被传入的,则一个控制台警告将会被抛出 |
validator | 自定义验证函数会将该 prop 的值作为唯一的参数代入 | 在非生产环境下,如果该函数返回一个false 的值 (也就是验证失败),一个控制台警告将会被抛出 |
我们来直接看看代码更直观:
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() {
return { message: 'hello vue' }
}
},
// 自定义验证函数
propF: {
validator(value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
额外的,type
还可以是一个自定义的构造函数,并且通过 instanceof
来进行检查确认。例如,给定下列现成的构造函数:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
你可以使用:
Vue.component('my-component', {
props: {
author: Person
}
})
来验证 author
prop 的值是否是通过 new Person
创建的。
子级向父级传递
props
用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。
我们需要使用自定义事件来完成。
什么时候需要自定义事件呢?
当子组件需要向父组件传递数据时,就要用到自定义事件了。
我们之前学习的 v-on
不仅仅可以用于监听 DOM 事件,也可以用于组件间的自定义事件。
自定义事件的流程:
在子组件中,通过 $emit()
来触发事件。
在父组件中,通过v-on
来监听子组件事件。
我们来看一个简单的例子:
我们之前做过一个两个按钮+1
和-1
,点击后修改 count
。
我们整个操作的过程还是在子组件中完成,但是之后的展示交给父组件。
这样,我们就需要将子组件中的 count
,传给父组件的某个属性,比如 currentCount
。
<div id="app">
<my-button @increment="showCurrentCount" @decrement="showCurrentCount"></my-button>
<p>当前值:{{ currentCount }}</p>
</div>
<template id="my-button">
<div>
<button type ="button" @click="decrement">-</button>
<button type ="button" @click="increment">+</button>
</div>
</template>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data:{
currentCount: 0
},
methods:{
showCurrentCount(count) {
this.currentCount = count
}
},
components:{
'my-button': {
template: '#my-button',
methods:{
increment() {
this.count++
this.$emit('increment', this.count)
},
decrement() {
this.count--
this.$emit('decrement', this.count)
}
},
data() {
return {
count:0
}
}
}
}
})
</script>
不同于组件和 prop,事件名不会被用作一个 JS 变量名或 property 名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on
事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent
将会变成 v-on:myevent,
导致 myEvent
不可能被监听到。
因此,推荐你始终使用 kebab-case 的事件名。