前言
实现效果: 折叠版,默认收起内容,点击展开。
实现思路: 使用canvas绘画横线和圆形以及箭头图标,通过slot插槽放置收起内容。
背景: 使用框架vue3,使用组件库Vant@3.6.5
实现效果:
代码
template
<template>
<div class="encCollapseStyle">
<canvas id="myCanvas2" :width="clientWidth" :height="clientHeight" style="display: none"
>您的浏览器不支持 HTML5 canvas 标签。
</canvas>
<canvas id="myCanvas1" width="40" height="20" style="display: none"
>您的浏览器不支持 HTML5 canvas 标签。
</canvas>
<div v-if="!isOpen">
<div @click="clickOpen(true)" style="text-align: center; height: 0.6rem; font-size: 0.3rem">
<img :src="blueCircle" />
<span class="openCollapse">展开</span>
<img :src="arrow" :width="imgWidth" style="padding-bottom: 0.072rem" />
</div>
</div>
<div v-if="isOpen">
<!-- 插槽-内容 -->
<slot></slot>
</div>
</div>
</template>
script setup
根据设备适配圆形半径
判断设备类型
// 1.判断设备类型
const judgIsEquipmentType = () => {
var ua = navigator.userAgent,
isWindowsPhone = /(?:Windows Phone)/.test(ua),
isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
isAndroid = /(?:Android)/.test(ua),
isFireFox = /(?:Firefox)/.test(ua),
isChrome = /(?:Chrome|CriOS)/.test(ua),
isTablet =
/(?:iPad|PlayBook)/.test(ua) ||
(isAndroid && !/(?:Mobile)/.test(ua)) ||
(isFireFox && /(?:Tablet)/.test(ua)),
isPhone = /(?:iPhone)/.test(ua) && !isTablet,
isPc = !isPhone && !isAndroid && !isSymbian;
if (isAndroid || isPhone) {
// 手机
return 'isAndoidOrPhone';
} else if (isTablet) {
// 平板
return 'isTablet';
} else if (isPc || isChrome) {
// 电脑
return 'isPc';
}
};
由设备类型确定圆形半径
// 由设备类型确定圆形半径
const judeCircleRadius = () => {
let res = judgIsEquipmentType();
if (res === 'isAndoidOrPhone') {
radius = 2.5;
imgWidth.value = 11;
clientHeight.value = 24;
marginWidth.value = 17;
}
if (res === 'isTablet') {
radius = 5.5;
imgWidth.value = 22;
clientHeight.value = 27;
marginWidth.value = 36;
}
if (res === 'isPc') {
radius = 8.5;
imgWidth.value = 30;
clientHeight.value = 30;
marginWidth.value = 23;
}
};
canavs绘制图形图片
// 绘制蓝色圆圈○
const convertImageToCanvas = (
r,
lineWidth,
width,
marginWidth,
circleColor,
circleBorderColor = '#0084FF',
height = 20,
) => {
// 处理宽度
let ctxlineWidth = lineWidth / 2 - r;
// =============canvas=================================
var c2 = document.getElementById('myCanvas2');
var ctx2 = c2.getContext('2d');
// 线
ctx2.beginPath();
ctx2.strokeStyle = '#E5E5E5'; // #E5E5E5
ctx2.moveTo(marginWidth, height + 0.5);
ctx2.lineTo(ctxlineWidth, height + 0.5);
ctx2.stroke();
ctx2.beginPath();
ctx2.moveTo(ctxlineWidth + r * 2, height + 0.5);
ctx2.lineTo(width - marginWidth, height + 0.5);
ctx2.stroke();
// 圆
ctx2.beginPath();
ctx2.arc(lineWidth / 2, height, r + 0.5, 0, 2 * Math.PI);
// ctx2.lineWidth = 1;
ctx2.strokeStyle = circleBorderColor;
ctx2.stroke();
// 转化为图片 - 分割线
var image1 = new Image();
image1.width = width;
image1.src = c2.toDataURL('image/png');
// 绘制箭头
var c1 = document.getElementById('myCanvas1');
var ctx1 = c1.getContext('2d');
ctx1.beginPath();
ctx1.lineWidth = 4;
ctx1.moveTo(0, 0);
ctx1.lineTo(20, 20);
ctx1.lineTo(40, 0);
ctx1.strokeStyle = '#737373';
ctx1.stroke();
// 转化为图片-箭头
var image2 = new Image();
image2.width = 40;
image2.src = c1.toDataURL('image/png');
return [image1.src, image2.src];
};
整体代码
<template>
<div class="encCollapseStyle">
<canvas id="myCanvas2" :width="clientWidth" :height="clientHeight" style="display: none"
>您的浏览器不支持 HTML5 canvas 标签。
</canvas>
<canvas id="myCanvas1" width="40" height="20" style="display: none"
>您的浏览器不支持 HTML5 canvas 标签。
</canvas>
<div v-if="!isOpen">
<div @click="clickOpen(true)" style="text-align: center; height: 0.6rem; font-size: 0.3rem">
<img :src="blueCircle" />
<span class="openCollapse">展开</span>
<img :src="arrow" :width="imgWidth" style="padding-bottom: 0.072rem" />
</div>
</div>
<div v-if="isOpen">
<!-- 插槽-内容 -->
<slot></slot>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue';
// 设备宽度
let clientWidth = ref(window.innerWidth);
let clientHeight = ref(100);
let marginWidth = ref(17);
let radius = 10; // 圆圈半径-适配
let imgWidth = ref(''); // 箭头适配宽度
// 蓝色圆圈+横线
const blueCircle = ref();
// 展开的箭头
const arrow = ref();
// 是否显示内容-展开
let isOpen = ref(false);
/**
* 适配圆形半径
*/
// 1.判断设备类型
const judgIsEquipmentType = () => {
var ua = navigator.userAgent,
isWindowsPhone = /(?:Windows Phone)/.test(ua),
isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
isAndroid = /(?:Android)/.test(ua),
isFireFox = /(?:Firefox)/.test(ua),
isChrome = /(?:Chrome|CriOS)/.test(ua),
isTablet =
/(?:iPad|PlayBook)/.test(ua) ||
(isAndroid && !/(?:Mobile)/.test(ua)) ||
(isFireFox && /(?:Tablet)/.test(ua)),
isPhone = /(?:iPhone)/.test(ua) && !isTablet,
isPc = !isPhone && !isAndroid && !isSymbian;
if (isAndroid || isPhone) {
// 手机
return 'isAndoidOrPhone';
} else if (isTablet) {
// 平板
return 'isTablet';
} else if (isPc || isChrome) {
// 电脑
return 'isPc';
}
};
// 由设备类型确定圆形半径
const judeCircleRadius = () => {
let res = judgIsEquipmentType();
if (res === 'isAndoidOrPhone') {
radius = 2.5;
imgWidth.value = 11;
clientHeight.value = 24;
marginWidth.value = 17;
}
if (res === 'isTablet') {
radius = 5.5;
imgWidth.value = 22;
clientHeight.value = 27;
marginWidth.value = 36;
}
if (res === 'isPc') {
radius = 8.5;
imgWidth.value = 30;
clientHeight.value = 30;
marginWidth.value = 23;
}
};
judeCircleRadius();
/**
* canvas
*/
// 绘制蓝色圆圈○
const convertImageToCanvas = (
r,
lineWidth,
width,
marginWidth,
circleColor,
circleBorderColor = '#0084FF',
height = 20,
) => {
// 处理宽度
let ctxlineWidth = lineWidth / 2 - r;
// =============canvas=================================
var c2 = document.getElementById('myCanvas2');
var ctx2 = c2.getContext('2d');
// 线
ctx2.beginPath();
ctx2.strokeStyle = '#E5E5E5'; // #E5E5E5
ctx2.moveTo(marginWidth, height + 0.5);
ctx2.lineTo(ctxlineWidth, height + 0.5);
ctx2.stroke();
ctx2.beginPath();
ctx2.moveTo(ctxlineWidth + r * 2, height + 0.5);
ctx2.lineTo(width - marginWidth, height + 0.5);
ctx2.stroke();
// 圆
ctx2.beginPath();
ctx2.arc(lineWidth / 2, height, r + 0.5, 0, 2 * Math.PI);
// ctx2.lineWidth = 1;
ctx2.strokeStyle = circleBorderColor;
ctx2.stroke();
// 转化为图片 - 分割线
var image1 = new Image();
image1.width = width;
image1.src = c2.toDataURL('image/png');
// 绘制箭头
var c1 = document.getElementById('myCanvas1');
var ctx1 = c1.getContext('2d');
ctx1.beginPath();
ctx1.lineWidth = 4;
ctx1.moveTo(0, 0);
ctx1.lineTo(20, 20);
ctx1.lineTo(40, 0);
ctx1.strokeStyle = '#737373';
ctx1.stroke();
// 转化为图片-箭头
var image2 = new Image();
image2.width = 40;
image2.src = c1.toDataURL('image/png');
return [image1.src, image2.src];
};
// 点击展开/收回
const clickOpen = () => {
isOpen.value = isOpen;
};
onMounted(() => {
let result = convertImageToCanvas(
radius,
clientWidth.value,
clientWidth.value,
marginWidth.value,
);
blueCircle.value = result[0];
arrow.value = result[1];
});
/**
* README
* 组件描述:仅支持点击展开,初始页面未展开内容;
* 参数:暂无参数
*/
</script>
<style>
.encCollapseStyle {
}
.openCollapse {
padding-right: 0.1rem;
color: #737373;
font-size: 0.4rem;
}
#container {
zoom: 0.5;
}
</style>
使用
<EncCollapse style="background: #ffffff; padding-bottom: 1.1rem">
// 需折叠内容
</EncCollapse>
若有问题,请多多指教。🎃