# 效果图
# 代码
<template>
<div>
<canvas height="500" width="500" ref="canvasDom" id="canvas"></canvas>
<input type="number" ref="inp1" v-model="height">
<input type="number" ref="inp2" v-model="width">
<input type="color" ref="inp3" v-model="color">
<label for="checkbox">🖊<input id="checkbox" type="checkbox" v-model="drawable"></label>
</div>
</template>
<script setup>
import {
ref,
onMounted,
watch
} from 'vue';
const ctx = ref(null)
const canvasDom = ref(null)
const height = ref(200)
const width = ref(200)
const color = ref('#cdcdcd')
const drawable = ref(true)
onMounted(() => {
ctx.value = canvasDom.value.getContext('2d');
ctx.scale(scale, scale);
rePicCanvas(width.value, height.value, color.value)
watch(drawable, (newV) => {
console.log(newV)
if (newV) { makeCanvasCanDraw() }
else { makeCanvasCannotDraw(); }
}, {
immediate: true
})
})
watch([height, width, color], ([preHeight, preWidth, preColor]) => {
ctx.value.clearRect(0, 0, canvasDom.value.clientWidth, canvasDom.value.clientHeight);
rePicCanvas(preWidth, preHeight, preColor)
})
const rePicCanvas = (width, height, color) => {
ctx.value.fillStyle = color;
ctx.value.fillRect(0, 0, parseInt(width), parseInt(height));
}
const makeCanvasCanDraw = () => {
canvasDom.value.addEventListener('mousedown', downFunc);
canvasDom.value.addEventListener('mousemove', moveFunc);
canvasDom.value.addEventListener('mouseup', stopFunc)
canvasDom.value.addEventListener('mouseleave', stopFunc)
}
let isDrawing = false;
let lastX = 0;
let lastY = 0;
const downFunc = (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
}
const moveFunc = (e) => {
if (isDrawing) {
ctx.value.beginPath();
ctx.value.moveTo(lastX, lastY);
ctx.value.lineTo(e.offsetX, e.offsetY);
ctx.value.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
}
const stopFunc = (e) => {
isDrawing = false;
}
const makeCanvasCannotDraw = () => {
const acts = ["mousedown", "mousemove", "mouseup", "mousemouseleavedown"]
const events = [downFunc, moveFunc, stopFunc, stopFunc]
acts.forEach((value, index) => {
canvasDom.value.removeEventListener(value, events[index]);
})
}
</script>
<style scoped>
#canvas {
position: relative;
width: 500px;
height: 500px;
display: block;
}
</style>
# 说明
- 注意 canvas 保留一个默认的高宽为 heigth:150 width:300,这个比例指的是 canvas 画布大小,而不是实际大小,这个属性可以直接在标签上修改,例如:
<canvas height="300" width="300"></canvas>
此时这个默认高宽的画布被设置成了 300 的正方形画布,这 300 个单位只在 js 调用 canvas 函数时产生效果。 2. 切记 当使用一个事件绑定时,最好将绑定事件单独写到外部,否则在给这个事件解绑时匿名函数是无法做到的。 3. 当事件解绑,或对应数据较多时,硬编码的方式可以替换成makeCanvasCannotDraw方法里的写法,让数组对应完成大量操作,比人为填写要更方便优雅。
# BUG
如果发现 bug 或者其他需求可以联系作者 也十分欢迎 pr 前往 github (opens new window)