当前位置:首页 > VUE

用vue实现手绘功能

2026-02-21 17:41:22VUE

使用 Vue 实现手绘功能

核心思路

基于 HTML5 的 Canvas API 结合 Vue 的响应式特性,通过监听鼠标或触摸事件实现手绘功能。需要处理画笔移动轨迹、颜色、粗细等属性,并提供清除画布功能。

基础实现代码

以下是一个完整的 Vue 3 组件示例(Composition API):

用vue实现手绘功能

<template>
  <div class="drawing-board">
    <canvas 
      ref="canvasRef"
      @mousedown="startDrawing"
      @mousemove="draw"
      @mouseup="stopDrawing"
      @mouseleave="stopDrawing"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    ></canvas>
    <div class="controls">
      <input type="color" v-model="drawColor">
      <input type="range" v-model="lineWidth" min="1" max="50">
      <button @click="clearCanvas">清除</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const canvasRef = ref(null)
const isDrawing = ref(false)
const drawColor = ref('#000000')
const lineWidth = ref(5)

let ctx = null

onMounted(() => {
  const canvas = canvasRef.value
  ctx = canvas.getContext('2d')
  resizeCanvas()
  window.addEventListener('resize', resizeCanvas)
})

function resizeCanvas() {
  const canvas = canvasRef.value
  canvas.width = canvas.offsetWidth
  canvas.height = canvas.offsetHeight
  ctx.lineJoin = 'round'
  ctx.lineCap = 'round'
}

function startDrawing(e) {
  isDrawing.value = true
  draw(e)
}

function draw(e) {
  if (!isDrawing.value) return

  const rect = canvasRef.value.getBoundingClientRect()
  const x = e.clientX - rect.left
  const y = e.clientY - rect.top

  ctx.strokeStyle = drawColor.value
  ctx.lineWidth = lineWidth.value

  ctx.lineTo(x, y)
  ctx.stroke()
  ctx.beginPath()
  ctx.moveTo(x, y)
}

function stopDrawing() {
  isDrawing.value = false
  ctx.beginPath()
}

function handleTouchStart(e) {
  e.preventDefault()
  const touch = e.touches[0]
  const mouseEvent = new MouseEvent('mousedown', {
    clientX: touch.clientX,
    clientY: touch.clientY
  })
  canvasRef.value.dispatchEvent(mouseEvent)
}

function handleTouchMove(e) {
  e.preventDefault()
  const touch = e.touches[0]
  const mouseEvent = new MouseEvent('mousemove', {
    clientX: touch.clientX,
    clientY: touch.clientY
  })
  canvasRef.value.dispatchEvent(mouseEvent)
}

function handleTouchEnd() {
  const mouseEvent = new MouseEvent('mouseup')
  canvasRef.value.dispatchEvent(mouseEvent)
}

function clearCanvas() {
  ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
}
</script>

<style scoped>
.drawing-board {
  width: 100%;
  height: 500px;
  position: relative;
}

canvas {
  border: 1px solid #ccc;
  background-color: white;
  width: 100%;
  height: 100%;
  touch-action: none;
}

.controls {
  margin-top: 10px;
  display: flex;
  gap: 10px;
  align-items: center;
}
</style>

功能扩展建议

保存绘图结果

用vue实现手绘功能

function saveAsImage() {
  const dataURL = canvasRef.value.toDataURL('image/png')
  const link = document.createElement('a')
  link.download = 'drawing.png'
  link.href = dataURL
  link.click()
}

撤销/重做功能

const history = ref([])
const historyIndex = ref(-1)

function saveState() {
  historyIndex.value++
  history.value = history.value.slice(0, historyIndex.value)
  history.value.push(canvasRef.value.toDataURL())
}

function undo() {
  if (historyIndex.value <= 0) return
  historyIndex.value--
  const img = new Image()
  img.onload = () => ctx.drawImage(img, 0, 0)
  img.src = history.value[historyIndex.value]
}

function redo() {
  if (historyIndex.value >= history.value.length - 1) return
  historyIndex.value++
  const img = new Image()
  img.onload = () => ctx.drawImage(img, 0, 0)
  img.src = history.value[historyIndex.value]
}

画笔类型扩展

const brushType = ref('pen')

function setBrush(type) {
  brushType.value = type
  switch(type) {
    case 'marker':
      ctx.globalCompositeOperation = 'multiply'
      break
    case 'eraser':
      ctx.globalCompositeOperation = 'destination-out'
      break
    default:
      ctx.globalCompositeOperation = 'source-over'
  }
}

性能优化技巧

  • 使用 requestAnimationFrame 优化绘制性能
  • 对于复杂绘图,考虑使用离屏 Canvas 进行缓冲
  • 实现节流处理高频绘制事件
  • 移动端适配时注意 passive event listeners

注意事项

  1. Canvas 尺寸必须通过属性设置(非 CSS),否则会出现拉伸变形
  2. 触摸事件需要正确处理 preventDefault 以避免页面滚动
  3. 高 DPI 设备需要处理像素比问题:
    function resizeCanvas() {
    const canvas = canvasRef.value
    const ratio = window.devicePixelRatio || 1
    canvas.width = canvas.offsetWidth * ratio
    canvas.height = canvas.offsetHeight * ratio
    ctx.scale(ratio, ratio)
    ctx.lineJoin = 'round'
    ctx.lineCap = 'round'
    }

标签: 手绘功能
分享给朋友:

相关文章

h5能实现的功能

h5能实现的功能

H5能实现的功能 H5(HTML5)是一种现代的网页技术标准,具备丰富的功能和特性,适用于多种场景。以下是H5能够实现的主要功能: 多媒体支持 H5原生支持音频和视频播放,无需依赖Flash等插件。…

vue功能实现

vue功能实现

Vue 功能实现指南 Vue.js 是一个流行的前端框架,用于构建用户界面和单页应用。以下是 Vue 功能实现的关键方法和技术。 数据绑定与响应式 Vue 的核心特性是数据绑定和响应式系统。通过…

uniapp实现支付功能

uniapp实现支付功能

支付功能实现概述 在UniApp中实现支付功能通常需要对接第三方支付平台(如微信支付、支付宝支付等)。以下是基于微信支付和支付宝支付的通用实现流程。 微信支付实现步骤 1. 配置支付权限 在微信开放…

vue电影功能实现

vue电影功能实现

Vue 电影功能实现 数据获取与展示 使用 Axios 或 Fetch API 从电影 API(如 TMDb、豆瓣 API)获取数据。在 Vue 的 created 或 mounted 生命周期钩子中…

php怎么实现登录功能

php怎么实现登录功能

数据库准备 创建用户表存储登录信息,通常包括用户名、密码(需加密)等字段。示例SQL: CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY…

vue实现论坛功能

vue实现论坛功能

实现论坛功能的核心模块 论坛功能通常包含用户发帖、回帖、分类浏览、搜索等核心模块。Vue.js 作为前端框架,需配合后端 API 实现数据交互。 基础项目结构搭建 使用 Vue CLI 或 Vite…