如果你有梦想,就要守护它。 --当幸福来敲门
什么是组件
对功能、ui样式的封装,一个功能或者一个ui样式就是一个组件,导航栏,banner,页脚等等这些功能、样式都是组件
按组件注册方式分类:vue将组件分为全局组件和局部组件
什么时候需要封装
如果一块内容在项目中出现了两次就要考虑是否应进行封装
一个组件、一个函数、一个css 只要是需要多次使用的都可以考虑封装
如何封装一个组件呢?
1.我们在写代码的时候都会把封装的组件,或者公共样式放在一个统一的文件夹里面
2.进行全局注册或者局部注册
全局注册: 在components 下的index 进行全局注册
之后在global.d.ts文件里进行泛型约束
3.在需要使用的地方使用就OK啦
介绍几个我自己封装的小组件吧!
一 . 轮播图组件
1.轮播图播放逻辑
<script lang="ts" setup name="XtxCarousel">
// BannerItem 轮播图类型
import { BannerItem } from '@/types/data'
import { onBeforeUnmount, onMounted, ref } from 'vue';
// 接收父组件传来的数据
const { slides, autoPlay = true ,duration=1 } = defineProps<{
slides:BannerItem[]
autoPlay?:boolean
duration?:number
}>()
const active = ref(0)
// 点击右箭头换轮播图
const zuo = () =>{
active.value --
if(active.value < 0){
active.value = slides.length-1
}
}
// 点击左箭头换轮播图
const you = () =>{
active.value ++
if(active.value === slides.length){
active.value = 0
}
}
// 组件挂载后,自动播放
onMounted(()=>{
start()
})
// 组件卸载之前执行的函数
// 组件结束--停止播放
onBeforeUnmount(()=>{
stop()
})
let time = -1
// 如果开启了自动播放,则每隔 duration 去播放下一个 hNext()
// 鼠标离开要继续播放
const start = () =>{
if(autoPlay){
// 开启定时器
time = window.setInterval(()=>{
// 播放
you()
},duration)
}
}
// 鼠标hover要暂停播放
const stop = () =>{
clearInterval(time)
}
</script>
// 样式
<template>
<!-- @mouseleave="start" 鼠标移入 -->
<!-- @mouseenter="stop" 鼠标移出 -->
<div class="xtx-carousel" @mouseleave="start" @mouseenter="stop">
<ul class="carousel-body">
<li
class="carousel-item"
:class="{fade: active === index }"
v-for="(item,index) in slides " :key="item.id">
<RouterLink to="/">
<img
:src="item.imgUrl"
alt=""
/>
</RouterLink>
</li>
</ul>
<a href="javascript:;" class="carousel-btn prev" @click="zuo"><i class="iconfont icon-angle-left"></i></a>
<a href="javascript:;" class="carousel-btn next" @click="you"><i class="iconfont icon-angle-right"></i></a>
<div class="carousel-indicator">
<span
v-for="( it,ind ) in slides " :key="it.id"
:class="{active:active === ind }"></span>
</div>
</div>
</template>
<style scoped lang="less">
.xtx-carousel {
width: 100%;
height: 100%;
min-width: 300px;
min-height: 150px;
position: relative;
.carousel {
&-body {
width: 100%;
height: 100%;
}
&-item {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0; // 不可见
transition: opacity 0.5s linear;
&.fade {
opacity: 1; // 可见
z-index: 1;
}
img {
width: 100%;
height: 100%;
}
}
&-indicator {
position: absolute;
left: 0;
bottom: 20px;
z-index: 2;
width: 100%;
text-align: center;
span {
display: inline-block;
width: 12px;
height: 12px;
background: rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
~ span {
margin-left: 12px;
}
&.active {
background: #fff;
}
}
}
&-btn {
width: 44px;
height: 44px;
background: rgba(0, 0, 0, 0.2);
color: #fff;
border-radius: 50%;
position: absolute;
top: 228px;
z-index: 2;
text-align: center;
line-height: 44px;
opacity: 0;
transition: all 0.5s;
&.prev {
left: 20px;
}
&.next {
right: 20px;
}
}
}
&:hover {
.carousel-btn {
opacity: 1;
}
}
}
</style>
2.类型 (根据自己的项目写自己的类型哦)
// 轮播图类型
export type BannerItem = {
hrefUrl: string
id: string
imgUrl: string
type: string
}
3.全局注册
import type { App } from 'vue'
import carousel from './XtXCarousel/XtXCarousel.vue'
export default {
install(app: App) {
app.component(carousel.name, XtXCarousel)
}
}
4.使用组件
<!-- 父传子,将数据传给组件 -->
<!-- 自动播放 autoPlay 切换间隔时间 :duration="3000" -->
<XtxCarousel :slides="home.bannerList" autoPlay :duration="1000"></XtxCarousel>
二 .消息组件
1.先创建个组件
<!-- 消息提示组件 -->
<script lang="ts" setup name="XtxMessage">
// 引入 类型
import { MessageType } from './type';
defineProps<{type:'success' | 'error' | 'warning'}>()
defineProps<{
type:MessageType,
text:string
} >()
// 定义一个对象,包含三种情况的样式,对象key就是类型字符串
三种提示情况
const style = {
warning: {
icon: 'icon-warning',
color: '#E6A23C',
backgroundColor: 'rgb(253, 246, 236)',
borderColor: 'rgb(250, 236, 216)',
},
error: {
icon: 'icon-shanchu',
color: '#F56C6C',
backgroundColor: 'rgb(254, 240, 240)',
borderColor: 'rgb(253, 226, 226)',
},
success: {
icon: 'icon-queren2',
color: '#67C23A',
backgroundColor: 'rgb(240, 249, 235)',
borderColor: 'rgb(225, 243, 216)',
},
}
</script>
<template>
<div class="xtx-message" :style="style[type]">
<i class="iconfont" :class="style[type].icon"></i>
<span class="text"><slot></slot></span>
// 提示文字 由插槽传过来
<span class="text">{{text}}</span>
</div>
</template>
2.定义写类型
export type MessageType = 'success' | 'error' | 'warning'
export type Message = {
type: MessageType
text: string
}
3.通过代码的方式去渲染 创建的组件vue组件
创建一个TS文件在组件旁
// 导入XtxMessage.vue组件
// 通过代码的方式去渲染它
import { h, render } from 'vue'
import { Message } from './type'
import XtxMessage from './XtxMessage.vue'
// 创建一个dom容器
// 把这个容器添加在body上
const div = document.createElement('div')
div.className = "xtx-message-container"
document.body.appendChild(div)
let time = -1
// 调用这个函数
// h的作用是: 产生虚拟DOM
// render 的作用是将虚拟的DOM渲染成真实的DOM中
export default function Message(obj: Message){
const vNode = h(XtxMessage, { type: obj.type, text: obj.text})
// 把虚拟dom放入上面定义的容器中
render(vNode, div)
// 清除定时器
clearTimeout(time)
time = window.setTimeout(()=>{
render(null,div)
},obj.duration||3000)
}
Message.success =(value:string)=>{{
Message({ type:"success",text:value , duration: 1500})
}}
Message.error =(value:string)=>{{
Message({ type:"error",text:value , duration: 1500})
}}
Message.warning =(value:string)=>{{
Message({ type:"warning",text:value , duration: 1500})
}}
4.使用
<script setup lang="ts">
import Message from '@/components/XtxMessage'
//使用
Message.success('我还好')
Message.error('我还好')
Message.warning('我还好')
// Message({
// type:'success',
// text:'你好吗'
// })
</script>
<template>
<div id="div"></div>
</template>
三 .单选框
1.创建组件
<script lang="ts" setup name="XtxCheckbox">
const { modelValue } = defineProps<{
modelValue:boolean
}>()
// 通知父组件 ,改变状态,取反
const emit = defineEmits<{
(e: 'update:modelValue', val: boolean): void
}>()
// 点击进行取反
const add = () =>{
emit('update:modelValue', !modelValue)
}
// 原版
// const add = () =>{
// emit('update:modelValue', false)
// }
// const addList = () =>{
// emit('update:modelValue', true)
// }
</script>
<template>
<div class="xtx-checkbox">
<!-- 选中时,要显示的图标 -->
<i @click="add" v-if="modelValue" class="iconfont icon-checked"></i>
<!-- 未选中时,要显示的图标 -->
<i @click="add" v-else class="iconfont icon-unchecked"></i>
<span> <slot/> </span>
</div>
</template>
<style scoped lang="less">
.xtx-checkbox {
display: inline-block;
margin-right: 2px;
.icon-checked {
color: @xtxColor;
~ span {
color: @xtxColor;
}
}
i {
position: relative;
top: 1px;
}
span {
margin-left: 2px;
}
}
</style>
2.注册全局组件
前面轮播图有就不写了
3.使用
<!-- 确认框 -->
<XtxCheckbox v-model="isAgree">我已同意</XtxCheckbox>
告诉你一个万能的方法
当然了不会封装也没事
这影响我单手开法拉利吗