props
props可以实现父子组件通信,不管是在vue2或者vue3,props数据还是只读的!!!不能直接修改其值;在vue3中,我们可以通过defineProps获取父组件传递的数据,且在组建内部不需要引入defineProps方法可以直接使用,如下面例子
Parent.vue
//父组件
<template>
<h3>
props组件案例
</h3>
<div class="text_div">props可以实现父子组件通信,不管是在vue2或者vue3,props数据还是只读的!!!不能直接修改其值;在vue3中,我们可以通过defineProps获取父组件传递的数据,且在组建内部不需要引入defineProps方法可以直接使用,如下面例子</div>
<div class="box">
<h1>这是父组件</h1>
<Child1 info ="我是父组件传过来的值" :money="money"></Child1>
</div>
</template>
<script setup lang="js">
import Child1 from "@/views/props/Child1.vue";
import {ref} from "vue";
let money =ref(10000)
</script>
<style scoped>
.text_div{
width: 70%;
height: 50px;
background: #1db393;
}
.box{
width: 500px;
height: 300px;
background: hotpink;
}
</style>
Child1.vue
<template>
<div class="son">
<h3>这是子组件</h3>
<p>{{ props.info }}</p>
<p>{{ props.money }}</p>
<button @click = "updateProps">修改props数据</button>
</div>
</template>
<script setup lang="js">
let props = defineProps(['info','money']);
const updateProps =() =>{
console.log(props.info)
}
</script>
<style scoped>
.son {
width: 200px;
height: 200px;
background: yellow;
}
</style>
实现效果:
使用props,子组件获取父组件传递数据方式有两种:
方式一:
let props = defineProps({
info:{
type:String,//接受的数据类型
default:'默认参数',//接受默认数据
},
money:{
type:Number,
default:0
}})
方式二:
let props = defineProps(["info",'money']);
原生DOM事件
在vue框架中,事件可以分为两种:
一种是原生DOM事件(比如click、abclick、change、mouseenter、mouseleave.....),原生事件可以让用户与网页进行交互;
一种是自定义事件,自定义事件可以实现子组件给父组件传递数据<!-- 原生DOM事件,默认会给事件回调注入event事件对象,无需写入 --><pre @click="handler"> 我是DOM原生事件</pre>
如果想给点击事件注入多个参数时,注入的事件对象必须叫做$event<div @click="handler1(1,2,3,$event)">我要传递多个参数</div>
在vue3中click、dbclick、change(这类原生DOM事件),不管是在标签、自定义标签上(组件标签)都是原生DOM事件,而在vue2中组件、标签都需要通过.native修饰符才能变为原生DOM事件。
自定义事件
在vue3中,原生DOM事件不管是放在元素标签身上、组件标签上都是原生DOM事件,在vue2中,则需要通过.native修饰符变为原生DOM事件,如下:
父组件:
<template>
<h1>自定义事件案例</h1>
<div class="fu">
<h2>这是父组件</h2>
<!-- 原生DOM事件-->
<pre @click = "handler">大江东去浪淘尽,千古分流人物</pre>
<hr>
<button @click="handler1(1,2,3,$event)">点击我传递多个参数</button>
<!--
vue2框架当中:这种写法自定义事件,可以通过.native修饰符变为原生DOM事件
vue3框架下面写法其实即为原生DOM事件
vue3:原生的DOM事件不管是放在标签身上、组件标签身上都是原生DOM事件
-->
<hr>
<zizujian1 @click="handler2"></zizujian1>
<hr>
<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<zizujian2 @xxx="handler3" @click="handler4"></zizujian2>
</div>
</template>
<script setup lang="js">
import zizujian1 from "@/views/zdy/zizujian1.vue";
import Zizujian2 from "@/views/zdy/zizujian2.vue";
// 回调事件-1
const handler = (event) =>{
console.log(event)
}
//事件回调--2
const handler1 = (a,b,c,$event)=>{
console.log(a,b,c,$event)
}
//事件回调--3
const handler2 = ()=>{
console.log("测试123")
}
//事件回调---4
const handler3 = (param1,param2)=>{
console.log(param1,param2);
}
//事件回调--5
const handler4 = (param1,param2)=>{
console.log(param1,param2);
}
</script>
<style scoped>
.fu {
width: 700px;
height: 700px;
background: #1db393;
}
</style>
子组件1
<template>
<div class="son1">
<p>我是子组件1</p>
<button>点击我也执行</button>
</div>
</template>
<style>
.son1{
width: 200px;
height: 200px;
background: #1b6d85;
}
</style>
子组件2
<template>
<div class="child">
<p>我是子组件2</p>
<button @click="handler">点击我触发自定义事件xxx</button>
<button @click="$emit('click','AK47','J20')">点击我触发自定义事件click</button>
</div>
</template>
<script setup lang="js">
let $emit = defineEmits(['xxx','click']);
//按钮点击回调
const handler = () => {
//第一个参数:事件类型 第二个|三个|N参数即为注入数据
$emit('xxx','东风导弹','航母');
};
</script>
<style scoped>
.child {
width: 400px;
height: 200px;
background: pink;
}
</style>
正常情况下,组件标签@click应该为原生DOM事件,但是如果子组件内部通过defineEmits定义就变为自定义事件了。
mitt
mitt是一个方法,会返回一个对象,该对象上挂载了四个方法,分别为all、on、off、emit
官网:mitt - npm
在src文件下新建文件bus/index.ts
//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from 'mitt';
const $bus = mitt();
export default $bus;
父组件:
<template>
<div class="container">
<Child1></Child1>
<Child2></Child2>
</div>
</template>
<script setup lang="ts">
//引入子组件
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";
</script>
<style scoped>
.box {
width: 100vw;
height: 400px;
background: yellowgreen;
}
.container{
display: flex;
justify-content: space-between;
}
</style>
Child1.vue<template> <div class="child1"> <h3>我是子组件1:曹植</h3> </div></template><script setup lang="ts">import $bus from "../../bus";//组合式API函数import { onMounted } from "vue";//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据onMounted(() => { //第一个参数:即为事件类型 第二个参数:即为事件回调 $bus.on("car", (car) => { console.log(car); });});</script><style scoped>.child1 { width: 300px; height: 300px; background: hotpink;}</style>
Child2.vue
<template>
<div class="child2">
<h2>我是子组件2:曹丕</h2>
<button @click="handler">点击我给兄弟送一台法拉利</button>
</div>
</template>
<script setup lang="ts">
//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
$bus.emit('car',{car:"法拉利"});
}
</script>
<style scoped>
.child2{
width: 300px;
height: 300px;
background: skyblue;
}
</style>
v-model
v-model有两个功能,
一个是收集表单数据(实现数据双向绑定);
一个是实现父子组建数据同步。
父组件
<template>
<div><h1>v-model:钱数{{ money }} {{ pageNo }} {{ pageSize }}</h1>
<input type="text" v-model="info"/>
<h5>v-model数据同步输入框信息:{{info}}</h5>
<hr/>
<!-- props:父亲给儿子数据 -->
<!-- <Child :modelValue="money" @update:modelValue="handler"></Child> -->
<!--
v-model组件身上使用
第一:相当有给子组件传递props[modelValue] = 10000
第二:相当于给子组件绑定自定义事件update:modelValue -->
<zizujian1 v-model="money"></zizujian1>
<hr/>
<zizujian2 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></zizujian2>
</div>
</template>
<script setup lang="js">
//父亲给子组件数据 props
// 子组件给父组件数据 自定义事件
// 引入子组件
import zizujian1 from "@/views/v-model/zizujian1.vue";
import zizujian2 from "@/views/v-model/zizujian2.vue";
import { ref } from "vue";
let info = ref("");
//父组件的数据钱数
let money = ref(10000);
//自定义事件的回调
const handler = (num) => {
money.value = num;}//将来接受子组件传递过来的数据
//父亲的数据
let pageNo = ref(1);
let pageSize = ref(3);
</script>
子组件1
<template>
<div class="child">
<h3>钱数:{{ modelValue }}</h3>
<button @click="handler">父子组件数据同步</button>
</div>
</template>
<script setup lang="js">
//子组件获取父组件的值接受props
let props = defineProps(["modelValue"]);
let $emit = defineEmits(['update:modelValue']);
//子组件内部按钮的点击回调
const handler = ()=>{
//触发自定义事件
$emit('update:modelValue',props.modelValue+1000);
}
</script>
<style scoped>
.child {
width: 600px;
height: 300px;
background: skyblue;
}
</style>
子组件2
<template>
<div class="child2">
<h1>同时绑定多个v-model</h1>
<button @click="handler">pageNo{{ pageNo }}</button>
<button @click="$emit('update:pageSize', pageSize + 4)">
pageSize{{ pageSize }}</button>
</div>
</template>
<script setup lang="js">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {
$emit("update:pageNo", props.pageNo + 3);
};
</script>
<style scoped>
.child2 {
width: 300px;
height: 300px;
background: hotpink;
}
</style>
useAttrs
在Vue3中可以利用useAttrs方法获取组件的属性与事件(包含:原生DOM事件或者自定义事件),此函数功能类似于Vue2框架中attrs属性与listeners方法
父组件
<template>
<h1>useAttrs组件学习</h1>
<div class="fu" title="这是编辑按钮">
<h2>这是父组件</h2>
<!-- 自定义组件-->
<el-button type="primary" size="default" :icon="Edit" @click="handler" @xxx="handler">修改按钮</el-button>
<!-- 给子组件1传入参数-->
<zizujian1 type="primary" size="default" :icon="Edit" @click="handler" @xxx="handler"></zizujian1>
</div>
</template>
<script setup lang="js">
import zizujian1 from "@/views/useAttrs/zizujian1.vue";
import {
Edit,
} from '@element-plus/icons-vue'
const handler = () =>{
alert("点击了编辑按钮")
}
</script>
<style scoped>
.fu {
width: 100vw;
height: 600px;
background: #1db393;
}
</style>
子组件
<template>
<div class="son">
<h2>这是子组件1</h2>
<el-button :="$attrs"></el-button>
</div>
</template>
<script setup lang="js">
import {useAttrs} from "vue";
let $attrs = useAttrs();
console.log($attrs)
</script>
<style scoped>
.son {
width: 300px;
height: 200px;
background: #42b983;
}
</style>
ref与$parent
父组件
<template>
<h1>这是父组件</h1>
<div class="fu">
<h2>我是父亲刘备:{{ money }}</h2>
<button @click="handler">
点我向儿子刘封借100元
</button>
<zizujian2 ref="son1"></zizujian2>
<zizujian1></zizujian1>
</div>
</template>
<script setup lang="js">
import {ref} from "vue";
import zizujian1 from "@/views/ref_parent/zizujian1.vue";
import zizujian2 from "@/views/ref_parent/zizujian2.vue";
import Zizujian1 from "@/views/ref_parent/zizujian1.vue";
let money = ref(10000000);
let son1 =ref()
const handler = () => {
money.value += 100;
son1.value.money -=100;
son1.value.fly()
}
defineExpose(
{
money,
}
)
</script>
<style scoped>
.fu {
width: 100vw;
height: 600px;
background: #1db393;
}
</style>
子组件1
<template>
<div class="son">
<h1>我是儿子刘婵{{money}}</h1>
<button @click="handler($parent)">点击我爸爸给我10000元</button>
</div>
</template>
<script setup lang="js">
import {ref} from 'vue';
let money = ref(999999);
const handler = ($parent)=>{
money.value+=10000;
$parent.money-=10000;
}
</script>
<style scoped>
.son{
width: 300px;
height: 300px;
background: hotpink;
}
</style>
子组件2
<template>
<div class="son">
<h3>我是子组件:刘封{{money}}</h3>
</div>
</template>
<script setup lang="js">
import {ref} from "vue";
let money =ref(1000)
const fly =()=>{
alert("父亲刘备向我借了100")
}
defineExpose(
{
money,
fly
}
)
</script>
<style scoped>
.son {
width: 300px;
height: 200px;
background: cyan;
}
</style>
provide(提供)与inject(注入)
vue3提供两个方法provide与inject,可以实现隔辈组件传递参数
provide方法用于提供数据,此方法执需要传递两个参数,分别提供数据的key与提供数据value
爷组件
<template>
<div class="box">
<h1>我是父组件</h1>
<h2>car:{{ car }}</h2>
<hr>
<zizujian></zizujian>
</div>
</template>
<script setup lang="js">
import zizujian from "@/views/provide_inject/zizujian.vue";
//vue3提供provde与inject可以实现隔辈传递数据
import {ref, provide} from 'vue';
let car = ref("法拉利")
//provide 需要传入两个参数 第一个参数提供数据的key 第二个 祖先组件提供的数据
provide("fucar", car)
</script>
<style scoped>
.box {
width: 100vw;
height: 500px;
background: skyblue;
}
</style>
子组件
<template>
<div class="er">
<h1>儿子组件</h1>
<runzujian></runzujian>
</div>
</template>
<script setup lang="js">
import runzujian from "@/views/provide_inject/runzujian.vue";
</script>
<style scoped>
.er{
width: 400px;
height: 300px;
background: palevioletred;
}
</style>
孙组件
<template>
<div class="sun">
<h1>孙子组件</h1>
<h2>{{car}}</h2>
</div>
</template>
<script setup lang="js">
import {inject} from "vue";
let car =inject("fucar")
</script>
<style scoped>
.sun{
width: 200px;
height: 200px;
background: red;
}
</style>
pipa
pinia也是集中式管理状态容器,类似于vuex,
但是核心概念没有mutation、modules
solt
插槽:分为默认插槽、具名插槽、作用域插槽
下载
代码源码下载:公众号回复“vue3组件学习”