使用uni-app和Canvas生成简易双列表格布局并长按下载到本地
在现代Web和移动应用开发中,Canvas技术为我们提供了强大的图形绘制能力。本文将介绍如何使用uni-app框架结合Canvas技术,创建一个美观的健康风险评估报告页面,并实现长按保存功能。
实现思路
1. Canvas基础设置
首先,我们需要设置Canvas画布并获取其实际尺寸:
2. 获取Canvas尺寸
使用uni-app的API(createSelectorQuery)获取Canvas的实际尺寸:
3. 绘制双列表格
核心的绘制函数drawCanvas实现了双列表格布局,左侧key右侧对应value
完整代码如下
<template><view class="canvaspage"><canvasstyle="width: 100%; height: 100vh"class="canvas"ref="canvasbox"canvas-id="canvasbox"@longpress="downloadPic(state.createImgPath)"></canvas></view>
</template><script setup lang="ts">
import { getCanvasSize } from "@/utils/canvas";
import { ref, onMounted, getCurrentInstance, nextTick, reactive } from "vue";
import { downloadPic } from "@/utils/common";const canvasbox = ref<HTMLCanvasElement | null | any>(null);
const instance = getCurrentInstance();
const state = reactive({createImgPath: "",
});onMounted(() => {console.log("onMounted", instance);nextTick(() => {drawCanvas();});
});async function drawCanvas() {const context = uni.createCanvasContext("canvasbox");const res = await getCanvasSize(".canvas", instance?.proxy);context.setFillStyle("white"); //全局背景const width = res.width;const startY = 50; // 脑卒中标准 Y轴起始位置 30为上下间距setCutLine(context, { x: 12, y: 30 }, width); // 分割线// 重新计算布局const leftMargin = 12; // 左边距const rightMargin = 12; // 右边距const tableWidth = width - leftMargin - rightMargin; // 表格总宽度const columnWidth = tableWidth / 2; // 每列宽度(平均分配)// 左列和右列的起始位置const leftColumnStart = leftMargin;const rightColumnStart = leftMargin + columnWidth;// 更精确的文本宽度估算函数const estimateTextWidth = (text: string) => {let width = 0;for (let i = 0; i < text.length; i++) {const char = text[i];if (/[\u0000-\u00FF]/.test(char)) {// 英文字符或数字width += 7;} else {// 中文字符width += 14;}}return width;};standardList().forEach((item: any, index: any) => {const y = index ? index * 30 + startY : startY;// 估算文本宽度const keyWidth = estimateTextWidth(item.key);const valueWidth = estimateTextWidth(item.value);// 计算左侧文本X坐标,使其在左列居中const tNumX = leftColumnStart + (columnWidth - keyWidth) / 2;// 计算右侧文本X坐标,使其在右列居中const vNumX = rightColumnStart + (columnWidth - valueWidth) / 2;context.setFillStyle("#333333");context.setFontSize(14); // 设置字体大小// 调整Y坐标,使文本垂直居中const textY = y - 2; // 向上偏移一点,使文本在行中垂直居中context.fillText(item.key, tNumX, textY);context.fillText(item.value, vNumX, textY);// 分割线setCutLine(context, { x: 12, y: y + 8 }, width);});// 画竖线context.lineWidth = 1;context.strokeStyle = "#E5E5E5";context.beginPath();const lineY = 30;const endY = standardList().length * 30 - 2 + lineY;// 竖线context.moveTo(leftColumnStart, lineY); // 左context.lineTo(leftColumnStart, endY);context.moveTo(rightColumnStart, lineY); // 中context.lineTo(rightColumnStart, endY);context.moveTo(width - rightMargin, lineY); // 右context.lineTo(width - rightMargin, endY);context.stroke();context.setFontSize(42);context.setFillStyle("red");context.setTextAlign("center");context.setTextBaseline("middle");context.fillText("长按点击下载", width / 2, res.height - 300);context.draw(false, () => {uni.canvasToTempFilePath({canvasId: "canvasbox",success: (result: any) => {state.createImgPath = result.tempFilePath;},});});
}// 分割线
const setCutLine = (ctx: any, xy: any, width?: any) => {const startX = 12;ctx.lineWidth = 1;ctx.beginPath();ctx.moveTo(xy.x, xy.y + 0.5); // + 0.5 线像素为1pxctx.lineTo(width ? width - startX : startX, xy.y + 0.5);ctx.closePath();ctx.strokeStyle = "#E5E5E5";ctx.stroke();
};// 标准列表
const standardList = () => {return [{key: "高血压",value: "≥140/90mmHg",},{key: "血脂情况",value: "血脂异常或不知道",},{key: "糖尿病",value: "有",},{key: "心房颤动",value: "心跳不规则",},{key: "吸烟",value: "有",},{key: "体重",value: "明显超重或肥胖",},{key: "运动",value: "缺乏运动",},{key: "是否抽烟",value: "是的",},{key: "是否喝酒",value: "是的",},{key: "是否患有精神洁癖",value: "不曾",},];
};
</script><style scoped lang="scss">
.canvaspage {width: 100%;min-height: 100vh;box-sizing: border-box;padding: 32rpx;
}
</style>
应用场景
这种技术可以广泛应用于:
健康评估报告生成
电子病历可视化
体检结果展示
医疗数据报告
引入方法补充
getCanvasSize方法
//获取canvas画布的实际尺寸
export const getCanvasSize = (classname: any, nodeInfo: any): Promise<any> => {return new Promise((resolve, reject) => {const query = uni.createSelectorQuery().in(nodeInfo);query.select(classname).fields({ size: true }, (res: any) => {if (res) {resolve(res);} else {reject("获取画布尺寸失败");}}).exec();});
};
downpic方法--参考本篇文章:
uni微信小程序实现保存图片到本地_uniapp保存图片到相册-CSDN博客
希望本文对你在uni-app中使用Canvas有所帮助!