Vue2组件通信

本节目标

  • 相关概念
  • 父子通信
  • 非父子通信
  • v-model
  • .sync修饰符
  • ref / $refs
  • $nextTick

相关概念

组件通信就是指组件与组件之间的数据传递

组件的数据是独立的, 无法直接访问其他组件的数据,

想要其他组件的数据, 就要使用组件通信技术

组件关系

总体来说, 组件分为父子关系 和 非父子关系

通信方案

父与子关系: props & $emit (自定义属性/自定义事件)

非父子关系: provide & inject 或者 eventbus (事件总线)

全局方案: Vuex

父子通信

步骤

  1. 通过自定义属性/自定义事件完成父子通信
  2. 父组件给子组件添加自定义属性并传值
  3. 子组件通过props接收数据
  1. 子组件通过$emit触发父组件的自定义事件
  2. 父组件通过事件参数接收数据

prop详解

prop就是组件上注册的一些自定义属性, 作用就是向子组件传递数据, 组件可以传递任意类型和数量的prop

不同的prop写法有不同的特点, 数组写法最简单, 基础写法可以限制数据类型, 完整写法可以有更多限制规则

1,组组写法:

2,基础写法:

3,完整写法

说明:

  1. 自定校验规则是一个函数, 返回true则通过校验, false则未通过
  2. 未通过教研室, 建议通过console.err() 返回原因, 便于排查

单向数据流

  1. 父级prop的数据更新, 会向下流动, 影响子组件, 这个数据流动是单向的
  2. data的数据是自己的, 可以随便改
  3. pop的数据是外部的, 不能直接改, 要遵循单向数据流
  4. 口诀: 谁的数据谁负责

非父子通信

1>兄弟组件通信

eventbus方案可以在非父子组件之间, 进行消息传递, 核心是利用Vue实例的事件机制

步骤

  1. 创建事件总线 (空的Vue实例) (utils/EventBus.js)
  1. A组件(接收方), 监听Bus实例的事件
  1. B组件(发送方), 触发Bus实例的事件

2>子孙组件通信

provide & inject 可以实现跨层级的数据共享

步骤

  1. 父组件通过peovide属性提供数据
  1. 子孙组件通过inject属性获取数据

v-model

v-model本质上是一个语法糖, 例如应用在输入框上, 就是value属性 和 input事件的合写

除了进行表单的双向数据绑定, 也可以实现父子组件通信 (简化表单组件的封装)

1>v-model原理

  1. 实现表单数据双向绑定,

  2. 数据变, 视图跟着变 :value

  3. 视图变, 数据跟着变 @input

  4. 在模版中获取事件对象的形参, 使用$evnet

    <template>
    复制代码
     <!-- 拆解v-model手动实现数据双向绑定 -->
     <input :value="msg2" @input="msg2 = $event.target.value"  type="text">
    </template> <script> export default { data() { return { msg1: '', msg2: '', } }, } </script>

2>封装表单组件

表单类组件封装, 最直接的方式就是使用父子组件通信技术

  1. 父传子: 数据应该是父组件 props 传递过来的
  2. 子传父: 监听输入, 子组件传值给父组件修改数据
  3. 最终实现了父子组件的数据双向绑定
  4. 右侧为效果图 ->_->

示例

复制代码
<template>
  <div class="app">
    <!--@change可以写行内, 便于理解这里不再简化 -->
    <BaseSelect :cityId="selectId" @change="handleChange"></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
  methods: {
    handleChange(e) {
      console.log('父组件拿到子组件选中的值', e);
      this.selectId = e
    }
  }
}
</script>

<template>
  <div>
    <!--这里不能使用v-model, 因为prop是只读的 -->
    <!--@change可以写行内, 便于理解这里不再简化 -->
    <select :value="cityId" @change="hander">
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
  props: {
    cityId: String
  },
  methods: {
    hander(e) {
      console.log('子组件选中的值', e.target.value);
      this.$emit('change', e.target.value)
    }
  }
}
</script>

3>简化表单组件

使用v-model简化表单组件的封装

  1. 改造子组件: props必须使用value接收, 事件触发必须使用input

  2. 简化父组件: 可以使用 v-model 给组件直接绑定数据

  3. 组件的封装步骤不变, 只是子组件的参数命名有了限制, 但是简化了组件的使用, 非常推荐

    <template>
    <select :value="value" @change="$emit('input', $event.target.value)"> <option value="101">北京</option> <option value="102">上海</option> <option value="103">武汉</option> <option value="104">广州</option> <option value="105">深圳</option> </select>
    </template> <script> export default { props: { // 必须通过value接收数据 value: String }, } </script> <template>
    <BaseSelect v-model="selectId"></BaseSelect>
    </template> <script> import BaseSelect from './components/BaseSelect.vue' export default { data() { return { selectId: '102', } }, components: { BaseSelect, }, } </script>

.sync修饰符

使用**.sync**实现父子组件的双向绑定, 简化代码

  1. 特点: prop属性名, 可以自定义, 非固定value

  2. 场景: 封装弹框类的基础组件, visible属性 true显示 false隐藏

  3. 本质: 就是 :属性名 和 @update:属性名 合写

  4. 对比: 相比如v-model简化代码, .sync简化代码时属性名更灵活

  5. 表单类的组件使用v-model简化, 弹窗类的组件使用.sync简化

    <template>
    <BaseDialog :visible.sync="isShow"></BaseDialog> <BaseDialog :visible="isShow" @update:visible="isShow = $event"></BaseDialog>
    </template> <script> export default { data() { return { isShow: true, } }, } </script> <template>

    温馨提示:

    <button @click="close" class="close">x</button>

    你确认要退出本系统么?

    <button @click="close">确认</button> <button>取消</button>
    </template> <script> export default { // 1,接收数据 props: { visible: Boolean }, methods: { close() { // 3, 通知父组件修改数据 // 使用.sync后,这里的触发格式为: update:属性名 this.$emit('update:visible', false) } }

    }
    </script>

ref / $refs

利用ref 和 $refs 可以用于获取DOM元素 或 组件实例

  1. 使用 document.querySelector() 等方法获取DOM, 是在整个HTML页面查找
  2. 使用 $refs 获取DOM, 只在当前组件内查找, 更加精准和稳定
  3. 获取DOM: <div ref="boxRef">我是容器</div>
  4. 获取DOM: this.$refs.BoxRef
  5. 获取组件实例: <sum ref="sumRef"><sum>
  6. 调用组件方法: this.$refs.sumRef.组件方法()
  7. 通过组件实例获取组件数据, 组件的方法要将数据return返回

$nextTick

Vue采用异步更新DOM的方案 (提升性能), 如果要保证本轮DOM更新后, 操作最新的DOM, 使用$nextTick

语法: this.$nextTick(函数体)

相比延时器更加准确可靠

相关推荐
恋猫de小郭8 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端