父与子通信

父组件如何向子组件传递数据?使用`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>
```

 

**直接调用**

 

posted @ 2021-04-26 10:20  好吗,好  阅读(49)  评论(0)    收藏  举报