一、props
概述:props是使用频率最高的一种通信方式,常用与:父<->子 若父传子:属性值是非函数 若子传父:属性值是函数
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>汽车:{{car}}</h4>
<h4 v-show="toy">子给的玩具:{{toy}}</h4>
<Child :car="car" :sendToy="getToy"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from 'vue'
// 数据
let car = ref('宝马')
let toy = ref('')
//方法
function getToy(value:string) {
console.log('父', value)
toy.value = value
}
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{toy}}</h4>
<h4>父给的车:{{car}}</h4>
<button @click="sendToy(toy)">把玩具给父亲</button>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from 'vue'
// 数据
let toy = ref('变形金刚')
//声明接收props
defineProps(['car','sendToy'])
</script>
二、emit 自定义事件
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>子给的玩具:{{toy}}</h4>
<!-- 给子组Child绑定事件-->
<Child @send-toy="saveToy"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from 'vue'
let toy = ref('')
//方法
function saveToy(value: string) {
console.log('saveToy',value)
toy.value = value
}
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{toy}}</h4>
<button @click="emit('send-toy', toy)">把玩具给父亲</button>
</div>
</template>
<script setup lang="ts" name="Child">
import { ref, onMounted } from 'vue'
let toy = ref('变形金刚')
// 声明事件
const emit = defineEmits(['send-toy'])
onMounted(() => {
setTimeout(() => {
emit('send-toy', toy.value)
}, 3000)
})
</script>
三、mitt
1.首先要安装mitt npm i mitt 2.创建uitls文件下的emitter.ts
emitter.ts
//引用mitt
import mitt from 'mitt'
//调用mitt得到emitter,emitter能:绑定事件、触发事件
const emitter= mitt()
//绑定事件
emitter.on('test1', () => {
console.log('test1被调用了')
})
emitter.on('test2', () => {
console.log('test2被调用了')
})
//触发事件
setInterval(() => {
emitter.emit('test1')
emitter.emit('test2')
},1000)
//解绑事件
setTimeout(() => {
//emitter.off('test1')
//emitter.off('test2')
emitter.all.clear()
},3000)
export default emitter
3.在main.ts文件中引用emitter.ts
import emitter from '@/utils/emitter'
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<Child1/>
<Child2/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
</script>
Child1.vue
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具: {{toy}}</h4>
<button @click="emitter.emit('send-toy', toy)">哥哥给弟弟玩具</button>
</div>
</template>
<script setup lang="ts" name="Child1">
import { ref, onMounted } from 'vue'
import emitter from '@/utils/emitter'
let toy = ref('变形金刚')
</script>
Child2.vue
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>电脑: {{computer}}</h4>
<h4>弟弟接收哥哥给的玩具: {{toy}}</h4>
</div>
</template>
<script setup lang="ts" name="Child2">
import { ref, onUnmounted } from 'vue'
import emitter from '@/utils/emitter'
let computer = ref('联想')
let toy = ref('')
//给emitter绑定send-toy事件
emitter.on('send-toy',(value: string) => {
toy.value = value
})
//在组件卸载时解绑send-toy事件,为了是当Child1组件没有了就不存在send-toy事件,更是为了占用内存空间
onUnmounted(() => {
emitter.off('send-toy')
})
</script>
四、v-model
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<!--v-model用在html标签上-->
<!-- <input type="text" v-model="username"> -->
<input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value"> <!--用于实现数据到页面-->
<!--v-model用在组件标签上-->
<!-- <Child v-model="username"/> 第一种方法-->
<Child :modelValue="username" @update:modelValue="username=$event"/> <!--第二种方法-->
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue"
//数据
let username = ref('zhangsan')
</script>
Child.vue
<template>
<div class="child">
<h3>子组件1</h3>
<input type="text" :value="modelValue" @input="emit('update:modelValue',(<HTMLInputElement>$event.target).value)">
</div>
</template>
<script setup lang="ts" name="Child">
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
event就是事件对象======> 能.target 对于自定义事件,$event就是触发事件时,所传递的数据 ==> 不能.target Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<!--修改modelValue-->
<Child v-model:ming="username" v-model:mima="password"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue"
//数据
let username = ref('zhangsan')
let password = ref('123456')
</script>
Child.vue
<template>
<div class="child">
<h3>子组件1</h3>
<input type="text" :value="ming" @input="emit('update:ming',(<HTMLInputElement>$event.target).value)">
<input type="text" :value="mima" @input="emit('update:mima',(<HTMLInputElement>$event.target).value)">
</div>
</template>
<script setup lang="ts" name="Child">
defineProps(['ming','mima'])
const emit = defineEmits(['update:ming', 'update:mima'])
</script>
五、$attrs
1.概述:$attrs用于实现当前组件的父组件,向当前组件的子组件通信(祖-> 孙)
2.具体说明:$attrs是一个对象,包含所有父组件传入的标签属性
注意:$attrs会自动排除props中声明的属性(可以认为声明过的props被子组件自己“消费”了)
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<Child :a="a" :b="b" v-bind="{x:10,y:20}" :update="update/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue"
//数据
let a = ref(1)
let b = ref(2)
function update(value: number) {
a.value += value
}
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild v-bind="$attrs">
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue'
</script>
GrandChild.vue
<template>
<div class="GrandChild">
<h3>孙组件</h3>
<h4>a:{{a}}</h4>
<h4>a:{{b}}</h4>
<h4>x:{{x}}</h4>
<h4>y:{{y}}</h4>
<button @click="update(2)">点我将爷爷那边的a更新</button>
</div>
</template>
<script setup lang="ts" name="Child">
defineProps(['a','b', 'x','y', 'update'])
</script>
六$refs和$params
1.概述:
- $refs用于:父 -> 子
- $parent用于:子 -> 父
2.原理如下:
| 属性 | 说明 |
|---|---|
| $refs | 值为对象,包含所有被ref属性标识的DOM元素或组件实例 |
| $parent | 值为对象,当前组件的父组件实例对象 |
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>房子: {{house}}套</h4>
<button @click="changeToy">修改child1的玩具</button>
<button @click="getAllChild($refs)">获取所有的子组件的实例对象</button>
<Child1 ref="c1"/>
<Child2 ref="c2"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import { ref } from "vue"
//数据
let house = ref(1)
let c1= ref()
let c2 = ref()
//方法
function changeToy() {
console.log(c1.value)
c1.value.toy= "奥特曼"
}
function getAllChild(refs:{[key:string]:any}) {
for(let key in refs) {
console.log(refs[key])
refs[key].book += 3
}
}
//把数据交给外部
defineExpose({house})
</script>
Child1.vue
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具: {{toy}}</h4>
<h4>书籍: {{book}}本</h4>
</div>
</template>
<script setup lang="ts" name="Child1">
import { ref, onMounted } from 'vue'
import emitter from '@/utils/emitter'
let toy = ref('变形金刚')
let book = ref(3)
//把数据交给外部
defineExpose({toy, book})
</script>
Child2.vue
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>电脑: {{computer}}</h4>
<h4>书籍: {{book}}本</h4>
<button @click="minusHouse($parent)">干掉父亲的一套房产</button>
</div>
</template>
<script setup lang="ts" name="Child1">
import { ref, onMounted } from 'vue'
import emitter from '@/utils/emitter'
let computer = ref('联想')
let book = ref(4)
//方法
function minusHouse(parent:any) {
console.log(parent)
parent.house -= 1
}
//把数据交给外部
defineExpose({computer, book})
</script>
七、provide、inject
1.概述:
- 实现祖孙租金直接通信
2.具体使用:
- 在祖先组件中通过provide配置向后代组件提供数据
- 在后代组件中通过injet配置来声明接收数据
3.具体编码:
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>定金:{{money}}万元</h4>
<h4>车子:一辆{{car.brand}},价格{{car.price}}万元</h4>
<Child />
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref,reactive,provide } from "vue"
//数据
let money = ref(1)
let car = reactive({
brand: '宝马',
price: 100
})
function updateMoney(value: number) {
money.value -= value
}
//向后代提供数据
//provide('qian', money)
provide('moneyContext', {money, updateMoney})
provide('che', car)
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild />
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue'
</script>
GrandChild.vue
<template>
<div class="GrandChild">
<h3>孙组件</h3>
<h4>定金:{{money}}万元</h4>
<h4>车子:一辆{{car.brand}},价格{{car.price}}万元</h4>
<button @click="updateMoney(2)">花爷爷的钱</button>
</div>
</template>
<script setup lang="ts" name="Child">
import {inject} from "vue"
//let money = inject('qian', '我是默认值如:1')
let {money,updateMoney} = inject('moneyContext', {money: 1, updateMoney:(param:number) => {}})
let car = inject('che', {brand: '未知', price: 0})
</script>
八、pinia
九、slot
第一种:默认插槽
默认插槽也有名字<slot name="default"></slot>
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Child title="热门游戏列表">
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
</Child>
<Child title="今日美食城市">
<img :src="imgUrl" alt=""/>
</Child>
<Child title="今日影视推荐">
<video :src="videoUrl" controls></video>
</Child>
</div>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref, reactive } from "vue"
//数据
let game = reactive([
{id: '01', name: '王者荣耀'},
{id: '02', name: 'cs'},
])
let imUrl = ref('https://12.png')
let videoUrl = ref('https://23.mp4')
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<h4>{{title}}</h4>
<slot>默认内容</slot>
</div>
</template>
<script setup lang="ts" name="Child">
defineProps(['title'])
</script>
第二种具名插槽:具有名字的插槽 Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Child>
<template v-slot:s2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
</template>
<template #s1>
<h2>热门游戏列表</h2>
</template>
</Child>
</div>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { reactive } from "vue"
//数据
let game = reactive([
{id: '01', name: '王者荣耀'},
{id: '02', name: 'cs'},
])
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<slot name="s1">默认内容1</slot>
<slot name="s2">默认内容2</slot>
</div>
</template>
<script setup lang="ts" name="Child">
</script>
第三种作用域插槽
作用域插槽可以有名字
<template v-slot:qwe="params">
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Child>
<template v-slot:qwe="params">
<ul>
<li v-for="g in params.youxi" :key="g.id">{{g.name}}</li>
</ul>
</template>
</Child>
<Child>
<template v-slot="params">
<ol>
<li v-for="g in params.youxi" :key="g.id">{{g.name}}</li>
</ol>
</template>
</Child>
<Child>
<template v-slot="{youxi}">
<h3 v-for="g in youxi" :key="g.id">{{g.name}}</h3>
</template>
</Child>
</div>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref, reactive } from "vue"
//数据
let game = reactive([
{id: '01', name: '王者荣耀'},
{id: '02', name: 'cs'},
])
</script>
Child.vue
<template>
<div class="child">
<h3>子组件</h3>
<!-- <slot :youxi="game">默认内容</slot> -->
<slot name="qwe" :youxi="game">默认内容</slot>
</div>
</template>
<script setup lang="ts" name="Child">
import { reactive } from "vue"
//数据
let game = reactive([
{id: '01', name: '王者荣耀'},
{id: '02', name: 'cs'},
])
</script>