对于一些公共性比较强的UI,可以使用组件的方式对其进行存储。方便多次调用
一、基础使用
1、定义组件
在components
目录下新建一个.vue
文件, 用于存放组件内容
组件内简单写一点东西:
<script setup>
</script>
<template>
<h3>这是一个自定义的组件</h3>
</template>
2、使用组件
替换app.vue
内代码如下:
<script setup>
// 第一步:引入组件
import component from "./components/conmonent.vue"
</script>
<template>
<!--第二步:使用组件-->
<component/>
</template>
二、组件的注册方式
1、局部注册
上述的例子中就属于局部注册,要在那个文件中使用组件,就在那个文件中import
对应组件
2、全局注册
修改main.js
为下图所示:
然后使用下述代码替换掉app.vue
中的代码
<script setup>
</script>
<template>
<!--第二步:使用组件-->
<global-component/>
</template>
可以看到,此时app.vue
中已经取消了之前的import
。 实际效果仍跟基础使用中的示例一样。
后面使用到组件的例子中都会采用局部注册的方式去使用组件。方便阅读理解。实际使用的时候按需即可
三、动态组件
有些使用场景需要在多个组件之间来回切换,这里就需要用到动态组件的概念,使用
:is
关键字来完成
1、新建两个component
组件
component1:
<script setup>
</script>
<template>
<h3>第一个自定义组件</h3>
</template>
component2:
<script setup>
</script>
<template>
<h3>第二个自定义组件</h3>
</template>
代码很简单,只是一行打印而已
3.1、使用下述代码替换掉app.vue
中的代码
<script setup>
import { ref } from 'vue'
// 引入组件
import component1 from './components/conmonent1.vue'
import component2 from './components/component2.vue'
// 声明一个默认组件
const currentTab = ref('component1')
// 将组件放入一个字典中
const tabs = {
component1,
component2,
}
</script>
<template>
<!--点击按钮切换到对应组件-->
<button v-for="(_, tab) in tabs" :key="tab" @click="currentTab = tab">{{ tab }}</button>
<component :is="tabs[currentTab]"></component>
</template>
3.2 或者使用下述代码替换app.vue
中的代码:
<script setup>
import { ref } from 'vue'
// 引入组件
import component1 from './components/conmonent1.vue'
import component2 from './components/component2.vue'
// 声明一个默认组件
const currentTab = ref('component1')
// 将组件放入一个字典中
const tabs = {
"component1":component1,
"component2":component2
}
function changeComponent() {
currentTab.value = currentTab.value == "component1" ? "component2" : "component1"
}
</script>
<template>
<!--点击按钮切换到对应组件-->
<button @click="changeComponent">切换组件</button>
<component :is="tabs[currentTab]"></component>
</template>
四、组件数据传递1:defineProps
使用组件过程中可能会涉及到数据的传递,不同组件之间的数据是没办法直接使用的,使用
defineProps
关键字完成数据传递
先新建一个组件,并在app.vue
中使用该组件
组件代码:
<script setup>
</script>
<template>
<h3>自定义的组件</h3>
</template>
app.vue
代码:
<script setup>
import component1 from "./components/conmonent1.vue"
</script>
<template>
<component1/>
</template>
此时访问主页效果应该是这样的:
在app.vue
中向组件传递数据:
组件中接收并使用数据:
最终效果如下图:
特别注意:
- 上述的数据传递方式只能从父组件传递给子组件,无法反向传递
- 如果要传递的是一个动态可变的数据,则需要使用
:
对变量进行绑定,例如:
<component1 :param1="从父组传递过过来的第一个参数"/>
3. 不同类型的数据传递,传递的时候都是使用双引号对数据进行包裹
<component1 :name="张三" :age="18"/>
4. 接收数据的时候可以将defineProps
赋值给变量,例如:
<script setup>
// 第一步:接收从父组件传递过来的数据并赋值给变量
const props=defineProps(['param1', 'param2'])
</script>
<template>
<h3>自定义的组件</h3>
<!--第二步:使用从父组件传递过来的数据-->
<p>{{props.param1}}</p>
<p>{{props.param2}}</p>
</template>
五、数据传递2:子组件向父组件传递数据
1、第一种方式:props
正常来讲
props
是没有办法反向传递数据给父组件的。但是可以通过使用props
向子组件传递一个函数。让函数使用到子组件的参数并传递回来。
app.vue
代码如下:
<script setup>
import component1 from "./components/conmonent1.vue"
import {ref} from "vue";
// 第一步:声明一个变量用于存储从子组件传递过来的数据
const data = ref('')
// 第二步:声明一个方法用于传输给子组件,方法内将子组件参数进行赋值, 这里注意不能有返回值,否则子组件那边也会产生打印
function dataTransmission(param1){
data.value = param1
}
</script>
<template>
<!--第三步:将声明的方法传递给子组件。这里注意要使用冒号-->
<component1 :title="dataTransmission"/>
<!--最后:打印结果-->
<p>这是从子组件传递过来的数据:{{data}}</p>
</template>
组件代码如下:
<script setup>
import {ref} from "vue";
// 第一步:获取子组件传递过来的方法
defineProps(['title'])
// 第二步:定义一个变量用于存储数据
const msg = ref('子组件数据')
</script>
<template>
<h3>自定义的组件</h3>
<!--第三步:使用从父组件传递过来的函数将定义的变量数据传递出去-->
<p>{{title(msg)}}</p>
</template>
最终效果如下:
2、第二种方式:自定义事件:emit
通过使用
$emit
自定义事件的方式从子组件向父组件传递数据
为了看起来更加清晰和直观。这里用截图的方式存放代码
效果如下:
3、第三种方式:插槽:slot
这种方式的数据传递主要传递的是html
父组件调用子组件的时候,在组件块中传递html
, 子组件使用slot
来接收父组件传递过来的html
并进行展示。结果如下:
slot
相关知识点如下:
- 默认值:可以在子组件
slot
标签对中定义默认值。当父组件有数据传递过来的时候使用父组件传递过来的数据;当父组件没有传递数据过来恩等时候使用子组件自定义的默认值
- 插槽名称:父组件传递数据的过程中可以使用
v-slot
关键字进行插槽命名。子组件使用name
关键字来获取对应的插槽内容进行展示。使插槽的使用更加灵活。例如:
- 插槽数据传递:当子组件既需要自己本身的数据,又需要父组件传递过来的模板内容的情况下:可以先将子组件中的数据传递给父组件,然后由父组件将数据通过插槽传递给子组件,例如:
- 当插槽数据传递和插槽名称需要同时使用时,使用又有所不同:
六、组件保持存活:keep-avive
每次进行组件切换的时候都会走一遍组件的声明周期,如果组件切换频率较高的话,会造成不必要的消耗。因此,有了保持存活的需求。 保持组件存活使用
keep-avive
关键字
测试代码如下:
上述利用了动态切换组件,并且在其中一个组件中对组件内数据进行了修改,用于看效果使用
效果如下:
通过上述两个示例的操作对比,应该很容易理解组件保持存活的概念
七、异步组件:defineAsyncComponent
有时候,我们希望组件是在需要的时候进行异步加载的。以此来减缓整个页面的加载时长,提高体验感,使用
defineAsyncComponent
关键字来完成
效果预览:
通过上述的截图可以看出:组件2是在切换的时候才进行加载的。再来看下同步组件的表现,做个对比
通过上述的截图可以看出:组件1和组件2都是在页面一开始就加载好了的。
八、依赖注入:provide
和inject
假设有三个组件,组件1,组件2,组件3: 组件1引用组件2,组件2引用组件3,组件3要使用组件1传递的数据。按照前面学到的: 组件1要将数据传递给组件2,组件2要将数据传递给组件3,然后组件3再使用传递过来的数据 此时使用依赖注入就可以轻松解决此问题:基础使用语法如下:
效果展示:
注意:
- 如果要修改传递过来的数据:传递的时候传递一个可变的变量过去,例如:
import {provide, ref} from "vue";
const message= ref('界面1传递过来的数据')
// 组件1使用provide方法传递数据, 第一个参数msg是用于接收的数据名, 第二个参数是具体数据
provide('msg', message)
- 可以在
main.js
中进行全局注册,这样全局所有的组件都可以使用到该数据(不推荐)
const app = createApp(App)
// main.js中配置全局数据传递
app.provide('msg', 'main.js传递出来的数据')
app.mount('#app')
- 任意一个子组件都可以使用父组件传递出来的数据