- 组件通信
- defineProps中的属性只读
- defineEmits: 声明触发的事件
- mitt: 全局事件总线插件
- v-model: 父子组件双向数据同步
- 通过props + 自定义事件实现父子组件数据同步
- 通过v-model实现父子组件数据同步
- v-model原理
- vue3.4版本使用v-model更为简洁
- useAttrs辅助函数
- 作用1: 子组件未使用props接收父组传递的属性,将会被添加到attrs属性中,可以通过useAttrs辅助函数获取
- v-bind绑定属性简写形式
- 作用2: 接收自定义事件和系统事件
- import x from xxx.vue报错
- vue3引入elment plus
组件通信
defineProps中的属性只读
在vue2中props中属性允许修改,但是提示警告,而vue3中的props属性是只读的,不能修改。
defineEmits: 声明触发的事件
<script setup lang="ts">
// 通过defineEmits声明自定义事件,如果包含了click事件,那么子组件的click事件将无法触发,而是将click事件作为自定义事件触发
let $emits = defineEmits(["childEvent"]);
const childEvent = () => {$emits("childEvent", "子组件参数");
};
</script>
mitt: 全局事件总线插件
vue2中全局事件总线通过对Vue原型对象添加一个vm实例,通过该vm实例实现全局事件,各组件使用this获取到该vm从而实现事件通信,而vue3中无法对Vue实例操作,且setup中无法通过this获取vm,因此需要借助插件实现全局事件总线。
mitt插件是一个轻量级的事件总线插件,使用起来非常简单,只需要在main.ts中引入并注册即可,然后在组件中使用即可。
bus/index.ts
import mitt from "mitt";
const $mitt = mitt();
export default $mitt;
// 组件定义事件
import $mitt from '../../bus';$mitt.on('childEvent1', (data) => {console.log('子组件1中接收子组件2传递的参数:', data);
});
// 其他组件触发事件
import $mitt from "../../bus";
const childEvent1 = (data: { info: string }) => {$mitt.emit("childEvent1", data);
};
v-model: 父子组件双向数据同步
通过props + 自定义事件实现父子组件数据同步
父组件:
<script setup lang="ts">
import Child from "./Child1.vue";
import { ref } from "vue";
let money = ref(1000);
// 父组件中修改v-model数据
function updateMoney(addMoney: number) {money.value += addMoney;
}
</script><template>v-model: 父子组件双向通信<div class="parent">父组件:<div>账户金额: <input type="text" v-model="money" /></div><div><Child :money="money" @update:money="updateMoney"> </Child></div></div>
</template>
子组件:
<script setup lang="ts">
// 声明自定义事件
let $emits = defineEmits<{(e: "update:money", money: number): void;
}>();
// 声明props属性
defineProps<{money: number;
}>();
// 子组件自定义事件中触发父组件自定义事件
const addMoney = (money: number) => {$emits("update:money", money);
};
</script><template><div class="child">子组件1: 父组件的账号金额: {{ money }}<button @click="addMoney(100)">修改父组件金额+100</button></div>
</template>
通过v-model实现父子组件数据同步
父组件:
<script setup lang="ts">
import Child from "./Child1.vue";
import { ref } from "vue";
let money = ref(1000);
</script><template>v-model: 父子组件双向通信<div class="parent">父组件:<div>账户金额:<input type="text" v-model="money" /><div><!-- <Child:modelValue="money"@update:modelValue="(newValue: number) => money = newValue"></Child>--><Child v-model="money"></Child></div></div></div>
</template>
子组件:
<script setup lang="ts">
// 定义 emit
let $emits = defineEmits<{(e: "update:modelValue", value: number): void;
}>();
// 定义 props
let props = defineProps<{modelValue: number;
}>();const addMoney = (money: number) => {$emits("update:modelValue", props.modelValue + money);
};
</script><template><div class="child">子组件1: 父组件的账号金额: {{ modelValue }}<button @click="addMoney(100)">修改父组件金额+100</button></div>
</template>
v-model原理
<Child v-model="money" />
原理:
1.通过props向子组件传递一个固定为modelValue
的属性,即 <Child modelValue="money" />
2.为子组件绑定一个固定为update:modelValue
自定义事件,回调逻辑也是固定的,就是把双向绑定的属性值替换为新值,即 <Child @update:modelValue="(newValue) => {money = newValue}" />
3.子组件声明modelValue
属性,并触发update:modelValue
自定义事件,将新的值传递给父组件
4.父组件接收到子组件传递的值,替换掉双向绑定的属性值,从而触发vue从新解析模板,更新父组件和子组件使用的双向绑定属性值
vue3.4版本使用v-model更为简洁
defineModel
useAttrs辅助函数
作用1: 子组件未使用props接收父组传递的属性,将会被添加到attrs属性中,可以通过useAttrs辅助函数获取
使用场景: 组件二次封装
对按钮组件二次封装
封装一个HintButton组件,
<script setup lang="ts">
import { useAttrs } from 'vue'
let $useAttrs = useAttrs();
console.log('$useAttrs:',$useAttrs);let $props = defineProps<{type: string
}>();
console.log('props:', $props);
</script><template><div class="hint-button"><el-button :icon="$attrs.icon" :type="$attrs.type">{{$attrs.content}}</el-button></div>
</template>
使用二次封装的按钮组件HintButton
<script setup lang="ts">
import { Delete } from "@element-plus/icons-vue";
import HintButtoon from "./HintButton.vue";
</script><template><div>子组件:<el-button type="primary" :icon="Delete">原始按钮</el-button><HintButtoon :icon="Delete" type="primary" content="二次封装按钮" /></div>
</template><style scoped>
.child {background-color: rgb(222, 189, 189);width: 200px;height: 200px;border: 1px solid blue;padding: 10px;margin: 5px;
}
</style>
v-bind绑定属性简写形式
$attrs对象中属性值有
{icon: Delete,type: 'primary',
}
<el-button v-bind:="$attrs"></el-button>
<el-button :="$attrs"></el-button>
<!-- 等价于 -->
<el-button :icon="$attrs.icon" :type="$attrs.type"></el-button>
作用2: 接收自定义事件和系统事件
<HintButtoon :icon="Delete" type="primary" content="二次封装按钮" title="删除按钮" @click="alert(1)" @hh="console.log(1)" />
1.当子组件只有一个根元素时,那么该元素继承父组件中为其添加的系统事件
2.子组件元素上使用:="$attrs"
: $attrs接收父组件为其添加的事件,并应用在该元素上
import x from xxx.vue报错
在vite-env.d.ts文件中添加如下代码:
/// <reference types="vite/client" />
declare module '*.vue' {import { ComponentOptions } from 'vue'const componentOptions: ComponentOptionsexport default componentOptions
}
vue3引入elment plus
自动导入element组件文档
各个组件使用文档