【Vue】props完整语法 && 非父子组件通信 && provide && inject && eventBus

文章目录

  • [Ⅰ. props完整语法](#Ⅰ. props完整语法)
  • [Ⅱ. 非父子组件通信](#Ⅱ. 非父子组件通信)

Ⅰ. props完整语法

一、语法

javascript 复制代码
defineProps({
  属性名: {
    type: 类型,       // Number、String、Boolean ...
    required: true,  // 是否必填
    default: 默认值,  // 默认值
    
    // value: 父传子的值
    validator (value) {
      // 自定义校验逻辑,比如判断value的范围
      return 布尔值
    }
  }
})
  1. default 和 required 最好不要同时写(因为当 required=true 时,默认值也就无效了)
  2. default 后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式 return 一个默认值

二、代码示例

App.vue文件:

javascript 复制代码
<template>
    <MyProgress :width="20"/>
    <MyProgress :width="50"/>
    <MyProgress />
    <MyProgress :width="-10"/>
    <MyProgress :width="210"/>
</template>

<script setup>
    import MyProgress from './components3/MyProgress.vue';
</script>

<style scoped></style>

MyProgress.vue文件:

javascript 复制代码
<script setup>
    defineProps({
        width: {
            type: Number,
            required: false,
            default: 50,

            validator(value) {
                // 控制范围
                if(value < 0 || value > 100) {
                    return false;
                }
                return true;
            }
        }
    })
</script>

<template>
  <div class="my-progress">
    <div
      class="inner"
      :style="{width : width + '%'}">
      <span>{{ width }}%</span>
    </div>
  </div>
</template>

<style scoped>
.my-progress {
  height: 26px;
  width: 400px;
  border-radius: 15px;
  background-color: #272425;
  border: 3px solid #272425;
  box-sizing: border-box;
  margin-bottom: 30px;
}
.inner {
  position: relative;
  background: #379bff;
  border-radius: 15px;
  height: 25px;
  box-sizing: border-box;
  left: -3px;
  top: -2px;
}
.inner span {
  position: absolute;
  right: -30px;
  top: 26px;
}
</style>

三、ref/reactive 与 props 的区别

特性 ref reactive props
定义位置 组件内部 组件内部 由父组件传入
数据类型 基本类型/单值 对象/数组 任意类型
是否响应式 ✅ ✅ ✅(来自父)
能否修改 ✅(.value) ✅ ❌(建议复制副本修改)
模板使用 自动解包({{ count }}) 直接访问({{ state.age }}) 直接访问({{ title }})

Ⅱ. 非父子组件通信

一、祖先传后代:provide && inject

祖先组件通过 provide 给后代提供数据:

javascript 复制代码
import { provide } from 'vue'
provide('数据名称', 值)

后代组件通过 inject 获取到祖先提供的数据:

javascript 复制代码
import { inject } from 'vue'
const value = inject('数据名称')

下面举个例子,模拟三代中祖先传给孙子的情况:

App.vue文件:

javascript 复制代码
<template>
<div class="app">
    <h3>我是祖先组件</h3>
    <my-parent />
</div>
</template>

<script setup>
    import { provide, ref } from 'vue';
    import MyParent from './components5/MyParent.vue';
    
    const money = ref(520)
    provide('rmb', money)
</script>

<style scoped>
    .app {
        background-color: aqua;
        padding: 20px;
    }
</style>

components5/MyParent.vue文件:

javascript 复制代码
<template>
    <div class="my-parent">
        <h3>我是父组件</h3>
        <my-child />
    </div>
</template>

<script setup>
    import MyChild from './MyChild.vue';
</script>

<style scoped>
    .my-parent {
        padding: 20px;
        background-color: chartreuse;
    }
</style>

components5/MyChild.vue文件:

javascript 复制代码
<template>
    <div class="my-child">
        <h3>我是子组件</h3>
        <p>收到爷爷的压岁钱:{{ money }}</p>
    </div>
</template>

<script setup>
    import {inject} from 'vue'

    const money = inject('rmb')
</script>

<style scoped>
    .my-child {
        background-color: blanchedalmond;
        padding: 20px;
    }
</style>

二、任意两个组件通信:eventBus

首先下载 mitt 模块包:

javascript 复制代码
npm install --save mitt

然后创建公共中间人模块(类似媒婆和中介),即创建一个 eventBus.js 文件:

javascript 复制代码
// 导入中介模块
import mitt from 'mitt'

// 通过 mitt() 拿到中介
const meipo = mitt()

// 默认导出:目的是给别的组件拿到 meipo 中间人
export default meipo

接着按照以下步骤走:

  1. 消息发送方: 使用 meipo.emit('消息名称', 数据) 发送消息
  2. 消息接收方: 使用 meipo.on('消息名称', (数据) => { 处理消息代码块 }) 接收消息并进行处理

举个例子:

App.vue文件:

javascript 复制代码
<template>
<div class="app">
    <my-left />
    <my-right />
</div>
</template>

<script setup>
    import MyLeft from './components6/MyLeft.vue';
    import MyRight from './components6/MyRight.vue';
</script>

<style scoped>
 .app {
    display: flex;
    align-items: center;
    justify-content: center;
 }
</style>

eventBus.js文件:

javascript 复制代码
import mitt from 'mitt'

// 拿到中介
const meipo = mitt()

// 默认导出:目的是给别的组件拿到 meipo 中间人
export default meipo

components6/MyLeft.vue文件:

javascript 复制代码
<template>
<div class="my-left">
    <p>我是左组件</p>
    <button @click="sendMsg">点击我发送消息给右组件</button>
</div>
</template>

<script setup>
    import { ref } from 'vue';
    import meipo from './eventBug';

    const text = ref('i like you~')

    const sendMsg = () => {
        // 发送方调用emit()发送消息
        meipo.emit('msg', text.value)
    }
</script>

<style scoped>
    .my-left {
        flex: 1;
        background-color: antiquewhite;
        text-align: center;
        height: 100px;
    }
</style>

components6/MyRight.vue文件:

javascript 复制代码
<template>
<div class="my-right">
    <p>我是右组件</p>
</div>
</template>

<script setup>
    import meipo from './eventBug';

    // 接收方调用 on() 接收消息并且进行处理
    meipo.on('msg', (text) => {
        console.log(text);
    })
</script>

<style scoped>
    .my-right {
        flex: 1;
        background-color: palegreen;
        text-align: center;
        height: 100px;
    }
</style>
相关推荐
Csvn18 小时前
WASM
前端
修己xj19 小时前
我用 AI 给自己写了一个 Markdown 编辑器,然后把它开源了
前端
FRing0319 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
幸运小猿20 小时前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
moshuying21 小时前
网购能买Token了!
前端
h_654321021 小时前
echarts实现柱状图加一条横线
前端·echarts
风骏时光牛马1 天前
生成一个后端标题,只需要一个标题,不需要其他的任何文本。
前端
子非鱼@Itfuture1 天前
关于前后端联调中登录状态/登录信息失效?
java·前端
郭小李1 天前
openFeign入门
java·开发语言·前端
馒头不想说话1 天前
AI当运营,帮你省人力
前端