1、Prop
父組件
<template>
<div class="parent">
<h1>我是父元素</h1>
<Child :msg="msg"></Child>
</div>
</template>
<script setup>
import Child from './Child.vue'
let msg = ref('我是父組件的數(shù)據(jù)')
</script>
<style scoped>
.parent{
width: 800px;
height: 600px;
background: skyblue;
}
</style>
子組件
<template>
<div class="son">
<h3>我是子元素</h3>
<h4>{{ msg }}</h4>
</div>
</template>
<script setup>
// 1、let props = defineProps(['msg'])
//2、defineProps(['msg'])
//3、
defineProps({
msg:{
type:String,
default:'默認數(shù)據(jù)'
}
})
</script>
<style scoped>
.son{
width: 200px;
height: 200px;
background: pink;
}
</style>
2、自定義事件
父組件
<template>
<div class="parent">
<h1>我是父元素</h1>
<Child :msg="msg" @getData="getData"></Child>
<hr>
<p>父組件接收數(shù)據(jù):{{passStr}}</p>
</div>
</template>
<script setup>
import Child from './Child.vue'
let msg = ref('我是父組件的數(shù)據(jù)');
let passStr = ref('')
const getData = (e)=>{
passStr.value=e
}
</script>
<style scoped>
.parent{
width: 800px;
height: 600px;
background: skyblue;
}
</style>
子組件
<template>
<div class="son">
<h3>我是子元素</h3>
<h4>{{ msg }}</h4>
<button @click="passData('我是子組件數(shù)據(jù)')">給父組件傳遞參數(shù)</button>
</div>
</template>
<script setup>
// 1、let props = defineProps(['msg'])
//2、defineProps(['msg'])
//3、
defineProps({
msg:{
type:String,
default:'默認數(shù)據(jù)'
}
})
let $emit = defineEmits('getData')
const passData = (msg)=>{
$emit('getData',msg)
}
</script>
<style scoped>
.son{
width: 200px;
height: 200px;
background: pink;
}
</style>
3、全局事件總線
1、安裝
npm install --save mitt
2、新建utils/mitt.js
import mitt from 'mitt'
const emitter =new mitt()
export default emitter
3、使用
子組件1
<template>
<div class="son">
<h3>我是子元素</h3>
<h4>{{ msg }}</h4>
<button @click="passData('我是子組件數(shù)據(jù)')">給父組件傳遞參數(shù)</button>
<button @click="passBusData('我是子組件1的數(shù)據(jù)')">給子組件2傳遞參數(shù)</button>
</div>
</template>
<script setup>
import emitter from '../utils/mitt'
// 1、let props = defineProps(['msg'])
//2、defineProps(['msg'])
//3、
defineProps({
msg:{
type:String,
default:'默認數(shù)據(jù)'
}
})
let $emit = defineEmits('getData')
const passData = (msg)=>{
$emit('getData',msg)
}
const instance = getCurrentInstance()
const passBusData = (msg) =>{
emitter.emit("passBusData",msg)
}
</script>
<style scoped>
.son{
width: 200px;
height: 200px;
background: pink;
}
</style>
子組件2
<template>
<div class="child1">
<h3>子組件2</h3>
<p>{{msg}}</p>
</div>
</template>
<script setup>
import emitter from '../utils/mitt'
let msg = ref('')
onMounted(() => {
emitter.on("passBusData",(data) =>{
msg.value=data
})
});
</script>
<style scoped>
.child1{
width: 200px;
height: 200px;
background: hotpink;
}
</style>
4、v-model
1、綁定單個數(shù)據(jù)
父組件
<template>
<div class="parent">
<h1>父組件錢數(shù):{{money}}</h1>
<input type="number" v-model="money">
<!-- props:父組件給子組件傳值 -->
<!-- <Child :modelValue="money" @update:modelValue="getData" /> -->
<!--
v-model組件身上使用
1、相當于給子組件傳遞props[modelValue] = 1000
2、給子組件綁定自定義事件update:modelValue
-->
<Child v-model="money" />
</div>
</template>
<script setup>
import Child from './Child.vue';
import { ref } from 'vue';
// v-model 指令 收集表單數(shù)據(jù),雙向數(shù)據(jù)綁定
// v-model也可以實現(xiàn)組件之間通信,實現(xiàn)父子組件數(shù)據(jù)同步
// 父組件給子組件傳數(shù)據(jù) props
// 子組件給父組件傳數(shù)據(jù) 自定義事件
let money = ref(1000);
const getData = (data)=>{
money.value = data
}
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:500px;
background: pink;
}
</style>
子組件
<template>
<div class="child">
<h3>子組件接收父組件錢數(shù){{modelValue}}</h3>
<button @click="handler">子組件改變數(shù)據(jù)</button>
</div>
</template>
<script setup>
let props = defineProps(['modelValue']);
let emits = defineEmits(['update:modelValue']);
const handler = () => {
emits('update:modelValue',props.modelValue+100)
}
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 200px;
background: skyblue;
}
</style>
2、綁定多個數(shù)據(jù)
父組件
<template>
<div class="parent">
<h2>父組件錢數(shù):{{money}}當前頁{{currentPage}}每頁條數(shù){{pageSize}}</h2>
<input type="number" v-model="money">
<!-- props:父組件給子組件傳值 -->
<!-- <Child :modelValue="money" @update:modelValue="getData" /> -->
<!--
v-model組件身上使用
1、相當于給子組件傳遞props[modelValue] = 1000
2、給子組件綁定自定義事件update:modelValue
-->
<Child v-model="money" />
<Child2 v-model:currentPage="currentPage" v-model:pageSize="pageSize"></Child2>
</div>
</template>
<script setup>
import Child from './Child.vue';
import Child2 from './Child2.vue';
import { ref } from 'vue';
// v-model 指令 收集表單數(shù)據(jù),雙向數(shù)據(jù)綁定
// v-model也可以實現(xiàn)組件之間通信,實現(xiàn)父子組件數(shù)據(jù)同步
// 父組件給子組件傳數(shù)據(jù) props
// 子組件給父組件傳數(shù)據(jù) 自定義事件
let money = ref(1000);
const getData = (data)=>{
money.value = data
}
//
let currentPage =ref(1)
let pageSize =ref(20)
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:600px;
background: pink;
}
</style>
子組件
<template>
<div class="child2">
<h3>子組件2接收父組傳遞的數(shù)據(jù){{currentPage}}{{ pageSize }}</h3>
<button @click="emits('update:currentPage',currentPage+1)">改變父組件currentPage</button>
<button @click="emits('update:pageSize',pageSize+10)">改變父組件pageSize</button>
</div>
</template>
<script setup>
let props=defineProps(['currentPage','pageSize'])
let emits= defineEmits(['update:currentPage','update:pageSize'])
</script>
<style lang="scss" scoped>
.child2{
width:300px;
height:200px;
background: hotpink;
}
</style>
5、useAttr
父組件
<template>
<div class="parent">
<h2>父組件</h2>
<Child type="primary" title="編輯按鈕" size="small" @click="handler" />
</div>
</template>
<script setup>
import Child from './Child.vue';
const handler = ()=>{
alert('點擊了')
}
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:600px;
background: pink;
}
</style>
子組件
<template>
<div class="child">
<h3>子組件</h3>
<!-- <el-button :type="$attrs.type" :size="$attrs.size">按鈕</el-button> -->
<el-button :="$attrs">按鈕</el-button>
</div>
</template>
<script setup>
//引入useAttrs方法:獲取組件標簽身上屬性與事件
let $attrs = useAttrs()
let props= defineProps(['title'])
console.log(props)
console.log($attrs)
//props和useAttrs方法都可以獲取父組件傳過來的屬性和屬性值
//但是props接收了useAttrs方法就獲取不到了
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 200px;
background: skyblue;
}
</style>
6、ref與$parent
父組件
<template>
<div class="parent">
<h2>父組件錢數(shù):{{money}}</h2>
<button @click="borrowMoney">向子組件借100</button>
<Child ref="child" />
</div>
</template>
<script setup>
import Child from './Child.vue';
// ref可以獲取真實的DOM節(jié)點,可以獲取到組件真實VC
//$parent 可以在子組件內(nèi)部獲取父組件的實例
let money = ref(1000)
//向外暴露
defineExpose({
money
})
//獲取子組件實例
let child = ref();
//借錢
let borrowMoney = ()=>{
money.value+=100;
child.value.money-=100;
//child.value.handler()
}
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:600px;
background: pink;
}
</style>
子組件
<template>
<div class="child">
<h3>子組件錢數(shù):{{money}}</h3>
<button @click="handler($parent)">向父組件借錢100</button>
</div>
</template>
<script setup>
let money = ref(1000)
//組件內(nèi)部的數(shù)據(jù)是對外關(guān)閉的,別人不能訪問
//如果想讓外部訪問需要通過defineExpose方法對外暴露
let handler = ($parent)=>{
console.log('子組件事件');
money.value+=100;
$parent.money-=100
}
defineExpose({
money,handler
})
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 200px;
background: skyblue;
}
</style>
7、Provide與Inject
父組件
<template>
<div class="parent">
<h2>父組件數(shù)據(jù):{{car}}</h2>
<Child ref="child" />
</div>
</template>
<script setup>
import Child from './Child.vue';
//vue3提供provide(提供)與inject(注入)可以實現(xiàn)隔輩組件傳遞數(shù)據(jù)
let car = ref('法拉利');
//祖先組件給后代組件傳遞數(shù)據(jù)
//兩個參數(shù),第一個參數(shù)是提供數(shù)據(jù)的數(shù)據(jù)key
//第二個參數(shù) 祖先組件提供的數(shù)據(jù)
provide('car', car);
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:600px;
background: pink;
}
</style>
子組件
<template>
<div class="child">
<h3>子組件</h3>
<Grandson></Grandson>
</div>
</template>
<script setup>
import Grandson from './Grandson.vue';
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 200px;
background: skyblue;
}
</style>
孫子組件
<template>
<div class="grandson">
<h5>孫子組件接收祖先組件傳遞的數(shù)據(jù):{{car}}</h5>
<button @click="updateData">更改祖先組件數(shù)據(jù)</button>
</div>
</template>
<script setup>
//注入祖先組件提供的數(shù)據(jù)
//需要參數(shù):即為祖先組件提供數(shù)據(jù)的key
let car = inject("car");
let updateData = ()=>{
car.value='寶馬'
}
</script>
<style lang="scss" scoped>
.grandson{
width:200px;
height: 100px;
background: yellowgreen;
}
</style>
8、pinia
1、安裝
pnpm i pinia
2、在src文件夾下創(chuàng)建store文件夾,新建index.js
//創(chuàng)建大倉庫
import { createPinia } from 'pinia';
//createPinia方法可以用來創(chuàng)建大倉庫
let store = createPinia();
//對外暴露,安裝倉庫
export default store
3、在main.js中引入使用
//引入倉庫
import store from './store'
let app= createApp(App);
app.use(store).mount('#app')
4、在store文件夾下新建modules文件夾,新建info.js
1、選擇式寫法
1、info.js
//定義info小倉庫
import { defineStore } from "pinia";
//2個參數(shù):1、小倉庫名稱 2小倉庫配置對象
//defineStore方法執(zhí)行返回一個函數(shù),函數(shù)作用讓組件獲取到倉庫數(shù)據(jù)
let useInfoStore = defineStore("info",{
//存儲數(shù)據(jù) state
state: ()=>{
return {
count:99,
arr:[1,2,3,4,5,6,7,8,9,10]
}
},
actions:{
updateCount(num){
// this.count++
this.count+=num;
}
},
getters:{
total(){
return this.arr.reduce((pre,next)=>{
return pre+next
},0)
}
}
})
//對外暴露
export default useInfoStore;
2、在組件1中使用
<template>
<div class="child">
<h3>子組件-接收倉庫數(shù)據(jù):{{infoStore.count}}</h3>
<h4>getters:數(shù)組求和:{{infoStore.total}}</h4>
<button @click="updateCount">修改倉庫數(shù)據(jù)</button>
</div>
</template>
<script setup>
import useInfoStore from '../store/modules/info';
//獲取小倉庫對象
let infoStore = useInfoStore();
console.log(infoStore)
//修改倉庫數(shù)據(jù)
let updateCount = ()=>{
//1、直接修改
//infoStore.count++
//2、patch
// infoStore.$patch({
// count:100
// })
//3、調(diào)用store方法
infoStore.updateCount(10)
}
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 200px;
background: skyblue;
}
</style>
3、在組件2中使用
<template>
<div class="child2">
<h3>子組件2-接收倉庫數(shù)據(jù):{{infoStore.count}}</h3>
</div>
</template>
<script setup>
import useInfoStore from '../store/modules/info';
//獲取小倉庫對象
let infoStore = useInfoStore();
</script>
<style lang="scss" scoped>
.child2{
width:300px;
height:200px;
background: hotpink;
}
</style>
2、組合式API寫法
1、在modules文件夾下新建todo.js
//定義組合式API
import { defineStore } from "pinia";
import { ref , computed } from 'vue'
//創(chuàng)建小倉庫
let useTodoStore = defineStore('todo',()=>{
//務必返回一個對象,對象的屬性和方法提供給組件使用
let todos = ref([
{id:1,title:'吃飯'},
{id:2,title:'睡覺'},
{id:3,title:'打豆豆'},
])
let arr=ref([1,2,3,4,5])
const total = computed(()=>{
return arr.value.reduce((prev, curr) => {
return prev+curr
}, 0)
})
return {
todos,//相當于選擇式API的state
arr,
total,
updateTodos(){
todos.value.push({id:4,title:'擺爛'})
},//相當于選擇式API的actions
}
})
export default useTodoStore
2、在組件1中使用
<template>
<div class="child">
<h3>子組件-接收倉庫數(shù)據(jù):</h3>
<ul>
<li v-for="item in todosStore.todos" :key="item.id">{{item.title}}</li>
</ul>
<p>{{ todosStore.arr }}--總和{{todosStore.total}}</p>
<button @click="updateTodos">修改倉庫數(shù)據(jù)</button>
</div>
</template>
<script setup>
//引入組合式API函數(shù)倉庫
import useTodosStore from '../store/modules/todo';
let todosStore = useTodosStore();
//修改倉庫數(shù)據(jù)
let updateTodos = ()=>{
todosStore.updateTodos()
}
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 300px;
background: skyblue;
}
</style>
3、在組件2中使用
<template>
<div class="child2">
<h3>子組件2-接收倉庫數(shù)據(jù):</h3>
<ul>
<li v-for="item in todosStore.todos" :key="item.id">{{item.title}}</li>
</ul>
</div>
</template>
<script setup>
import useTodosStore from '../store/modules/todo';
//獲取小倉庫對象
let todosStore = useTodosStore();
</script>
<style lang="scss" scoped>
.child2{
width:300px;
height:300px;
background: hotpink;
}
</style>
9、slot
1、默認插槽
父組件
<template>
<div class="parent">
<h2>父組件</h2>
<div class="container">
<Child>
<pre>我是父組件傳入的數(shù)據(jù)</pre>
</Child>
</div>
</div>
</template>
<script setup>
import Child from './Child.vue';
//插槽:默認插槽、具名插槽、作用域插槽
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:400px;
background: pink;
.container{
display: flex;
align-items: center;
justify-content: space-around;
}
}
</style>
子組件
<template>
<div class="child">
<h3>我是子組件默認插槽</h3>
<!-- 默認插銷 -->
<slot></slot>
<h3>我是子組件默認插槽</h3>
</div>
</template>
<script setup>
//引入組合式API函數(shù)倉庫
import useTodosStore from '../store/modules/todo';
let todosStore = useTodosStore();
//修改倉庫數(shù)據(jù)
let updateTodos = ()=>{
todosStore.updateTodos()
}
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 300px;
background: skyblue;
}
</style>
2、具名插槽
父組件
<template>
<div class="parent">
<h2>父組件</h2>
<div class="container">
<Child>
<!-- 具名插槽填充 v-slot:簡寫問# -->
<template v-slot:a>
<p>我是填充具名插槽a位置結(jié)構(gòu)</p>
</template>
<template #b>
<p>我是填充具名插槽b位置結(jié)構(gòu)</p>
</template>
</Child>
</div>
</div>
</template>
<script setup>
import Child from './Child.vue';
//插槽:默認插槽、具名插槽、作用域插槽
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:400px;
background: pink;
.container{
display: flex;
align-items: center;
justify-content: space-around;
}
}
</style>
子組件
<template>
<div class="child">
<h3>我是子組件具名插槽</h3>
<slot name="a"></slot>
<h3>我是子組件具名插槽</h3>
<hr>
<h3>我是子組件具名插槽</h3>
<slot name="b"></slot>
<h3>我是子組件具名插槽</h3>
</div>
</template>
<script setup>
//引入組合式API函數(shù)倉庫
import useTodosStore from '../store/modules/todo';
let todosStore = useTodosStore();
//修改倉庫數(shù)據(jù)
let updateTodos = ()=>{
todosStore.updateTodos()
}
</script>
<style lang="scss" scoped>
.child{
width: 300px;
height: 300px;
background: skyblue;
}
</style>
3、作用域插槽
父組件
<template>
<div class="parent">
<h2>父組件</h2>
<div class="container">
<Child :todos="todos">
<template v-slot="{$row,$index}">
<span :style="{color:$row.done?'green':'red'}">{{ $row.title }}--下標{{$index}}</span>
</template>
</Child>
</div>
</div>
</template>
<script setup>
import Child from './Child.vue';
// import Child2 from './Child2.vue';
//插槽:默認插槽、具名插槽、作用域插槽
//作用域插槽:就是可以傳遞數(shù)據(jù)的插槽,子組件可以將數(shù)據(jù)回傳給父組件,
//父組件可以決定這些回傳的數(shù)據(jù)是以何種結(jié)構(gòu)或者外觀在子組件內(nèi)部去展示
let todos = ref([
{id:1,title:'吃飯',done:true},
{id:2,title:'睡覺',done:false},
{id:3,title:'打豆豆',done:true},
{id:4,title:'打游戲',done:false},
])
</script>
<style lang="scss" scoped>
.parent{
width:800px;
height:400px;
background: pink;
.container{
display: flex;
align-items: center;
justify-content: space-around;
}
}
</style>
子組件
<template>
<div class="child">
<h3>子組件1</h3>
<ul>
<li v-for="(item,index) in todos" :key="item.id">
<!-- 作用域插槽:可以將數(shù)據(jù)回傳給父組件 -->
<slot :$row="item" :$index="index"></slot>
</li>
</ul>
</div>
</template>
<script setup>
let props = defineProps(['todos'])
</script>
<style lang="scss" scoped>
.child{
width: 500px;
height: 300px;
background: skyblue;
}
</style>
文章來源:http://www.zghlxwxcb.cn/news/detail-697452.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-697452.html
到了這里,關(guān)于vue3組件通信學習筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!