Canvas实现基本画图
JS操作DOM很慢,改用canvas
canvas是用 width 和 height 属性设置宽高的,用CSS设置会拉伸模糊
为了适配手机,需判断是否是触屏
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>画板</title><link rel="stylesheet" href="style.css" /></head><body><canvas id="canvas"></canvas><script>const canvas = document.getElementById("canvas");// 获取文档宽度和高度,设置canvas的html属性canvas.width = document.documentElement.clientWidth;canvas.height = document.documentElement.clientHeight;const ctx = canvas.getContext("2d");let lineWidth = 6ctx.lineWidth = lineWidth; // 设置画线宽度ctx.lineCap = "round"; // 防止转折处断开let painting = false;let last = [0, 0];// 画线函数function drawLine(lastX, lastY, newX, newY) {ctx.beginPath();ctx.moveTo(lastX, lastY);ctx.lineTo(newX, newY);ctx.stroke();}// 画圆function drawCircle(x, y, radius) {ctx.beginPath()ctx.arc(x, y, radius, 0, 2 * Math.PI, true)ctx.fill()}// 检测是否支持触屏const isTouchDevice = "ontouchstart" in document.documentElement;if (isTouchDevice) {canvas.ontouchstart = (e) => {const x = e.touches[0].clientX;const y = e.touches[0].clientY;last = [x, y];drawCircle(x, y, lineWidth / 2)};canvas.ontouchmove = (e) => {const x = e.touches[0].clientX;const y = e.touches[0].clientY;drawLine(last[0], last[1], x, y);last = [x, y];};} else {canvas.onmousedown = (e) => {painting = true;last = [e.clientX, e.clientY];drawCircle(e.clientX, e.clientY, lineWidth / 2)};canvas.onmousemove = (e) => {if (painting === true) {drawLine(last[0], last[1], e.clientX, e.clientY);last = [e.clientX, e.clientY];}};canvas.onmouseup = () => {painting = false;};}</script></body></html>
添加橡皮擦
使用 clearRect API 实现橡皮擦功能
let eraserEnabled = falsecanvas.onmousedown = (e) => {painting = truelast = [e.clientX, e.clientY]if (eraserEnabled) {ctx.clearRect(e.clientX - 10, e.clientY - 10, 20, 20)} else {drawCircle(e.clientX, e.clientY, lineWidth / 2)}}canvas.onmousemove = (e) => {if (painting === true) {if (eraserEnabled) {ctx.clearRect(e.clientX - 10, e.clientY - 10, 20, 20)} else {drawLine(last[0], last[1], e.clientX, e.clientY)last = [e.clientX, e.clientY]}}}
添加颜色选择功能

<ul class="colorPicker"><li class="black active"></li><li class="blue"></li><li class="red"></li><li class="green"></li><li class="yellow"></li></ul>
利用事件委托,将事件监听放在父元素上
const colors = {black: '#000',red: '#ff1a40',blue: '#1a8cff',green: '#2bd965',yellow: '#ffdd33',}const colorPicker = document.querySelector('.colorPicker')colorPicker.addEventListener('click', (e) => {if (e.target !== e.currentTarget) {const oldPicked = document.querySelector('.colorPicker > li.active')if (oldPicked) oldPicked.classList.remove('active')e.target.classList.add('active')const classname = e.target.className.replace('active', '').trim()const pickedColor = colors[classname]ctx.strokeStyle = pickedColorctx.fillStyle = pickedColor}})
清空画板
clearBtn.onclick = () => {ctx.clearRect(0, 0, canvas.width, canvas.height)}
保存成图片
canvas默认背景是透明的,先写个初始化背景函数, 在程序开始以及清空画布时调用
let pickedColor = '#000'const initBG = () => {ctx.fillStyle = '#fff'ctx.fillRect(0, 0, canvas.width, canvas.height)ctx.fillStyle = pickedColor}
保存成图片的方法
save.onclick = () => {const url = canvas.toDataURL('image/jpeg')const a = document.createElement('a')document.body.append(a)a.href = urla.download = 'my-drawing'a.target = '_blank'a.click()}
修改画笔粗细

通过 ctx.lineWidth 属性修改画笔粗细
通过 e.target.nodeName 判断点击的是什么元素
该功能更多的是CSS样式的编写,但也没什么难度,就不贴上代码了
const thicknessHash = {1: 4,2: 7,3: 10,4: 13,5: 16,}const thicknessCircle = document.querySelector('.thickness > .circle-wrapper > .circle')const thicknessNumber = document.querySelector('.thickness > .number')const thicknessPicker = document.querySelector('.thickness-picker > ul')thicknessPicker.onclick = (e) => {if (e.target.nodeName === 'LI') {const oldPicked = document.querySelector('.thickness-picker > ul > li.active')oldPicked.classList.remove('active')e.target.classList.add('active')const num = e.target.innerTextctx.lineWidth = thicknessHash[num]thicknessCircle.style.width = thicknessHash[num] + 'px'thicknessCircle.style.height = thicknessHash[num] + 'px'thicknessNumber.innerText = num}}
总结
整个 Canvas画板 都用原生JS编写,实现了画笔颜色选取,画笔粗细切换,橡皮擦,一键清空画布以及保存图片等功能,项目中用的关键技术有:Canvas API, DOM原生API,事件委托,flex布局,iconfont svg图标,项目使用了 parcel 编译和打包。
预览链接
源代码

