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>
相关推荐
裘乡1 分钟前
vonage音视频基本使用--web@opentok/client
前端·音视频开发
BugCollect4 分钟前
Lodash常用方法
前端·javascript
RainbowSea10 分钟前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 01
vue.js·spring boot·后端
工业互联网专业11 分钟前
基于JavaWeb的兼职发布平台的设计与实现
java·vue.js·spring boot·毕业设计·源码·课程设计·兼职发布平台
低代码布道师21 分钟前
HTML5 `<figure>` 标签:提升网页语义化与可访问性的利器
前端·html·html5
CAD老兵24 分钟前
解锁 JavaScript 模块的秘密:ES6模块内部结构详解
前端·javascript
程序视点27 分钟前
豹图CAD完全免费版下载 - 专业DWG看图软件推荐 | 支持AutoCAD全版本
前端
gnip31 分钟前
nrm
前端·javascript
天天码行空33 分钟前
Radash: 新一代前端工具库平替Lodash库
前端·javascript·github
gnip34 分钟前
nvm
前端·javascript