前言
现在市面上有很多成熟的UI组件库,大多时候也是直接拿过来用,当某一天项目中那些UI组件库满足不了我们或组件风格不是我们想要的,这时就需要自己封装组件来实现,下面列举五种常见的组件封装,当然是比不上那些优秀UI组件库的,我觉得封装组件的过程也是提高代码能力的方式吧!虽然写的不咋地哈,我也很快乐!!!😜😜😜 注意:本文技术栈:Vue3+TypeScript
字体图标地址: //at.alicdn.com/t/font_2143783_iq6z4ey5vu.css
轮播图
参数: | 说明 | 类型 | 默认值 |
---|---|---|---|
interval | 自动切换的时间间隔,单位为毫秒 | number | 1500 |
autoPlay | 是否开启自动切换 | boolean | true |
imagesList | 循环的图片数据 | Array | |
height | 轮播图的高度单位px | number | 450 |
width | 轮播图的宽度单位px | number | 100% |
实现效果图
轮播图基本使用
App.vue
举个栗子:
<script lang="ts" setup>
// 导入轮播图组件
import GoodsImages from './components/GoodsImages/GoodsImages.vue';
import { ref } from 'vue';
const imagesList = ref([
{
id:0,
img:'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aad8fefad8484117b9334982e3834c04~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?'
},
{
id:1,
img:'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/563194bb6765480698d2b3ca7b4238ef~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?'
},
{
id:2,
img:'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9720ff461a2446948dba9c4ec1da06e8~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?'
},
])
</script>
<template>
<GoodsImages :interval="3000" autoPlay :list="imagesList" :height="400" :width="700"></GoodsImages>
</template>
代码
GoodsImages.vue
<script lang="ts" setup>
import {ref,onMounted} from 'vue'
type imglist = {
id:number,
img:string
}
const {interval,autoPlay,list} = defineProps<{
interval:number, // 自动切换的时间间隔,单位为毫秒
autoPlay:boolean, // 是否开启自动切换
list:imglist[], // 循环的图片数组
height?: number, // 轮播图的高度单位px
width?:number// // 轮播图的宽度单位px
}>()
let active = ref(0)
// 上一张
const prev = ()=>{
active.value === 0 ? active.value = list.length-1 : active.value--
// if(active.value === 0){
// active.value = list.length-1
// }else{
// active.value--
// }
}
// 下一张
const next = ()=>{
active.value >= list.length-1 ? active.value = 0 : active.value++
}
// 鼠标经过小圆点切换
const ringlet = (index:number)=>{
active.value = index
}
const rbt = ()=>{
if(autoPlay){
setInt = setInterval(()=>{
next()
},interval)
}
}
let setInt = -1
onMounted(()=>{
rbt()
})
// 鼠标经过图片停止定时器
const stop = () =>{
clearTimeout(setInt)
}
// 鼠标离开开启定时器
const play =()=>{
rbt()
}
</script>
<template>
<div class="xtx-carousel" @mouseenter="stop" @mouseleave="play" :style="{height:height+'px',width:width+'px'}">
<ul class="carousel-body">
<li class="carousel-item " :class="{fade: active=== item.id}" v-for="item in list" :key="item.id">
<img :src="item.img" alt=""/>
</li>
</ul>
<a href="javascript:;" class="carousel-btn prev" @click="prev"><i class="iconfont icon-angle-left"></i></a>
<a href="javascript:;" class="carousel-btn next" @click="next"><i class="iconfont icon-angle-right"></i></a>
<div class="carousel-indicator">
<span :class="{active:active===index}" v-for="(item,index) in list.length" :key="index" @mouseenter="ringlet(index)"
></span>x
</div>
</div>
</template>
<style scoped lang="less">
a{
text-decoration: none;
}
.xtx-carousel {
width: 100%;
height: 100%;
min-width: 300px;
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>
骨架屏
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
bg | 骨架屏背景颜色 | string | #efefef |
width | 骨架屏宽度px | number | 100 |
height | 骨架屏高度px | number | 30 |
br | 骨架屏换行 | string | inline-block,block |
animated | 是否开启动画1 | boolean | false |
fade | 是否开启闪烁动画2 | boolean | false |
骨架屏基本使用
- 普通骨架屏
import XtxSkeleton from './components/XtxSkeleton/XtxSkeleton.vue'; // 导入骨架屏组件
<XtxSkeleton br="block"></XtxSkeleton>
<XtxSkeleton :width="200"></XtxSkeleton>
- 进阶骨架屏
<template>
<XtxSkeleton bg="#ef3fef" br="block" animated fade></XtxSkeleton>
<XtxSkeleton bg="#ef3fef" animated fade :width="200"></XtxSkeleton>
<XtxSkeleton bg="#ef3fef" br="block" animated fade :width="300"></XtxSkeleton>
</template>
代码
<script lang="ts" setup>
import { ref } from "@vue/reactivity"
const a = ref(0)
defineProps<{
bg?:string, // 背景颜色
width?:number, // 骨架宽度
height?:number, // 骨架高度
br?:string ,// 骨架换行
animated?:boolean,// 是否开启动画
fade?:boolean, // 是否开启闪烁动画
}>()
</script>
<template>
<div
class="xtx-skeleton"
:style="{width:width+'px',height:height+'px',display:br}"
:class="{fade:fade,shan:animated}"
>
<!-- 1 盒子-->
<div class="block" :style="{background:bg}"></div>
<!-- 2 闪效果 xtx-skeleton 伪元素 --->
</div>
</template>
<style scoped lang="less">
.xtx-skeleton {
display: inline-block;
position: relative;
overflow: hidden;
vertical-align: middle;
margin-top: 10px;
width: 100px;
height: 30px;
.block {
width: 100%;
height: 100%;
border-radius: 2px;
background: #efefef;
}
}
.shan {
&::after {
content: '';
position: absolute;
animation: shan 1.5s ease 0s infinite;
top: 0;
width: 50%;
height: 100%;
background: linear-gradient(
to left,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.3) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: skewX(-45deg);
}
}
@keyframes shan {
0% {
left: -100%;
}
100% {
left: 120%;
}
}
.fade {
animation: fade 1s linear infinite alternate;
}
@keyframes fade {
from {
opacity: 0.2;
}
to {
opacity: 1;
}
}
</style>
button按钮
参数 | 说明 | 类型 | 默认 | 可选值 |
---|---|---|---|---|
mini | 尺寸 | string | large | middle/small/mini |
type | 类型 | string | default | primary/plain/gray |
button按钮基本用法
<XtxButton size="mini" type='default'>按钮</XtxButton>
<XtxButton size="mini" type='gray'>按钮</XtxButton>
<XtxButton size="mini" type='plain'>按钮</XtxButton>
<XtxButton size="mini" type='primary'>按钮</XtxButton>
代码
<script lang="ts" setup>
// size='large',type='default'默认值设置
const {size='large',type='default'} = defineProps<{
size: 'large' | 'middle' | 'small' | 'mini',
type: 'default' | 'primary' | 'plain' | 'gray',
}>()
</script>
<template>
<button class="xtx-button ellipsis" :class="[size, type]">
<slot />
</button>
</template>
<style scoped lang="less">
.xtx-button {
appearance: none;
border: none;
outline: none;
background: #fff;
text-align: center;
border: 1px solid transparent;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
.large {
width: 240px;
height: 50px;
font-size: 16px;
}
.middle {
width: 180px;
height: 50px;
font-size: 16px;
}
.small {
width: 100px;
height: 32px;
}
.mini {
width: 60px;
height: 32px;
}
.default {
border-color: #e4e4e4;
color: #666;
}
.primary {
border-color:#27ba9b;
background:#27ba9b;
color: #fff;
}
.plain {
border-color:#27ba9b;
color:#27ba9b;
background: lighten(#27ba9b, 50%);
}
.gray {
border-color: #ccc;
background: #ccc;
color: #fff;
}
</style>
面包屑
消息提示框
参数 | 说明 | 类型 | 默认值 | 可选值 |
---|---|---|---|---|
type | 类型 | string | --- | success/errorwarning |
text | 提示文字 | string | --- | ---- |
消息提示框基本使用
- 用法一:
<template>
<XtxMessage type="success" text="成功消息提示!"></XtxMessage>
<XtxMessage type="warning" text="警告消息提示!"></XtxMessage>
<XtxMessage type="error" text="错误消息提示!"></XtxMessage>
</template>
- 用法二:
<script setup lang="ts">
import Message from './components/XtxMessage';
Message.success('成功!')
Message.warning('警告!')
Message.error('错误!')
</script>
代码
用法一代码:SyMessage.vue
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
type MessageType = '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)',
},
}
const isShow = ref(false)
onMounted(()=>{
isShow.value = true
})
</script>
<template>
<Transition name="down">
<div class="xtx-message" :style="style[type]" v-if="isShow">
<i class="iconfont" :class="style[type].icon"></i>
<span class="text">{{text}}</span>
</div>
</Transition>
</template>
<style scoped lang="less">
.down {
&-enter {
&-from {
transform: translate3d(0, -75px, 0);
opacity: 0;
}
&-active {
transition: all 0.5s;
}
&-to {
transform: none;
opacity: 1;
}
}
}
.xtx-message {
width: 300px;
height: 50px;
position: fixed;
z-index: 9999;
left: 50%;
margin-left: -150px;
top: 25px;
line-height: 50px;
padding: 0 25px;
border: 1px solid #e4e4e4;
background: #f5f5f5;
color: #999;
border-radius: 4px;
i {
margin-right: 4px;
vertical-align: middle;
}
.text {
vertical-align: middle;
}
}
</style>
用法二代码:ts代码
import { h, render } from 'vue'
import XtxMessage from './SyMessage.vue' // 导入SyMessage.vue
type MessageType = 'success' | 'error' | 'warning'
type Props = {
type:MessageType
text: string
duration?: number
}
const div = document.createElement('div')
div.setAttribute('class', 'xtx-message-container')
document.body.appendChild(div)
export default function Message({ type, text, duration = 2000 }: Props) {
const vNode = h(XtxMessage, { type, text })
render(vNode, div)
setTimeout(() => {
render(null, div)
}, duration)
}
Message.error = function (text: string, duration = 2000) {
Message({
type: 'error',
text,
duration,
})
}
Message.success = function (text: string, duration = 2000) {
Message({
type: 'success',
text,
duration,
})
}
Message.warning = function (text: string, duration = 2000) {
Message({
type: 'warning',
text,
duration,
})
}
结束语
虽然写的不咋地哈,但我还是很快乐!!!😜😜 还请前端大佬指点指点 后续还会不断更新 请继续关注 感谢阅读^_^