vue2 父子组件传值
发表于 2023-11-10 | | 开发笔记

1.父组件向子组件传递数据

-- Props + $emit( )

我们在父组件(Parent.vue)中定义一个 name 数据,通过 v-bind 指令将 name 重命名为 parentName 传递给子组件

<template>
  <h1>父组件</h1>
  <p>{{ name }}</p>
  <Child :parentName="name"></Child>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    data() {
      return {
        name: '周帅帅'
      }
    }
  }
</script>

我们在子组件(Child.vue)中使用 props 方法接收父组件传递的参数 parentName,除了接收值为数组外,接收值还可以为对象,并且还可以设置默认值

<template>
  <div>我是子组件</div>
  <p>{{ parentName }}</p>
</template>
<script>
  export default {
    // 还可以定义接收的类型
    // props: { parentName: { type: String, default: '' } }
    props: ['parentName'],
  }
</script>

2.子组件向父组件传递数据

我们在子组件(Child.vue)中添加 button 按钮, 点击时我们使用 $emit() 的方式将 handleClick 事件重命名为 childMessage 方法传递给父组件

<template>
  <div>我是子组件</div>
  <p>{{ parentName }}</p>
  <button @click="handleClick">按钮</button>
</template>
<script>
  export default {
    props: ['parentName'],
    methods: {
      handleClick() {
        this.$emit('childMessage', '子组件的值')
      }
    }
  }
</script>

我们在父组件(Parent.vue)接收子组件(Child.vue)传递的 childMessage 方法,并重新命名为 parentClick 方法,并将子组件传递在 $event 的值赋值给 name,这样我们发现父组件中的 name 值发生了改变。

<template>
  <h1>父组件</h1>
  <p>{{ name }}</p>
  <Child :parentName="name" @parentClick="childMessage"></Child>
  <!-- 下面的这行代码和上面代码意思是一样的 -->
  <!-- <Child :parentName="name" @childMessage="name = $event"></Child> -->
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    data() {
      return {
        name: '周帅帅'
      }
    },
    methods: {
      parentClick($event) {
        this.name = $event
      }
    }
  }
</script>

使用回调函数(callback)方式
我们在父组件(Parent.vue)中定义一个 changeMessage 来修改 name 的值,然后将 parentClick 方法和 parentName 的值传递给子组件(Child.vue)

<template>
  <h1>父组件</h1>
  <div>{{ name }}</div>
  <Child :parentName="name" :parentClick="changeMessage"></Child>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    data() {
      return {
        name: '周帅帅'
      }
    },
    methods: {
      changeMessage() {
        this.name = 'web前端'
      }
    }
  }
</script>

我们在子组件(Child.vue)通过 props 接收父组件传递的 msg 和 parentClick 方法

<template>
  <h1>我是子组件</h1>
  <p>{{parentName}}</p>
  <button @click="parentClick">按钮</button>
</template>
<script>
  export default {
    props: ['parentName', parentClick],
  }
</script>

这样当我们点击按钮的时候,发现父组件中的 name 和子组件中的 parentName 都会发生改变。

3、$children + $parent

我们在父组件(Parent.vue)通过 this.$children[0].age 获取子组件(Child.vue)中 age 的值并修改为50

<template>
  <h1>父组件</h1>
  <p>{{ name }}</p>
  <Child @click="changeChildAge">按钮</Child>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    data() {
      return {
        name: '周帅帅'
      }
    },
    methods: {
      changeChildAge() {
        // 因为子组件可能存在多个,所以加了一个下标0
        this.$children[0].age = 50;
      }
    }
  }
</script>

我们在子组件(Child.vue)通过 this.$parent.message 获取父组件中的值,并在子组件中展示出来

<template>
  <div>
    <div>我是子组件</div>
    <p>{{ age }}</p>
    <p>{{ parentName }}</p>  
  </div>
</template>
<script>
  export default {
    data() {
      return {
        age: 10
      }
    },
    computed: {
      parentName() {
        return this.$parent.name
      }
    }
  }
</script>

所以在子组件(Child.vue)中可以显示父组件的 name 值,当父组件中的按钮点击时,子组件(Child.vue)中 age 的值会从10变成50

4、provide + inject

我们在父组件(Parent.vue)里面通过 provide 提供一个 message 的值

<template>
  <h1>父组件</h1>
  <Child></Child>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    provide: {
      name: '周帅帅'
    }
  }
</script>

子组件(Child.vue)中通过 inject 接收父组件(Parent.vue)中传递的值

<template>
  <div>
    <h1>子组件</h1>
    {{ name }}
  </div>
</template>

<script>
  export default {
    inject: ['name']
  }
</script>

这样我们可以在子组件(Child.vue)中看到父组件中定义的 name 值

5、$attrs + $listeners

我们在父组件(Parent.vue)中向子组件(Child.vue)传递 name 和 age,我们在父组件(Parent.vue)中定义了一个 parentName 事件监听器

<template>
  <h1>父组件</h1>
  <p>姓名:{{ name }}</p>
  <p>年龄:{{ age }}</p>
  <Child :name="name" :age="age" @parentName="changeName"></Child>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    data() {
      return {
        name: '周帅帅',
        age: 24
      }
    },
    methods: {
      changeName() {
        this.name = '小夏'
      }
    }
  }
</script>

我们在子组件(Child.vue)中可以通过 $listeners 获取到父组件(Parent.vue)中的 parentName,这样我们就能执行父组件(Parent.vue)中绑定的事件处理函数(changeName)。然后我们在子组件(Child.vue)里面引入孙子组件(GrandChild.vue),将父组件(Parent.vue)传递给子组件(Child.vue)的 name 和 age 通过 v-bind="$attrs" 传递给孙子组件(GrandChild.vue)。

<template>
  <div>
    <h1>子组件</h1>
    <button @click="$listeners.parentName">按钮</button>
    // $attrs相当于子组件向孙子组件传递:name="name" :age="age"
    <GrandChild v-bind="$attrs"></Child>
  </div>
</template>
<script>
  import GrandChild from './GrandChild.vue';
  export default {
    components: {
      GrandChild,
    },
    data() {
      return {

      }
    }
  }
</script>

这样我们在孙子组件(GrandChild.vue)中就可以接收子组件(Child.vue)传递过来的 name 和 age 了。然后通过 $attrs.name 和 $attrs.age 来使用。

<template>
  <div>
    <h1>孙子组件</h1>
    <p>姓名:{{ $attrs.name }}</p>
    <p>年龄:{{ $attrs.age }}</p>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        // 如果不加这个属性,我们发现div中会携带name和age这两个属性
        inheritAttrs: false
      }
    }
  }
</script>

6、ref 我们在父组件(Parent.vue)中给引入子组件(Child.vue),并且给子组件(Child.vue)中定义一个 ref 为childName 的值。

<template>
  <h1>父组件</h1>
  <Child ref="childName"></Child>
  <button @click="changeName">按钮</button>
</template>
<script>
  import Child from './Child.vue';
  export default {
    components: {
      Child,
    },
    methods: {
      changeName() {
        console.log('修改前', this.$refs.childName.name)
        this.$refs.childName.changeName()
        console.log('修改后', this.$refs.childName.name)
      }
    }
  }
</script>

我们在子组件(Child.vue)中定义一个 changeName 的方法

<template>
  <div>
    <h1>子组件</h1>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        name: '周帅帅'
      }
    },
    methods: {
      changeName() {
        this.name = '前端程序员'
      }
    }
  }
</script>

这样当我们点击父组件(Parent.vue)中的按钮时,我们在浏览器的控制台就可以看到打印的值发生了变化。

几种父子传递方法的区别
props
props 只能用于父组件传递给子组件的时候区使用。

provide与inject?
我们使用 provide 和 inject 进行传值可以在父子组件中传递,也可以将父子组件的传递的值在孙子组件中接收,例子在下面。

举个例子
父组件(Parent.vue)里调用了子组件(Child.vue),同时子组件(Child.vue)里调用了孙子组件(GrandChild.vue)

区别

父组件(Parent.vue)可以用 props 方法直接传数据给子组件(Child.vue),但不能传数据给孙子组件(GrandChild.vue)
父组件(Parent.vue)可以用 provide 与 inject 方法直接传递数据给子组件(Child.vue),也可以直接给孙子组件(GrandChild.vue)

发表评论:

TOP