一、组件化
解释:正如上图所示,一个页面可以分为多块部分,但是如果把所有代码都写在一个vue文件当中,维护性和可读性都会很差,所以需要用到组件化思维->创建多个vue文件每个里面写一部分代码,然后集中在一个主的vue文件调用
二、组件的注册
1.全局
解释:顾名思义,全局注册使得组件可以在每个vue文件里面直接被调用
main.js
import { createApp } from 'vue'
import App from './App.vue'
import header from './views/header.vue'
const app = createApp(App)
app.component("Gaoheader",header)
// 多个可链式调用app.component('ComponentA', ComponentA).component('ComponentB', ComponentB).component('ComponentC', ComponentC)
app.mount('#app')
App.vue
<template>
<div>
<Gaoheader></Gaoheader>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
2.局部
解释:局部就是只有当前块内才可使用
2.1 选项式
<template>
<div>
<Gaoheader></Gaoheader>
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
components: {
Gaoheader
}
}
</script>
<style>
</style>
2.2 组合式
<template>
<div>
<ComponentA ></ComponentA >
</div>
</template>
// setup可以直接去注册不用额外操作
<script setup>
import ComponentA from './ComponentA.vue'
</script>
三、深入组件
1.props
解释:props的作用是父组件给子组件传值使用
1.1 选项式
父组件:
<template>
<div>
<Gaoheader :box=box></Gaoheader><!-- 主要代码-->
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
box :5558,
}
},
components: {
Gaoheader
}
}
</script>
<style>
</style>
子组件:
<template>
<div>
{{okko}}
{{box}}
<br>
</div>
</template>
<script>
export default {
props:['box'],//主要代码
data() {
return {
okko: 153445323,
}
},
}
</script>
<style>
</style>
1.2 组合式
父组件
test.vue
<template>
<div>
<Gaoheader :box=box></Gaoheader><!-- 主要代码-->
</div>
</template>
<script lang="ts" setup>
import Gaoheader from './test1.vue'
import { ref } from 'vue'
let box = ref('11111111111111111')
</script>
<style></style>
子组件
test1.vue
<template>
<div>
{{ box.box }}
<br>
</div>
</template>
<script lang="ts" setup>
import { ref, defineProps } from 'vue'
defineProps(['box'])
console.log(box.box)
</script>
<style></style>
2.事件
解释:其使用this.$emit('名字',数值)
,主要是子组件给父组件传递值使用
2.1 选项式
父组件
<template>
<div>
<Gaoheader @name="dosss"></Gaoheader> <!-- 主要代码-->
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
box :5558,
}
},
components: {
Gaoheader
},
methods:{
// 主要代码
dosss(value){
console.log(value)
}
}
}
</script>
<style>
</style>
子组件
<template>
<div>
{{okko}}
<button @click="sub"></button>
<br>
----------
<br>
----------
<br>
----------
</div>
</template>
<script>
export default {
data() {
return {
okko: 153445323,
}
},
methods:{
sub(){
this.$emit('name',this.okko)//主要代码
}
}
}
</script>
<style>
</style>
2.2 组合式
父组件
<template>
<div>
<Gaoheader :box=box @name="dosss"></Gaoheader><!-- 主要代码-->
</div>
</template>
<script lang="ts" setup>
import Gaoheader from './test1.vue'
import { ref } from 'vue'
let box = ref('11111111111111111')
function dosss(v){
console.log(v)
}
</script>
<style></style>
子组件
<template>
<div>
<button @click="go">1</button>
</div>
</template>
<script lang="ts" setup>
import { ref, defineProps,defineEmits } from 'vue'
const emit = defineEmits()
defineProps(['box'])
const okko = ref('151dwadwa515')
console.log(box.box)
function go(){
emit('name',okko.value)
}
</script>
<style></style>
3.provide/inject
解释:provide/inject适用于跨多层组件传递数据,简化了深层次的组件之间的通信。适用于在高阶组件或基础组件库中使用,可以将实现细节封装起来,子孙组件只需要知道如何使用注入的数据。可以动态提供数据,它可以利用Vue的响应式系统动态地提供数据给子孙组件。
缺点:
- provide/inject可能会导致组件间的依赖关系不清晰,因为组件的数据来源不再是明显的props;
- 使用props或provide/inject的组件结构、复杂度以及特定的需求来决定。理想情况下,对于直接父子关系的简单通信,应使用props,而对于跨多层级的复杂场景,特别是在开发基础组件库时,provide/inject可能是更好的选择。重要的是保持数据流的清晰和组件解耦,以便于维护和扩展。
- 过度使用provide/inject可以导致组件之间产生复杂和难以理解的联系,尤其是在大型应用中
用法:
爷组件:
<script setup lang="ts">
// 爷组件向provide值或者函数(子孙组件可直接调用该函数)
const data = 5
const modal = ref('9')
provide('list', data)
provide('modal', modal)
</script>
子孙组件:
// 子孙组件无需复杂操作即可获取爷组件传来的值
// 下面有一个重点,对于provide传来的数据其第一时间传来的值可能没有任何值或者属性就传过来了(例如要异步先向后端获取数据),这时我们需要配合v-if,当有值时再开始渲染组件,不然会发生意外的错误
<template>
<div v-if="modal && list">
</div>
</template>
<script setup>
import { inject } from 'vue'
// 接收project传来的数值
const modal = inject('modal')
const list = inject('list')
</script>
4.mitt
解释:mitt是一个简单的事件发射器/事件总线,允许不相关的组件相互通信,处理多个组件之间的松耦合通信,需要广播或监听全局事件,而这些组件不必维持直接的、层级关系上的联系,那么mitt可能是更好的选择
安装:npm install mitt
创建文件并写入:
// bus.js
import mitt from 'mitt'
export const eventBus = mitt()
使用方法:
import { eventBus } from '../../bus';
eventBus.emit(name,data)
//触发事件,两个参数:name:触发的方法名,data:需要传递的参数
eventBus.on(name,callback)
//绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
eventBus.off(name,callback)
//解绑事件,一个参数:name:需要解绑的方法名,callback:on中绑定的函数名
示例(目标A组件调用B组件的函数):
A组件:
import { eventBus } from '../../bus';
export default {
methods: {
active(id){
eventBus.emit('chat', id);//表示使用active这个函数将调用B里面对应填入chat的相关操作
},
}
}
B组件:
import { eventBus } from '../../bus';
export default {
created() {
eventBus.on('chat', this.add_chat);
},
beforeUnmount() {
eventBus.off('chat', this.add_chat);
},
}
5.插槽
解释:如下图,开发了一个组件,但是里面图像(如园和矩形),需要根据需求变更,包括里面的文字,这时候就需要到了插槽
5.1 基本使用
解释:可以直接在父组件写入内容,配置到子组件当中
父组件
<template>
<div>
<Gaoheader>245354354</Gaoheader><!-- 主要代码-->
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
}
},
components: {
Gaoheader
},
methods:{
}
}
</script>
<style>
</style>
子组件
<template>
<div>
<slot></slot><!-- 主要代码-->
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods:{
}
}
</script>
<style>
</style>
5.2 具名插槽
解释:就如上介绍一般,具名插槽比满足上面图片的需求,在某个位置插入数值
父组件
<template>
<div>
<Gaoheader>
<template v-slot:bug><!-- 主要代码-->
<button>123</button><!-- 主要代码-->
</template><!-- 主要代码-->
<template v-slot:nobug><!-- 主要代码-->
<input type="text"><!-- 主要代码-->
</template><!-- 主要代码-->
</Gaoheader>
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
}
},
components: {
Gaoheader
},
methods:{
}
}
</script>
<style>
</style>
子组件
<template>
<div>
<slot name="bug"></slot><!-- 主要代码-->
<slot name="nobug"></slot><!-- 主要代码-->
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods:{
}
}
</script>
<style>
</style>
5.3 默认内容
解释:当父组件没有使用子组件里面的slot时,子组件展示默认内容
父组件
<template>
<div>
<Gaoheader><!-- 主要代码-->
</Gaoheader><!-- 主要代码-->
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
}
},
components: {
Gaoheader
},
methods:{
}
}
</script>
<style>
</style>
子组件
<template>
<div>
<slot name="bug">123</slot><!-- 主要代码-->
<slot name="nobug">abc</slot><!-- 主要代码-->
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods:{
}
}
</script>
<style>
</style>
5.4 作用域插槽
解释:作用域插槽可以让父组件获取子组件的值
父组件
<template>
<div>
<Gaoheader>
<template v-slot:bug="hy"><!-- 主要代码-->
<button>{{hy}}</button>
</template>
<template v-slot:nobug>
<input type="text">
</template>
</Gaoheader>
</div>
</template>
<script>
import Gaoheader from './views/header.vue'
export default {
data(){
return {
}
},
components: {
Gaoheader
},
methods:{
}
}
</script>
<style>
</style>
子组件
<template>
<div>
<slot name="bug" :list="list">123</slot><!-- 主要代码-->
<slot name="nobug">abc</slot><!-- 主要代码-->
</div>
</template>
<script>
export default {
data() {
return {
list:[1,2,3]//主要代码
}
},
methods:{
}
}
</script>
<style>
</style>