vue-2 组件传值

组件关系分类

  1. 父子关系
  2. 非父子关系
    在这里插入图片描述

父子通信流程

在这里插入图片描述

父组件通过props将数据传递给子组件

  1. 给子组件以添加属性的方式传值
  2. 子组件内部通过 props 接收
  3. 模板中直接使用 props 接收的值

在这里插入图片描述
父组件 Parent.vue

<template>
  <div class="parent" style="border: 3px solid #f60202;text-align: center">
    <span>我是 父 组件</span>
    <!-- 1.给组件标签,添加属性方式 赋值 -->
    <div style="text-align: center">
      <Son :title="sonTitle"></Son>
    </div>
  </div>
</template>

<script>
import Son from '@/pages/test/Son.vue'
export default {
  name: 'Parent',
  data() {
    return {
      sonTitle: '父组件传给子组件',
    }
  },
  components: {
    Son,
  },
}
</script>

<style scoped>
.parent {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  height: 300px;
  width: 700px;
}
</style>

子组件 Son.vue

<template>
  <div class="son" style="border:3px solid #000">
    <!-- 3.直接使用 props 的值 -->
    我是 子 组件-- {{title}}
  </div>
</template>

<script>
export default {
  name: 'Son',
  // 2.通过 props 来接收
    props: {
    title: {
      type: String,
      require: true
    }
  }
}
</script>

<style scoped>
.son {
  height: 200px;
  width: 300px;
  margin-left: calc((700px - 300px)/2);
  margin-top: calc((300px - 200px)/2);
  float: left;
}

</style>

子组件利用$emit通知父组件修改更新

  1. $emit 触发事件,给父组件发送消息通知
  2. 父组件监听$emit 触发的事件
  3. 提供处理函数,在函数的性参中获取传过来的参数

在这里插入图片描述

代码省略样式

子组件 Son.vue

<template>
  <div class="son" style="border:3px solid #000">
    <!-- 3.直接使用 props 的值 -->
    我是 子 组件-- {{title}}<br/>
    <button @click="changeFu">修改title</button>
  </div>
</template>

<script>
export default {
  name: 'Son',
  methods: {
    changeFu() {
      // 通过this.$emit向父组件发送通知 名字要保持一致 参数一事件,参数二:参数
      this.$emit('changeTitle','newtitle')
    }
  },
  // 通过 props 来接收
  props: {
    title: {
      type: String,
      require: true
    }
  }
}
</script>

父组件 Parent.vue

<template>
  <div class="parent" style="border: 3px solid #f60202;text-align: center">
    <span>我是 父 组件</span>
    <!-- 1.给组件标签,添加属性方式 赋值 -->
    <div style="text-align: center">
      <Son :title="sonTitle" @changeTitle="handleChange"></Son>
    </div>
  </div>
</template>

<script>
import Son from '@/pages/test/Son.vue'

export default {
  name: 'Parent',
  data() {
    return {
      sonTitle: '父组件传给子组件',
    }
  },
  methods: {
    // 提供处理函数,提供逻辑
    handleChange(newTitle) {
      this.sonTitle = newTitle
    }
  },
  components: {
    Son,
  },
}
</script>

props 示例

<script>
  export default {
    // 完整写法(类型、默认值、非空、自定义校验)
    props: {
      w: {
        type: Number,
        required: true,
        default: 0,
        validator(val) {
          // console.log(val)
          if (val >= 100 || val <= 0) {
            console.error('传入的范围必须是 0-100 之间')
            return false
          } else {
            return true
          }
        },
      },
    },
  }
</script>
  • default 和 required 一般不同时写(因为当时必填项时,肯定是有值的)
  • default后面如果是简单类型的值,可以直接写默认值。如果是复杂类型的值,则需要以函数的形式 return 一个默认值

props & data、单向数据流

共同点:都可以给组件提供数据。
区别:data 的数据是自己的 → 随便改;prop 的数据是外部的 → 不能直接改,要遵循 单向数据流。
单向数据流:父级 props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的。


非父子通信 — event bus 事件总线

非父子组件之间,进行简易消息传递。(复杂场景→ Vuex)

步骤

  1. 创建一个都能访问的事件总线 (空 Vue 实例):
import Vue from 'vue'
const Bus = new Vue()
export default Bus
  1. A 组件(接受方),监听 Bus 的 $on 事件:
created () {
    Bus.$on('sendMsg', (msg) => {
      this.msg = msg
    })
  }
  1. B 组件(发送方),触发 Bus 的$emit 事件:
Bus.$emit('sendMsg', '这是一个消息')

在这里插入图片描述

代码示例

新建 EventBus.js

实例化一个新组件实例并向外暴露,作为兄弟组件传值的媒介:

import Vue from 'vue'
const Bus  =  new Vue()
export default Bus

新建 BaseA.vue(接收方)

<template>
  <div class="base-a">
    我是 A 组件(接受方)
    <p>{{msg}}</p>
  </div>
</template>
<script>
import Bus from '@/pages/test/EventBus'
export default {
  data() {
    return {
      msg: '',
    }
  },
  created() {
    Bus.$on('sendMsg', (msg) => {
      this.msg = msg
    })
  },
}
</script>
<style scoped>
.base-a {
  width: 200px;
  height: 200px;
  border: 3px solid #000;
  border-radius: 3px;
  margin: 10px;
}
</style>

新建 BaseB.vue(发送方)

<template>
  <div class="base-b">
    <div>我是 B 组件(发布方)</div>
    <button @click="sendMsgFn">发送消息</button>
  </div>
</template>

<script>
import Bus from '@/pages/test/EventBus'
export default {
  methods: {
    sendMsgFn() {
      Bus.$emit('sendMsg', '今天天气不错,适合旅游')
    },
  },
}
</script>

<style scoped>
.base-b {
  width: 200px;
  height: 200px;
  border: 3px solid #000;
  border-radius: 3px;
  margin: 10px;
}
</style>

App.vue

<template>
  <div class="app">
    <BaseA></BaseA>
    <BaseB></BaseB>
  </div>
</template>
<script>
import BaseA from "@/pages/test/BaseA.vue";
import BaseB from "@/pages/test/BaseB.vue";

export default {
  components: {BaseB, BaseA}
}
</script>

非父子通信 — provide & inject

作用

跨层级共享数据,不只是父子之间,也可以是祖父与孙子之间,曾祖父与重孙之间……

1、父组件 provide 提供数据

export default {
    provide () {
      return {
         // 普通类型【非响应式】
         color: this.color, 
         // 复杂类型【响应式】
         userInfo: this.userInfo, 
      }
    }
  }

2、子/孙组件 inject 获取数据

export default {
    inject: ['color','userInfo'],
    created () {
      console.log(this.color, this.userInfo)
    }
  }

在这里插入图片描述

传递方式

export default {
  data(){
    return{
      obj:{
        name:'JavaScript',
      },
      developer:'布兰登·艾奇',
      year:1995,
      update:'2021 年 06 月',
    }
  },
  provide(){
    return {
      obj: this.obj, // 方式 1.传入一个可监听的对象
      developerFn:() => this.developer, // 方式 2.通过 computed 来计算注入的值
      year: this.year, // 方式 3.直接传值
      app: this, // 方式 4. 提供祖先组件的实例 缺点:实例上挂载很多没有必要的东西 比如:props,methods。
    }
  }
}

注意

无论点击多少次,孙组件中的诞生于 year 字段永远都是 1995 并不会发生变化,通过 方式 1、方式 2、方式 4 传值是可以响应的。

在孙组件中修改祖组件传递过来的值(方式 1、方式 4),发现对应的祖组件中的值也发生了变化。查看目录爷爷组件一,父组件一,孙组件一

代码示例

爷爷组件 Grandpa.vue

<template>
  <div style="border: #fb0707 3px solid ">
    <button @click="changeMsg">祖组件触发</button>
    <h3>祖组件</h3>
    <Parent></Parent>
  </div>
</template>

<script>
import Parent from '@/pages/test/Parent.vue';
export default {
  data(){
    return{
      obj:{
        name:'JavaScript',
      },
      developer:'布兰登·艾奇',
      year:1995,
      update:'2021 年 06 月',
    }
  },
  provide(){
    return {
      obj: this.obj, // 方式 1.传入一个可监听的对象
      developerFn:() => this.developer, // 方式 2.通过 computed 来计算注入的值
      year: this.year, // 方式 3.直接传值
      app: this, // 方式 4. 提供祖先组件的实例 缺点:实例上挂载很多没有必要的东西 比如:props,methods。
    }
  },
  components: {
    Parent,
  },
  methods:{
    changeMsg(){
      this.obj.name = 'Vue';
      this.developer = '尤雨溪';
      this.year = 2014;
      this.update = '2021 年 6 月 7 日';
    },
  },
}
</script>

父组件 Parent.vue

<template>
  <div class="wrap" style="border: #0759fb 3px solid ">
    <h4>父组件(只做中转)</h4>
    <Son/>
  </div>
</template>

<script>
import Son from '@/pages/test/Son.vue';
export default {
  components:{
    Son,
  },
}
</script>

孙组件 Son.vue

<template>
  <div style="border: #605d5d 3px solid ">
    <h5>孙组件</h5>
    <span>名称:{{obj.name}}</span> |
    <span>作者:{{developer}}</span> |
    <span>诞生于:{{year}}</span> |
    <span>最后更新于:{{this.app.update}}</span>
  </div>
</template>

<script>
export default {
  computed:{
    developer(){
      return this.developerFn()
    }
  },
  inject:['obj','developerFn','year','app'],
}
</script>

爷爷组件一 Grandpa.vue

<template>
  <div style="border: #f60202 3px solid ">
    <h1>祖组件</h1>
    <span>名称:{{obj.name}}</span> |
    <span>最后更新于:{{update}}</span>
    <parent></parent>
  </div>
</template>

<script>
import parent from '@/pages/test/Parent.vue';
export default {
  data(){
    return{
      obj: {
        name: 'JavaScript',
      },
      update: '2021 年 06 月',
    }
  },
  provide() {
    return {
      obj: this.obj,
      app: this,
    }
  },
  components: {
    parent,
  },
}
</script>

父组件一 Parent.vue

不变

孙组件一 Son.vue

<template>
  <div style="border: #656567 3px solid ">
    <button @click="changeMsg">孙组件触发</button>
    <h3>孙组件</h3>
    <span>名称:{{obj.name}}</span> |
    <span>最后更新于:{{this.app.update}}</span>
  </div>
</template>

<script>
export default {
  inject:['obj','app'],
  methods: {
    changeMsg(){
      this.obj.name = 'React';
      this.app.update = '2020 年 10 月';
    }
  },
}
</script>

在这里插入图片描述

总结

慎用 provide / inject
Vuex 和 provide/inject 最大的区别:Vuex 中的全局状态的每次修改是可以追踪回溯的,而 provide/inject 中变量的修改是无法控制的。换句话说,不知道是哪个组件修改了这个全局状态。

相关推荐

  1. vue组件

    2024-06-18 15:32:16       68 阅读
  2. vue3 组建

    2024-06-18 15:32:16       62 阅读
  3. vue中父子组件

    2024-06-18 15:32:16       58 阅读
  4. vue父子组件问题

    2024-06-18 15:32:16       39 阅读
  5. vue3父子组件

    2024-06-18 15:32:16       58 阅读
  6. vue3组件之间通讯

    2024-06-18 15:32:16       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 15:32:16       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 15:32:16       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 15:32:16       82 阅读
  4. Python语言-面向对象

    2024-06-18 15:32:16       91 阅读

热门阅读

  1. 使用爬虫爬取豆瓣电影Top250(方法一)

    2024-06-18 15:32:16       83 阅读
  2. Protobuf详解及入门指南

    2024-06-18 15:32:16       34 阅读
  3. Android的布局有哪些?

    2024-06-18 15:32:16       35 阅读
  4. MySQL触发器基本结构

    2024-06-18 15:32:16       28 阅读
  5. 大文件上传实现

    2024-06-18 15:32:16       28 阅读
  6. 前端BUG记录-a-spin和a-pagination

    2024-06-18 15:32:16       33 阅读
  7. 探索 HNSW:分层导航小世界算法的深度解析

    2024-06-18 15:32:16       33 阅读
  8. 正则表达式 - 在线工具

    2024-06-18 15:32:16       31 阅读
  9. 从史上最惨618看经济趋势

    2024-06-18 15:32:16       27 阅读
  10. 【HarmonyOS NEXT】鸿蒙customScan (自定义界面扫码)

    2024-06-18 15:32:16       30 阅读
  11. mysql中社区版如何查看进程中sql

    2024-06-18 15:32:16       30 阅读