# Canvas 画布 
Canvas 画布组件,支持2D和WebGL渲染,提供统一的跨平台画布API。
# 平台差异说明
App(vue) | App(nvue) | H5 | 小程序 |
---|---|---|---|
√ | X | √ | √ |
# 基本使用
<template> <view> <u-canvas :width="300" :height="200" ref="canvas"></u-canvas> <u-button @click="drawBasicShapes">绘制基本图形</u-button> </view> </template> <script> export default { methods: { async drawBasicShapes() { const canvasContext = await this.$refs.canvas.getCanvasContext(); const { canvas } = canvasContext; // 绘制矩形 canvas.fillStyle = '#ff6b6b'; canvas.fillRect(20, 20, 80, 60); // 绘制描边矩形 canvas.strokeStyle = '#4ecdc4'; canvas.lineWidth = 3; canvas.strokeRect(120, 20, 80, 60); // 绘制圆形 canvas.fillStyle = '#45b7d1'; canvas.beginPath(); canvas.arc(60, 120, 30, 0, 2 * Math.PI); canvas.fill(); // 绘制线条 canvas.strokeStyle = '#f9ca24'; canvas.lineWidth = 4; canvas.beginPath(); canvas.moveTo(120, 120); canvas.lineTo(200, 120); canvas.lineTo(160, 160); canvas.closePath(); canvas.stroke(); canvas.draw(); } } }; </script>
✅ Copy success!
# 绘制图形
<template> <view> <u-canvas :width="300" :height="200" ref="basicCanvas" ></u-canvas> <u-button @click="drawBasicShapes">绘制基本图形</u-button> <u-button @click="clearCanvas">清空画布</u-button> </view> </template> <script> export default { methods: { async drawBasicShapes() { const canvasContext = await this.$refs.basicCanvas.getCanvasContext(); const { canvas } = canvasContext; // 绘制矩形 canvas.fillStyle = '#ff6b6b'; canvas.fillRect(20, 20, 80, 60); // 绘制描边矩形 canvas.strokeStyle = '#4ecdc4'; canvas.lineWidth = 3; canvas.strokeRect(120, 20, 80, 60); // 绘制圆形 canvas.fillStyle = '#45b7d1'; canvas.beginPath(); canvas.arc(60, 120, 30, 0, 2 * Math.PI); canvas.fill(); // 绘制线条 canvas.strokeStyle = '#f9ca24'; canvas.lineWidth = 4; canvas.beginPath(); canvas.moveTo(120, 120); canvas.lineTo(200, 120); canvas.lineTo(160, 160); canvas.closePath(); canvas.stroke(); canvas.draw(); }, async clearCanvas() { const canvasContext = await this.$refs.basicCanvas.getCanvasContext(); const { canvas, width, height } = canvasContext; canvas.clearRect(0, 0, width, height); canvas.draw(); } } }; </script>
✅ Copy success!
# 绘制文字
<template> <view> <u-canvas :width="300" :height="200" ref="textCanvas" ></u-canvas> <u-button @click="drawText">绘制文字</u-button> <u-button @click="clearTextCanvas">清空画布</u-button> </view> </template> <script> export default { methods: { async drawText() { const canvasContext = await this.$refs.textCanvas.getCanvasContext(); const { canvas } = canvasContext; // 设置字体样式 canvas.font = '20px Arial'; canvas.fillStyle = '#333'; canvas.textAlign = 'center'; canvas.textBaseline = 'middle'; // 绘制填充文字 canvas.fillText('Hello uView Canvas', 150, 50); // 绘制描边文字 canvas.strokeStyle = '#ff6b6b'; canvas.lineWidth = 2; canvas.strokeText('Stroke Text', 150, 100); // 设置阴影 canvas.shadowColor = 'rgba(0,0,0,0.3)'; canvas.shadowBlur = 8; canvas.shadowOffsetX = 2; canvas.shadowOffsetY = 2; canvas.fillStyle = '#4ecdc4'; canvas.fillText('Shadow Text', 150, 150); canvas.draw(); }, async clearTextCanvas() { const canvasContext = await this.$refs.textCanvas.getCanvasContext(); const { canvas, width, height } = canvasContext; canvas.clearRect(0, 0, width, height); canvas.draw(); } } }; </script>
✅ Copy success!
# 图表绘制
# 柱状图
<template> <view> <u-canvas :width="300" :height="200" ref="chartCanvas" ></u-canvas> <u-button @click="drawChart">绘制柱状图</u-button> </view> </template> <script> export default { methods: { async drawChart() { const canvasContext = await this.$refs.chartCanvas.getCanvasContext(); const { canvas, width, height } = canvasContext; const data = [60, 80, 45, 90, 70]; const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7']; const barWidth = 30; const barSpacing = 20; const startX = 30; const maxHeight = 120; // 清空画布 canvas.clearRect(0, 0, width, height); // 绘制柱状图 data.forEach((value, index) => { const barHeight = (value / 100) * maxHeight; const x = startX + index * (barWidth + barSpacing); const y = height - 30 - barHeight; canvas.fillStyle = colors[index]; canvas.fillRect(x, y, barWidth, barHeight); // 绘制数值标签 canvas.fillStyle = '#333'; canvas.font = '12px Arial'; canvas.textAlign = 'center'; canvas.fillText(value.toString(), x + barWidth / 2, y - 5); }); canvas.draw(); } } }; </script>
✅ Copy success!
# 饼图
<template> <view> <u-canvas :width="300" :height="200" ref="pieCanvas" ></u-canvas> <u-button @click="drawPieChart">绘制饼图</u-button> </view> </template> <script> export default { methods: { async drawPieChart() { const canvasContext = await this.$refs.pieCanvas.getCanvasContext(); const { canvas, width, height } = canvasContext; const data = [30, 25, 20, 15, 10]; const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7']; const centerX = width / 2; const centerY = height / 2; const radius = 60; // 清空画布 canvas.clearRect(0, 0, width, height); let currentAngle = -Math.PI / 2; // 从顶部开始 data.forEach((value, index) => { const sliceAngle = (value / 100) * 2 * Math.PI; // 绘制扇形 canvas.fillStyle = colors[index]; canvas.beginPath(); canvas.moveTo(centerX, centerY); canvas.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle); canvas.closePath(); canvas.fill(); // 绘制标签 const labelAngle = currentAngle + sliceAngle / 2; const labelX = centerX + Math.cos(labelAngle) * (radius + 20); const labelY = centerY + Math.sin(labelAngle) * (radius + 20); canvas.fillStyle = '#333'; canvas.font = '12px Arial'; canvas.textAlign = 'center'; canvas.fillText(`${value}%`, labelX, labelY); currentAngle += sliceAngle; }); canvas.draw(); } } }; </script>
✅ Copy success!
# 图片处理
# 绘制图片
<template> <view> <u-canvas :width="300" :height="200" ref="imageCanvas" ></u-canvas> <u-button @click="drawImage">绘制图片</u-button> </view> </template> <script> export default { methods: { async drawImage() { const canvasContext = await this.$refs.imageCanvas.getCanvasContext(); const { canvas, width, height } = canvasContext; // 清空画布 canvas.clearRect(0, 0, width, height); // 绘制真实图片 const imageUrl = 'https://uview.d3u.cn/web/static/uview/common/50c02fb7gy1i0vn1f8mbuj20qo13eal2.jpg'; canvas.drawImage(imageUrl, 27, 0, 246, 364); canvas.draw(); } } }; </script>
✅ Copy success!
# 导出图片
<template> <view> <u-canvas :width="300" :height="200" ref="exportCanvas" ></u-canvas> <u-button @click="exportImage">导出图片</u-button> </view> </template> <script> export default { methods: { async exportImage() { try { const tempFilePath = await this.$refs.exportCanvas.canvasToTempFilePath({ x: 0, y: 0, width: 300, height: 200, destWidth: 300, destHeight: 200, fileType: 'png', quality: 1 }); console.log('图片已保存到:', tempFilePath); uni.showToast({ title: '图片导出成功', icon: 'success' }); } catch (error) { console.error('导出失败:', error); uni.showToast({ title: '导出失败', icon: 'error' }); } } } }; </script>
✅ Copy success!
# 页面源码地址
# API
# Props
参数 | 说明 | 类型 | 默认值 | 可选值 |
---|---|---|---|---|
width | 画布宽度 | String | Number | 375 | - |
height | 画布高度 | String | Number | - | - |
type | 画布类型 | String | 2d(微信小程序/抖音小程序) webgl(其他平台) | 2d | webgl |
disableScroll | 是否禁用滚动 | Boolean | false | true |
hidpi | 是否启用高清 | Boolean | true | false |
# Events
事件名 | 说明 | 回调参数 |
---|---|---|
onTouchstart | 触摸开始 | event |
onTouchmove | 触摸移动 | event |
onTouchend | 触摸结束 | event |
onTouchcancel | 触摸取消 | event |
onLongtap | 长按 | event |
onError | 错误事件 | event |
# Methods
方法名 | 说明 | 参数 | 返回值 |
---|---|---|---|
getCanvasContext | 获取画布上下文 | - | Promise<{canvas, width, height, canvasId, use2D}> |
queryCanvas | 查询画布节点信息 | - | Promise<{node, size}> |
canvasToTempFilePath | 导出画布为临时文件 | options | Promise<string> |
# canvasToTempFilePath 参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
x | 画布x轴起点 | Number | 0 |
y | 画布y轴起点 | Number | 0 |
width | 画布宽度 | Number | canvas宽度 |
height | 画布高度 | Number | canvas高度 |
destWidth | 输出图片宽度 | Number | width |
destHeight | 输出图片高度 | Number | height |
fileType | 图片格式 | String | png |
quality | 图片质量 | Number | 1 |
← Tree 树形组件 Paging 分页组件 →