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
实现任意组件的通信。个人理解:在组件与组件之间提供了一个平台,都向这个平台发送、读取数据。
安装步骤:
- npm i mitt
- 新建文件utiles/emitter.ts
- 在需要的文件中引入emitter,进行绑定 事件,或调用事件。
- 在文件中进行解绑(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>