清茶书香

一杯清茶,一本书籍,一个下午。


  • 首页

  • 归档

  • 分类

  • 关于

  • 搜索
Redis JPA Solr SpringData SpringMVC localRepository local Mapper 事务 Mybatis JDBC AOP DI IOC 常用函数 触发器 存储过程 Promise Gateway SpringCloud vue-cli axios es6 webpack npm vue 个性化 zsh 终端 caffeine jvm缓存 guava cache validation Mapping MapStruct comment 小程序 建站 WeHalo config logback plugins database idea maven spring https http nginx password RabbitMQ 秒杀系统 Windows MySQL 数据备份 halo SpringBoot shell Linux ip Optional Stream Lambda k8s Docker 列编辑 vim MacOS 图片合成 Java 远程联调 nps 内网穿透

vue学习记录之组件间通信

发表于 2021-12-16 | 分类于 vue | 0 | 阅读次数 465

在组件之间进行传递数据一般可以通过props从父组件向子组件传递,用自定义事件的方式从子组件向父组件传递数据。

父传子props

之前模版语法中也演示过一次props的作用,这里再详细的介绍一下props。

通过props你可以传递各种类型的数据,你可以直接传递一个静态的数据,也可以传递动态获取的数据。

传递静态数据

<!-- 传递静态的字符串 -->
<comp msg="this is a static message"></comp>

<!-- 传递静态的布尔类型数据(子组件的props也要指定类型为Boolean) -->
<comp is-success></comp>
<comp :is-success="true"></comp>

<!-- 传递静态的数组类型数据(数组、对象等类型虽然数据是静态的,但为了让Vue知道是数组类型而不是字符串就必须是v-bind来告知Vue这是一个js表达式) -->
<comp :book-ids="[111,222,333]"></comp>

tips: 在html中标签的属性不区分大小写,因此使用时camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 。

传递动态数据

传递动态数据都需要使用v-bind或者:来动态赋值。

<!-- 传递动态的字符串 -->
<comp :msg="comp.msg"></comp>

<!-- 传递动态的布尔类型数据 -->
<comp :is-success="comp.isSuccess"></comp>

<!-- 传递动态的数组类型数据 -->
<comp :book-ids="comp.bookIds"></comp>

props的定义以及类型检查

props的定义

你可以通过字符串数据的方式定义子组件中的props。

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

也可以像Java等语言一样单独为一个属性定义类型,这种方式看上去会更加具有可读性。

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // 或任何其他构造函数
}

props的类型检查

  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' }
      }
    },
    // 自定义验证函数
    propF: {
      validator(value) {
        // 这个值必须与下列字符串中的其中一个相匹配
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组的默认值不同,这不是一个工厂函数——这是一个用作默认值的函数
      default() {
        return 'Default function'
      }
    }
  }

自定义构造函数类型,此举可以让你知道这个属性是否是通过new的方式创建出来的(一般不怎么用)。

export class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

// es6之前的语法
// function Person(firstName, lastName) {
//   this.firstName = firstName
//   this.lastName = lastName
// }

export default {
  name: "Test",
  props: {
    customProp: {
      type: Person
    }
  }
}
<template>
  <test :custom-prop="customProp"/>
</template>

<script>
import Test from "@/components/Test";
import {Person} from "@/components/Test";

export default {
  name: 'App',
  components: {
    Test
  },
  data() {
    return {
      customProp: new Person('abc', 'sdj')
    }
  }
}
</script>

数据子传父

Vue有个自定义事件的功能,我们可以通过自定义事件的方式把子组件的数据传递给父组件。

// 可以在子组件的一个事件函数中使用$emit函数传递数据
this.$emit('myEvent', 123)

// 父组件中使用自定义定义的事件(同样的驼峰转连接符)
<my-component @my-event="myEvent"></my-component>


// ... 父组件中的myEvent函数接收的参数就是子组件中传递的数据
myEvent(data) {
// data就是子组件传递过来的数据
}

更多关于自定义事件的使用,可查阅官方文档自定义事件

父子组件相互访问

Provide / Inject

针对多层组件引用,比如app->subApp->demo1->demo2->demo3想要使用app组件中的某些方法或者属性,就可以使用一对Provide/Inject来达到目的,无论层次有多深都可以使用这一对。

// ... App组件
export default {
  name: "Test"
  components: {
    SubApp
  },
  data() {
    return {
      user: 
    }
  },
  provide: {
    user: 'Bennett'
  }
}
// ... demo3组件
export default {
  name: "Test",
  inject: ['user'],
  created() {
     // this.user is Bennett
     console.log(this.user);
  }
}

上面的provide中的user属性只能给后代组件使用,本身使用不到,demo3要想访问到实例中的属性或函数就需要使用provide()返回一个对象的形式才可以。

// ... App组件
export default {
  name: "Test"
  components: {
    SubApp
  },
  data() {
    return {
      user: 
    }
  },
  provide() {
    return {
      user: this.user
    }
  }
}

注意⚠️inject的数据并不会随着provide中的数据改变而改变,要想做到响应式就需要返回的数据是通过computed包装过的计算属性。

// ... App组件
export default {
  name: "Test"
  components: {
    SubApp
  },
  data() {
    return {
      user: 
    }
  },
  provide() {
    return {
      user: Vue.computed(() => this.user);
    }
  }
}

使用实例属性访问

Vue为所有的组件都提供了以下几个属性:

  • $data: 当前实例的数据对象
  • $props: 当前实例接收到的props对象
  • $el: 组件实例正在使用的根 DOM 元素(不推荐直接使用$el,推荐在使用模版引用)
<input ref="customInput" />

之后可通过this.$refs.customInput.focus()触发focus事件。

  • $options: 用于当前组件实例的初始化选项。当你需要在选项中包含自定义property时会有用处。
const app = createApp({
  customOption: 'foo',
  created() {
    console.log(this.$options.customOption) // => 'foo'
  }
})
  • $parent: 父实例,如果当前实例有的话。
  • $root: 当前组件树的根组件实例。如果当前实例没有父实例,此实例将会是其自己。
  • $slots: 用来以编程方式访问通过插槽分发的内容。每个具名插槽都有其相应的property(例如:v-slot:foo中的内容将会在this.$slots.foo()中被找到)。
  • $refs: 一个对象,持有注册过refattribute 的所有 DOM 元素和组件实例。
  • attrs: 包含了父作用域中不作为组件props或自定义事件的attribute绑定和事件。

父组件访问子组件数据

可以用上面的this.$refs.customRefName.componentData访问到customRefName子组件的componentData。这个需要依赖于$refs和模版引用组合使用。

<custom-component ref="customComponent"></custom-component>
<custom-component></custom-component>


export default {
  name: "Test",
  components: {
   CustomComponent
  },
  methods: {
    demoMethod() {
      // 访问第一个CustomComponent组件中的componentData属性、componentMethod方法
      console.log(this.$refs.customRefName.componentData)
      console.log(this.$refs.customRefName.componentMethod)
    }
  }
}

子组件访问父组件数据

这个可直接使用$parent访问到父组件实例中的内容,比如:

// 访问父组件中的demo属性、demoMethod方法
this.$parent.demo;
this.$parent.demoMethod();

// 访问父组件的父组件的demo属性、demoMethod方法(没有provide/inject好用)
this.$parent.$parent.demo;
this.$parent.$parent.demoMethod();


// 访问根组件中的属性和方法
this.$root.demo;
this.$root.demoMethod();

可见如果层级太深就比较麻烦,如果是子组件访问父组件还好,反过来就麻烦了。这就需要到vue官方提供的vuex组件了,这个后面再说。

Bennett wechat
欢迎收藏我的微信小程序,方便查看更新的文章。
  • 本文作者: Bennett
  • 本文链接: https://hibennett.cn/archives/study-components-communicate
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# vue
日志查看相关操作
vue学习记录之vue插槽slot
  • 文章目录
  • 站点概览
Bennett

Bennett

60 日志
28 分类
74 标签
RSS
Github E-mail Gitee QQ
Creative Commons
Links
  • MacWk
  • 知了
0%
© 2020 — 2023 hibennett.cn版权所有
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4

浙公网安备 33010802011246号

    |    浙ICP备2020040857号-1