VUE3(四)、组件通信

1、props

作用:子组件之间的通信。

父传子:属性值的非函数。

子传父:属性值是函数。

父组件:

html 复制代码
<template>
    <div>{{ childeData }}</div>
    ------------------------------------------------------------------------------------------
    <child :parentData="parentData" :sendData="getChildData"/>
</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import child from './childeIndex.vue'

const childeData=ref("");
const parentData=ref("parentData");

function getChildData(data:string){
    childeData.value=data;
}

</script>

子组件:

html 复制代码
<template>
    <div>{{ parentData }}</div>
    <button @click="sendData(data)"></button>
</template>
<script setup lang="ts" name="child">
import { ref } from 'vue'
defineProps(['parentData','sendData'])

const data=ref('aaa')

</script>

2、自定义事件

通过父组件定义函数,子组件调用父组件的函数来实现参数的传递。

父组件:

html 复制代码
<template>
    <div>{{ childeData }}</div>
    ------------------------------------------------------------------------------------------
    <child @send-toy="getChildData"/>
</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import child from './childeIndex.vue'

const childeData=ref("");

function getChildData(data:string){
    childeData.value=data;
}

</script>

子组件:

html 复制代码
<template>
    <div>子组件</div>
    <button @click="sendDat"></button>
</template>
<script setup lang="ts" name="child">
    import { ref } from 'vue'
    let data=ref('我是子组件')
    const emit = defineEmits(['send-toy'])
    function sendDat(){
        emit('send-toy',data)
    }

</script>

3、mitt

实现任意组件的通信。个人理解:在组件与组件之间提供了一个平台,都向这个平台发送、读取数据。

安装步骤:

  1. npm i mitt
  2. 新建文件utiles/emitter.ts
  3. 在需要的文件中引入emitter,进行绑定 事件,或调用事件。
  4. 在文件中进行解绑(unmounted中)

emitter.ts

javascript 复制代码
import mitt from 'mitt'
const emitter=mitt()
export default emitter

获取数据的文件

html 复制代码
<template>
    <h2>child2中的数据:{{ src }}</h2>
</template>
<script setup lang="ts" name="child1">
    import { onUnmounted, ref } from 'vue'
    import emitter from '@/utils/emitter'

    const src=ref('')

    //监听事件
    emitter.on('getData',(data:string)=>{
        src.value=data
    })

    //在组件销毁时取消监听
    onUnmounted(()=>{
        emitter.off('getData')
    })
</script>

发送数据的文件

html 复制代码
<template>
    <h2>child2的数据:{{ data }}</h2>
    <button @click="getdata"> 点击获取数据 </button>
</template>
<script setup lang="ts" name="child2">
    import { ref } from 'vue'
    import emitter from '@/utils/emitter'

    const data = ref('222')
    function getdata(){
        emitter.emit('getData',data)
    }
</script>

4、v-model

原理:实现双向绑定,通过传递props参数实现父传子,通过emit传递input或者点击事件实现子传父。

父组件:

html 复制代码
<template>
    <!-- 这个写法的本质就是下面那种 -->
    <input type="text" v-model="str"/>
    <input type="text" :value="str" @input="str=(<HTMLInputElement>$event.target).value"/>

    <!-- 自定义组件,一二种方法一致 -->
    <selfInput v-model="str"></selfInput>
    <!-- 此处的$event就是传递的数据 -->
    <selfInput :modelValue="str" @update:modelValue="str=$event"></selfInput>

</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import selfInput from './selfInput.vue';

let str = ref('');
</script>

自定义组件(selfInput.vue):

html 复制代码
<template>
    <input type="text" :value="modelValue" @input="emit('update:modelValue',($event.target as HTMLInputElement).value)"/>
</template>
<script setup lang="ts" >
import { ref,defineProps,defineEmits } from 'vue';

defineProps(['modelValue'])

const emit = defineEmits(['update:modelValue'])

</script>

如果自定义自定义组件中的名称,可以实现多个组件的双向绑定。

父组件:

html 复制代码
<template>

     {{ str }} --------{{ pass }}
    <selfInput v-model:name="str" v-model:pass="pass"></selfInput> 
</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import selfInput from './selfInput.vue';

let str = ref('');
let pass = ref('');
</script>

子组件:

html 复制代码
<template>
    <input type="text" :value="name" @input="emit('update:name',($event.target as HTMLInputElement).value)"/>
    <input type="text" :value="pass" @input="emit('update:pass',($event.target as HTMLInputElement).value)"/>
</template>
<script setup lang="ts" >
import { ref,defineProps,defineEmits } from 'vue';

defineProps(['name','pass'])

const emit = defineEmits(['update:name','update:pass'])

</script>

5、$attrs

作用:适用于当前组件,向子组件通信(祖-->孙)。

当父组件给子组件传递参数,且子组件没有使用props进行接收时,所传递的参数存在attrs中。在子组件中使用$attrs就可以获取所有未被接收的数据。

父组件:

html 复制代码
<template>
    <div>{{ a }}</div><hr/>
    <div>{{ b }}</div><hr/>
    <div>{{ c }}</div><hr/>
    <child v-bind="{a,b,c}" @changeA="changeA"></child>
</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import child from './chile.vue';
let a=ref(1);
let b=ref(2);
let c=ref(3);
function changeA(value:number){
    a.value=value;
}
</script>

子组件:

html 复制代码
<template>
    <div>{{ a }}</div><hr/>
    --------------------------------
    <sun v-bind="$attrs"></sun>
</template>
<script setup lang="ts" name="chile">
    import sun from './sun.vue'
    defineProps(['a'])
</script>

孙组件:

html 复制代码
<template>
    <div>{{ b }}</div><hr/>
    <div>{{ c }}</div><hr/>
    <button @click="changeAa">修改a</button>
</template>
<script setup lang="ts" >
    const num=defineProps(['b','c']);
    const emit=defineEmits(['changeA']);
    function changeAa(){
        emit('changeA',num.b);
    }
</script>

6、refs、parent

$refs:用于父组件修改子组件中的数据。获取所有子组件暴露的数据。

$parent:用于子组件修改父组件的数据。获取父组件所有暴露的数据。

以上的前提:使用defineExpose暴露数据。

父组件:

html 复制代码
<template>
    <h1>父组件数据</h1>
    <h1>{{ a }}</h1>
    <button @click="changeChildeA($refs)">修改子组件数据</button><br/>
    --------------------------------
    <child1 ref="child1"/>
    --------------------------------
    <child2 ref="child2"/>
</template>
<script setup lang="ts" name="parentIndex">
import { ref } from 'vue';
import child1 from './childe1.vue';
import child2 from './childe2.vue';
let a=ref(1);
function changeChildeA(refs:any){
    refs.child1.b++;
    refs.child2.b++;
}
defineExpose({a})
</script>

子组件1:

html 复制代码
<template>    
    <h1>子组件数据</h1>
    <h1>a:{{ a }}</h1>
    <h1>b:{{ b }}</h1>
    <button @click="changeParent($parent)">修改父组件的a</button>
</template>
<script setup lang="ts" >
import { ref } from 'vue'
let a=ref(1)
let b=ref(1)
function changeParent(parent:any){
    parent.a++
}
//暴露
defineExpose({
    b
})
</script>

子组件2:

html 复制代码
<template>    
    <h1>子组件数据</h1>
    <h1>a:{{ a }}</h1>
    <h1>b:{{ b }}</h1>
</template>
<script setup lang="ts" >
import { ref } from 'vue'
let a=ref(1)
let b=ref(1)

//暴露
defineExpose({
    a,
    b
})
</script>

7、provide、inject

作用:实现祖孙组件之间的数据传递。

传递数据:provide("数据名称",数据)。

接收数据:inject("数据名称",默认值)。

父组件:

html 复制代码
<template>
    <h1>父组件数据</h1>
    <h1>{{ a }}</h1>
    --------------------------------
    <child1 ref="child1"/>
</template>
<script setup lang="ts" name="parentIndex">
import { ref,provide } from 'vue';
import child1 from './childe1.vue';

let a=ref(0);
function changeA(value:number){
    a.value+=value;
}

provide("parent",{a:a,changeA})

</script>

子组件:

html 复制代码
<template>    
    <h1>子组件数据</h1>
    <h1>a:{{ a }}</h1>
    <div><button @click="changeA(1)">更改父组件的a</button></div>
</template>
<script setup lang="ts" >
import { ref,inject } from 'vue'
let {a,changeA} = inject('parent',{a:ref(0),changeA:function(x:number){}})
</script>

8、插槽

作用:引入组件时可以给组件传递一些HTML元素。

默认插槽

父组件中引入子组件时,子组件标签内部的元素就是会传入slot的参数。

子组件中的slot就相当于占位符,给未来传进来的元素预留空位。

父组件:

html 复制代码
<template>
    <h1>父组件数据</h1>
    <div class="child">
        <child1 :title="'第一个'">
            <div style="color: aqua;">
                1111111111
            </div>
        </child1>
        <child1 :title="'第二个'">
            <div style="color:black;">
                22
            </div>
        </child1>
    </div>
</template>
<script setup lang="ts" name="parentIndex">
import child1 from './childe.vue';
</script>
<style scoped>

子组件:

html 复制代码
    <div class="child">
        <h1 style="color: black;">{{ title }}</h1>
        <slot>默认值</slot>
    </div>

</template>
<script setup lang="ts" >
    defineProps(['title'])
</script>

具名插槽

作用:可以指定元素插入的位置。

用法:在定义插槽位置时,使用name属性定义其名字。

在应用组件时,在其标签或Templet标签内部定义v-slot(或使用#+名字)属性。

父组件:

html 复制代码
<template>
    <h1>父组件数据</h1>
    <div class="child">
        <child1 :title="'第一个'">
            <template #b>
                <div style="color: aqua;">
                    1111111111
                </div>
            </template>
        </child1>
        <child1 :title="'第二个'">
            <template #a>
                <div style="color:black;">
                    22
                </div>
            </template>
        </child1>
    </div>
</template>
<script setup lang="ts" name="parentIndex">
import child1 from './childe.vue';
</script>

子组件:

html 复制代码
<template>    
    <div class="child">
        <h1 style="color: black;">{{ title }}</h1>
        <slot name="a">默认值</slot>
        <h1>-------------分隔符--------------------</h1>
        <slot name="b">默认值</slot>
    </div>

</template>
<script setup lang="ts" >
    defineProps(['title'])
</script>

作用域插槽

作用:当父组件需要子组件的数据。

用法:在定义slot标签时,使用props写法进行传递参数。

在父组件中使用v-slot拿到参数。

如果同时使用了具名插槽:v-slot:name='parms'

父组件:

html 复制代码
<template>
    <h1>父组件数据</h1>
    <div class="child">
        <child1 :title="'第一个'">
            <template #a="{game,a}">
               <ul>
                   <li v-for="item in game" :key="item.id">{{ item.name }}</li>
               </ul>
            </template>
        </child1>
    </div>
</template>
<script setup lang="ts" name="parentIndex">
import child1 from './childe.vue';
</script>

子组件:

html 复制代码
<template>    
    <div class="child">
        <h1 style="color: black;">{{ title }}</h1>
        <slot name="a" :game="game" :a="a">默认值</slot>
    </div>

</template>
<script setup lang="ts" >
import { reactive } from 'vue'; 
    defineProps(['title'])
    const game=reactive([
        {id:1,name:'a'},
        {id:2,name:'b'},
    ])
    const a=1;
</script>
相关推荐
星栈7 分钟前
Dioxus 接数据库最容易写歪的 3 个地方:sqlx + SQLite 怎么接才顺
前端·rust·前端框架
晴虹9 分钟前
vue3-scroll-more:横向滚动条-元素或页签过多滚动显示处理的组件
前端·vue.js
代码搬运媛11 分钟前
Claude 全栈开发专用 Rules 配置
前端
PedroQue9914 分钟前
uni-router v1.7.0重磅更新:守卫重定向自由掌控
前端·uni-app
Forever7_15 分钟前
尤雨溪转发:Vue-tui 0.1 发布!Vue 终于杀进终端!
vue.js
逸铭15 分钟前
Day 4:登录与 Token——桌面端怎么存密钥
前端·客户端
默_笙15 分钟前
🍞 我用 CSS 画了一个会转的 3D 立方体,同事以为我学了 Three.js(这节课真的很神奇,我很喜欢)
javascript
dkbnull16 分钟前
Vue 虚拟 DOM Diff 算法与 key 机制原理
vue.js
溯朢20 分钟前
TokUI 流式渲染的 SSE 全链路拆解
前端
京东云开发者23 分钟前
京东 Oxygen xLLM 大模型推理引擎正式捐赠开放原子开源基金会,共建国产 AI Infra 生态
前端