父与子通信
父组件如何向子组件传递数据?使用`props`属性。
> 使用组件的`props`属性
```javascript
const cpn = {
template: "#cpn",
props: {
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
}
}
}
```
> 向cmessage对象传值
```html
<div id="app">
<cpn :cMessage="message"></cpn>
</div>
<script>
const app = new Vue({
el: "#app",
data: {
message: "你好",
movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
},
components: {
cpn
}
})
</script>
```
## props属性使用
> 数组写法
```javascript
props: ['cmovies', 'cmessage']
```
> 对象写法
```javascript
props: {
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
}
}
```
> props属性的类型限制
```javascript
//1.类型限制(多个类使用数组)
cmovies:Array,//限制为数组类型
cmessage:String,//限制为Strin类型
cmessage:['String','Number']//限制为String或Number类型
```
> props属性的默认值
```javascript
// 2.提供一些默认值,以及必传值
cmessage: {
type: String,
default: 'zzzzz',//默认值
}
```
> props属性的必传值
```javascript
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
}
```
> 类型是Object/Array,默认值必须是一个函数
```javascript
//类型是Object/Array,默认值必须是一个函数
cmovies: {
type: Array,
default () {
return [1, 2, 3, 4]
}
},
```
> 自定义验证函数
```javascript
vaildator: function (value) {
//这个传递的值必须匹配下列字符串中的一个
return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
}
```
> 自定义类型
```javascript
function Person(firstName,lastName) {
this.firstName = firstName
this.lastName = lastName
}
cmessage:Person//限定了cmeessage必须是Person类型
```
> 综合使用
```html
<div id="app">
<cpn :cMovies="movies" :cMessage="message"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="(item, index) in cmovies" :key="index">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
function Person(firstName,lastName) {
this.firstName = firstName
this.lastName = lastName
}
// 父传子:props
const cpn = {
template: "#cpn",
// props: ['cmovies', 'cmessage'],//数组写法
props: { //对象写法
// 1.类型限制(多个类使用数组)
// cmovies:Array,
// cmessage:String,
// cmessage:['String','Number'],
// 2.提供一些默认值,以及必传值
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
},
//类型是Object/Array,默认值必须是一个函数
cmovies: {
type: Array,
default () {
return [1, 2, 3, 4]
}
},
// 3.自定义验证函数
// vaildator: function (value) {
// //这个传递的值必须匹配下列字符串中的一个
// return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
// }
// 4.自定义类型
// cmessage:Person,
},
data() {
return {
}
},
methods: {
},
};
const app = new Vue({
el: "#app",
data: {
message: "你好",
movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
},
components: {
cpn
}
})
</script>
```
## 组件通信
父传子(props的驼峰标识)
v-bind是 不支持使用驼峰标识的,例如`cUser`要改成`c-User`。
```html
<div id="app">
<!-- v-bind不支持驼峰 :cUser改成 :c-User-->
<!-- <cpn :cUser="user"></cpn> -->
<cpn :c-User="user"></cpn>
<cpn :cuser="user" ></cpn>
</div>
<template id="cpn">
<div>
<!-- 使用驼峰 -->
<h2>{{cUser}}</h2>
<!-- 不使用 -->
<h2>{{cuser}}</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
props: { //对象写法
//驼峰
cUser:Object,
//未使用驼峰
cuser:Object
},
data() {return {}},
methods: {},
};
const app = new Vue({
el: "#app",
data: {
user:{
name:'zzz',
age:18,
height:175
}
},
components: {
cpn
}
})
</script>
```
### 子传父`$emit`
子组件向父组件传值,使用自定义事件`$emit`。
```html
<!-- 父组件 -->
<div id="app">
<!-- 不写参数默认传递btnClick的item -->
<cpn @itemclick="cpnClcik"></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
categoties: [{
id: 'aaa',
name: '热门推荐'
},
{
id: 'bbb',
name: '手机数码'
},
{
id: 'ccc',
name: '家用家电'
},
{
id: 'ddd',
name: '电脑办公'
},
]
}
},
methods: {
btnClick(item) {
this.$emit('itemclick', item)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
}
},
methods: {
cpnClcik(item) {
console.log('cpnClick'+item.name);
}
},
components: {
cpn
},
})
</script>
```
1.在子组件中定义一个方法`btnClick(item)`,使用`$emit`,'itemclick'是事件名,`item`是传过去的值。
```javascript
methods: {
btnClick(item) {
this.$emit('itemclick', item)
}
},
```
2.在子组件中监听点击事件并回调此方法
```html
<div>
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
</div>
```
3.在父组件中定义一个方法cpnClcik(item)
```javascript
methods: {
cpnClcik(item) {
console.log('cpnClick'+item.name);
}
},
```
4.并在父组件(vue实例)中调用`<cpn @itemclick="cpnClcik"></cpn>`(*不写参数默认传递btnClick的item* ),父组件监听事件名为`itemclick`的子组件传过来的事件。
```html
<cpn @itemclick="cpnClcik"></cpn>
```
父子组件通信案例
实现父子组件的值双向绑定。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件通信-父子通信案例</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>
<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" >
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2">
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>{{number1}}</h2>
<h2>{{dnumber1}}</h2>
<input type="text" :value="dnumber1" @input="num1input">
<h2>{{number2}}</h2>
<input type="text" :value="dnumber2" @input="num2input">
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
dnumber1:this.number1,
dnumber2:this.number2
}
},
props:{
number1:[Number,String],
number2:[Number,String],
},
methods: {
num1input(event){
this.dnumber1 = event.target.value
this.$emit('num1change',this.dnumber1)
},
num2input(event){
this.dnumber2 = event.target.value
this.$emit('num2change',this.dnumber2)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
num1:1,
num2:2,
}
},
methods: {
num1Change(value){
this.num1=value
},
num2Change(value){
this.num1=value
}
},
components: {
cpn
},
})
</script>
</body>
</html>
```
使用watch实现。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件通信-父子通信案例(watch实现)</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>
<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" >
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2">
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>{{number1}}</h2>
<input type="text" v-model="dnumber1">
<h2>{{number2}}</h2>
<input type="text" v-model="dnumber2">
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
dnumber1:this.number1,
dnumber2:this.number2
}
},
props:{
number1:[Number,String],
number2:[Number,String],
},
watch: {
dnumber1(newValue){
this.dnumber1 = newValue * 100
this.$emit('num1change',newValue)
},
dnumber2(newValue){
this.dnumber1 = newValue * 100
this.$emit('num2change',newValue)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
num1:1,
num2:2,
}
},
methods: {
num1Change(value){
this.num1=value
},
num2Change(value){
this.num1=value
}
},
components: {
cpn
},
})
</script>
</body>
</html>
```
父访问子(children-ref)
父组件访问子组件,有时候我么你需要直接操作子组件的方法,或是属性,此时需要用到`$children`和`$ref`。
```html
<!-- 父组件 -->
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick" >按钮</button>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
我是子组件
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
name:"我是子组件的name"
}
},
methods: {
showMessage(){
console.log("showMessage");
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
message:"hello"
}
},
methods: {
btnClick(){
// 1.children
// console.log(this.$children[0].showMessage)
// for (let cpn of this.$children) {
// console.log(cpn.showMessage)
// }
// 2.$ref
console.log(this.$refs.aaa.name)
}
},
components: {
cpn
},
})
</script>
```
> `$children`方式
```javascript
// 1.children
console.log(this.$children[0].showMessage)
for (let cpn of this.$children) {
console.log(cpn.showMessage)
}
```
使用`this.$children`直接获取**当前实例的直接子组件,需要注意 `$children` 并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 `$children` 来进行数据绑定,考虑使用一个数组配合 `v-for` 来生成子组件,并且使用 Array 作为真正的来源。
> $refs方式
**先定义子组件**
```html
<cpn ref="aaa"></cpn>
```
**直接调用**