uni-app实战教程 从0到1开发 画图软件 (学会画图)

一、什么是uniapp呢?

1. uni-app简介

uni-app 是一个基于 Vue.js 的跨平台开发框架,允许开发者使用一套代码同时发布到 iOS、Android、Web、各类小程序及快应用等多个平台。它采用 Vue 语法,支持组件化开发,封装了各平台的原生能力,极大降低了开发与维护成本。使用 UniApp 开发的主要优势包括"一次编写,多端运行",适合快速迭代和覆盖多端的项目需求;基于 Vue.js,学习成本低,便于现有前端开发者上手;拥有完善的开发工具和生态支持,如 HBuilderX、插件市场等;性能接近原生,尤其在主流平台表现优秀;开发效率高,特别适合中小型团队和初创公司快速推出产品。

二、实现基本的画图功能

接下来,我将手把手教会你使用uniapp开发画图软件

1. 实现的效果展示

目前实现了以下的功能:

  • (1)可以进行绘画
  • (2)选择画笔的颜色
  • (3)选择画笔的粗细程度
  • (4)清空画布
  • (5)保存画布

2. 实现功能核心代码讲解

在实现画画功能之前,应该明白画布是如何创建的

创建画布

复制代码
ctx.value = uni.createCanvasContext('drawCanvas')

画布配置

复制代码
ctx.value.setStrokeStyle('#000000') // 默认黑色
ctx.value.setLineWidth(5)          // 默认线宽
ctx.value.setLineCap('round')      // 圆角线头
ctx.value.setLineJoin('round')     // 圆角连接

未处理画布尺寸的,需要动态获取屏幕尺寸并设置画布宽高

复制代码
const systemInfo = uni.getSystemInfoSync()
canvasWidth.value = systemInfo.windowWidth
canvasHeight.value = systemInfo.windowHeight * 0.8

画布区域

复制代码
    <canvas 
      canvas-id="drawCanvas"
      class="draw-canvas"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      disable-scroll="true"
      :style="{width: canvasWidth + 'px', height: canvasHeight + 'px'}"
    ></canvas>

2.2.1 画画的功能实现

画画无法就是触摸,触摸移动,触摸后三个状态

画布区域的三个方法就是对应着这三个状态的触发。

复制代码
@touchstart="handleTouchStart"

@touchmove="handleTouchMove"

@touchend="handleTouchEnd"
2.2.1.1 触摸开始

如何实现绘画呢?一条黑色的线,就是无数条黑色的点连接而成的,所以我们使用将存储点来组合成我们所画的线,我们将点使用points数组进行存储绘画路过的无数的点,当我们触摸开始的时候就记录当前的点位置,所以points.value = [point],后续我们移动时就会添加其他的点进入该数组中。

复制代码
// 触摸开始
const handleTouchStart = async (e) => {
  if (!ensureContext()) return
  
  isDrawing.value = true
  const point = {
    x: e.touches[0].x,
    y: e.touches[0].y
  }
  points.value = [point] // 重置点数组
  
  
  ctx.value.beginPath() // 开始新的绘制路径
  ctx.value.moveTo(point.x, point.y)  // 移动画笔到起点
  ctx.value.stroke()  // 执行描边(绘制第一个点)
  ctx.value.draw(true)  // 立即渲染到画布
}
2.2.1.2 触摸移动
复制代码
// 触摸移动
const handleTouchMove = async (e) => {
  if (!isDrawing.value || !ensureContext()) return
  
  const point = {
    x: e.touches[0].x,
    y: e.touches[0].y
  }
  points.value.push(point)
  
  if (points.value.length >= 2) {
    const lastPoint = points.value[points.value.length - 2]
    const currentPoint = points.value[points.value.length - 1]
    
    ctx.value.moveTo(lastPoint.x, lastPoint.y)  // 移动到上一个点
    ctx.value.lineTo(currentPoint.x, currentPoint.y)  // 画线到当前点
    ctx.value.stroke()  // 执行描边
    ctx.value.draw(true)  // 立即渲染
  }
}

至少需要2个点才能形成线段(所以判断points.value.length >= 2)

2.2.1.3 触摸结束

将绘画的状态设置为false,表示不在继续绘画了,同时将points用于存储绘画的点设置为空,方便下次绘画时使用。

复制代码
// 触摸结束
const handleTouchEnd = () => {
  isDrawing.value = false
  points.value = []
}

2.2.2 选择画笔的颜色

复制代码
ctx.value.setStrokeStyle('#000000') // 默认黑色

2.2.3 选择画笔的粗细程度

复制代码
ctx.value.setLineWidth(5)          // 默认线宽

2.2.4 清空画布

复制代码
    ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value)
    ctx.value.draw(true)

clearRect(x, y, width, height) 清除指定矩形区域内的像素,其中:

  • (0, 0):从画布左上角开始
  • (canvasWidth, canvasHeight):覆盖整个画布

2.2.5 保存画布

使用了uni.canvasToTempFilePath和uni.saveImageToPhotosAlbum

uni.canvasToTempFilePath- 生成临时文件​(将 Canvas 内容导出为临时图片文件)

uni.saveImageToPhotosAlbum- 保存到相册​(将临时文件保存至系统相册。)

复制代码
  uni.canvasToTempFilePath({
    canvasId: 'drawCanvas',
    success: (res) => {
      uni.saveImageToPhotosAlbum({
        filePath: res.tempFilePath,
        success: () => {
          uni.showToast({
            title: '保存成功',
            icon: 'success'
          })
        },
        fail: () => {
          uni.showToast({
            title: '保存失败,请检查权限',
            icon: 'none'
          })
        }
      })
    },
    fail: (err) => {
      console.error('保存失败:', err)
      uni.showToast({
        title: '生成图片失败',
        icon: 'none'
      })
    }
  })
相关推荐
Ai行者心易13 小时前
10天!前端用coze,后端用Trae IDE+Claude Code从0开始构建到平台上线
前端·后端
东东23314 小时前
前端开发中如何取消Promise操作
前端·javascript·promise
掘金安东尼14 小时前
官方:什么是 Vite+?
前端·javascript·vue.js
柒崽14 小时前
ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案
前端
渣哥14 小时前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
烛阴14 小时前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长14 小时前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit14 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_14 小时前
[css] border 渐变
前端·css
云中雾丽14 小时前
flutter的dart语言和JavaScript的消息循环机制的异同
前端