预览链接

1.用 div 当画点

1.1.监听鼠标位置(打 log 监听)

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>画板</title>
  7. <link rel="stylesheet" href="style.css" /> <!-- 引入一个CSS样式文档 -->
  8. </head>
  9. <body>
  10. <div id="canvas"></div> <!-- id 可以直接用来做全局变量 -->
  11. <script>
  12. canvas.onclick = (e) => {
  13. //监听 canvas 的事件,这里先用 onclick 事件,出问题再改
  14. console.log(e);
  15. //console 调试
  16. };
  17. </script>
  18. </body>
  19. </html>
  1. * {
  2. margin: 0;
  3. padding: 0;
  4. box-sizing: border-box;
  5. }
  6. #canvas {
  7. height: 100vh;
  8. border: 1px solid red;
  9. }
  • 开启终端,输入 http-server . -c-1 进入其中一个网址,刷新不出来就在链接后面加上路径,如:/index.html
  • 打开浏览器的开发者模式,
  • 在画板的左上角点击一下(这里的XY应该都是0),进入下图位置

image.png

  • 点开 MouseEvent

image.png

  • 会发现里面有好几个显示 X Y 的,都是显示现在点击的那个点,选择其中一个来用,出现问题了再换
  • 确认可以读出鼠标点击的点的位置后,打出X和Y

    1. console.log(e.clientX);
    2. console.log(e.clientY);

    1.2.让鼠标点击出现一个实心圆点(给div加样式)

    1. let div = document.createElement("div");
    2. //让文档创建一个元素div,默认在内存里,不在 canvas 里
    3. div.style.position = "absolute";
    4. //让 div 里的内联元素样式为 absolute
    5. div.style.left = e.clientX + "px";
    6. div.style.top = e.clientY + "px";
    7. //注意加单位
    8. div.style.border = "1px solid red";
    9. div.style.width = "6px";
    10. div.style.height = "6px";
    11. canvas.appendChild(div);
    12. //让div在canvas里,而不是在内存里,不加这个的话点击不会显示任何东西
  • 此时鼠标每次点击会出现一个 6px 的矩形框

image.png

  • 并且鼠标的箭头指的位置是矩形框的左上角,我们需要它是在中间,并且为实心圆形

    1. div.style.marginLeft = "-3px";
    2. div.style.marginTop = "-3px"; //鼠标的箭头指的位置是矩形框的中间
    3. div.style.borderRadius = "50%";//变圆
    4. div.style.backgroundColor = "black";//实心,此时可去掉 border
  • 效果图,实心圆点

image.png

1.3.连续的点

  • 将 onclick 换成 onmousemove ,鼠标移动就会画点(弊病:不会停止,只要鼠标在图框里移动就会画点)
  • 最终的 script 里的内容

    1. <script>
    2. canvas.onmousemove = (e) => {
    3. //监听 canvas 的事件,这里先用 onclick 事件,出问题再改,后面改成了 onmousemove
    4. console.log(e.clientX);
    5. console.log(e.clientY);
    6. // console.log 调试大法
    7. let div = document.createElement("div");
    8. //让文档创建一个元素div,默认在内存里,不在 canvas 里
    9. div.style.position = "absolute";
    10. //让 div 里的内联元素样式为 absolute
    11. div.style.left = e.clientX + "px";
    12. div.style.top = e.clientY + "px";
    13. //注意加单位
    14. div.style.width = "6px";
    15. div.style.height = "6px"; //使点击出来的为一个6px的矩形框
    16. div.style.marginLeft = "-3px";
    17. div.style.marginTop = "-3px"; //鼠标的箭头指的位置是矩形框的中间
    18. div.style.borderRadius = "50%"; //变圆
    19. div.style.backgroundColor = "black"; //实心,此时可去掉 border
    20. canvas.appendChild(div);
    21. //让div在canvas里,而不是在内存里
    22. };
    23. </script>

    效果图
    image.png
    弊端:

  • 鼠标移动太快会间断

  • 会一直产生新的 DOM 点,画的越多越卡

image.png

2.用 canvas 属性

canvas教程

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>画板</title>
  7. <link rel="stylesheet" href="style.css" />
  8. <!-- 引入一个CSS样式文档 -->
  9. </head>
  10. <body>
  11. <canvas id="canvas" width="100" height="100"></canvas>
  12. <script>
  13. </script>
  14. </body>
  15. </html>

2.1.样式暂定

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. box-sizing: border-box;
  5. }
  6. #canvas {
  7. height: 100vh;
  8. width: 100vw;
  9. border: 1px solid red;
  10. display: block;
  11. }
  12. /* 暂定这样,后面会有问题;目的,既没有左右,又没有上下的滚动条 */

2.2.搜索 canvas mdn (复制过来以下内容到 script)

  1. const canvas = document.getElementById("canvas");
  2. const ctx = canvas.getContext("2d");
  3. ctx.fillStyle = "blue";//填充样式
  4. ctx.fillRect(20, 20, 60, 60);//间距左,右,宽,高

image.png

  • 此时会看到一个比较模糊的背景色(原因是前面的样式出了问题)

canvas 有一个原始的宽高,强行咋 CSS 里改样式会让其直接拉伸,而不会自适应,所有会有模糊状态

  • [x] 去掉 CSS 里的宽高

    1. #canvas {
    2. border: 1px solid red;
    3. display: block;
    4. }

    显示如下:比较清楚的背景色
    image.png

    2.3.如何让画板自适应到整个屏幕

    加入下面代码到 script

    1. canvas.width = document.documentElement.clientWidth;
    2. canvas.height = document.documentElement.clientHeight;
    3. //把canvas的宽高变成文档的宽高(注意不要变成body的宽高,宽度合适,但是高度只有body的高)
    4. 删除 canvas border

    得到一个无边框,无滚动条的画板
    image.png

    2.4.打 log,监听鼠标位置

    1. canvas.onmousemove = (e) => {
    2. console.log(e.clientX);
    3. console.log(e.clientY);
    4. ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10); //间距左,右,宽,高
    5. };

    用 onclick 打单个点,用 onmousemove 跟随鼠标打点,鼠标到哪点打到哪儿

    2.5.设置开关(鼠标按下去开始画,松开停止)

    前面的 const 改成 let
    加上

    1. let painting = false; //painting 是自己取的名字
    2. canvas.onmousedown = (e) => {
    3. painting = true;
    4. };//鼠标按下时 painting = true
    5. canvas.onmousemove = (e) => {
    6. if (painting === true) {
    7. ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10);
    8. } else {
    9. console.log("什么都不做");
    10. }
    11. };
    12. //如果painting === true ,执行画矩形点的命令,否则什么都不做
    13. canvas.onmouseup = () => {
    14. painting = false;
    15. };//鼠标抬起时 painting = false

    此时就可以按下鼠标时移动就会一直画点,松开就什么都不做
    image.png

    2.6.解决锯齿问题

    2.6.1.将矩形框改成圆形(参考教程)

    将之前的canvas.onmousemove 内容改成如下

    1. canvas.onmousemove = (e) => {
    2. if (painting === true) {
    3. ctx.beginPath();
    4. ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);
    5. //圆心到左边框距离,上,半径,起始弧度0,中止弧度2π
    6. ctx.stroke();
    7. ctx.fill();//填充
    8. } else {
    9. console.log("什么都不做");
    10. }
    11. };

    改变背景填充色为黑色
    效果如下
    image.png
    目前看的感觉还是拼凑的,但是没有像之前用矩形时有锯齿
    最终的代码如下

    1. <!DOCTYPE html>
    2. <html lang="zh-CN">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    6. <title>画板</title>
    7. <link rel="stylesheet" href="style.css" />
    8. <!-- 引入一个CSS样式文档 -->
    9. </head>
    10. <body>
    11. <canvas id="canvas" width="100" height="100"></canvas>
    12. <script>
    13. let canvas = document.getElementById("canvas"); //获取 canvas
    14. let ctx = canvas.getContext("2d");
    15. canvas.width = document.documentElement.clientWidth;
    16. canvas.height = document.documentElement.clientHeight;
    17. //把canvas的宽高变成文档的宽高(注意不要变成body的宽高,宽度合适,但是高度只有body的高)
    18. let painting = false; //painting 是自己取的名字
    19. ctx.fillStyle = "black"; //填充样式
    20. canvas.onmousedown = () => {
    21. painting = true;
    22. }; //鼠标按下时 painting = true
    23. canvas.onmousemove = (e) => {
    24. if (painting === true) {
    25. ctx.beginPath();
    26. ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);
    27. //圆心到左边框距离,上,半径,起始弧度0,中止弧度2π
    28. ctx.stroke();
    29. ctx.fill(); //填充
    30. } else {
    31. console.log("什么都不做");
    32. }
    33. };
    34. //如果painting === true ,执行画矩形点的命令,否则什么都不做
    35. canvas.onmouseup = () => {
    36. painting = false;
    37. };
    38. //鼠标抬起时 painting = false
    39. </script>
    40. </body>
    41. </html>

    3.让手机上也能使用画板

    用上面的代码会发现切换成手机模式没有任何效果

    3.1.怎么确认手机模式是否支持鼠标

    可搜索 js 浏览器是否支持触屏/js detect touch support
    寻找代码,打 log 试出来的
    (如果没找出来就只能设置屏幕宽度来制定是电脑还是触屏设备)

    1. var isTouchDevice = "ontouchstart" in document.documentElement;
    2. console.log(isTouchDevice);

    image.png
    切换成手机模式,刷新页面
    image.png

    3.2.如何分别执行两种模式

    3.2.1.代码如下(先用 log 看手机模式是否发生事件)

    ```javascript

    1. if (isTouchDevice) {
    2. canvas.ontouchmove = (e) => {
    3. console.log(e);
    4. };
    5. } else {
    6. canvas.onmousedown = () => {
    7. painting = true;
    8. }; //鼠标按下时 painting = true
    9. canvas.onmousemove = (e) => {
    10. if (painting === true) {
    11. ctx.beginPath();
    12. ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);
    13. //圆心到左边框距离,上,半径,起始弧度0,中止弧度2π
    14. ctx.stroke();
    15. ctx.fill(); //填充
    16. } else {
    17. console.log("什么都不做");
    18. }
    19. };
    20. //如果painting === true ,执行画矩形点的命令,否则什么都不做
    21. canvas.onmouseup = () => {
    22. painting = false;
    23. //鼠标抬起时 painting = false
    24. };
    25. }
    26. //如果是触屏模式执行前面的新加的,如果不是触屏模式,执行之前的三个鼠标模式(将之前的三个鼠标模式放入else里)
  1. - 因为触摸手机不一定是一根手指,所以 x y touches
  2. - 切换成手机模式会,鼠标在上面移动几下,会出现很多事件,点击其中一个,如下图:
  3. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1550299/1593428553136-1e1238de-84dd-42e9-aa8d-e3be44faf365.png#align=left&display=inline&height=927&margin=%5Bobject%20Object%5D&name=image.png&originHeight=927&originWidth=958&size=84194&status=done&style=none&width=958)
  4. <a name="rd7tG"></a>
  5. #### 3.2.2.实现鼠标点击出现x,y
  6. ```javascript
  7. canvas.ontouchmove = (e) => {
  8. let x = e.touches[0].clientX;
  9. let y = e.touches[0].clientY;
  10. console.log(x, y);
  11. };

找到对应位置替换代码
效果图如下
image.png

3.2.3.画点(触屏就不需要再设置鼠标按下事件了,没触屏的时候自然没有按在屏幕上)

以下代码加入到 canvas.ontouchmove 里

  1. ctx.beginPath();
  2. ctx.arc(x, y, 10, 0, 2 * Math.PI);
  3. ctx.stroke();
  4. ctx.fill();

实现效果
image.png
实现完成就可以把前面的 log 删除了

4.canvas 画线

4.1.加一个函数,把画线的代码放进去

  1. function drawLine(x1, y1, x2, y2) {
  2. ctx.beginPath();
  3. ctx.moveTo(x1, y1);
  4. ctx.lineTo(x2, y2);
  5. ctx.stroke();
  6. }

可以先让第二个点为鼠标点的那个点,第一个点暂设(0,0)

  1. canvas.onmousemove = (e) => {
  2. if (painting === true) {
  3. drawLine(0, 0, e.clientX, e.clientY);
  4. } else {
  5. console.log("什么都不做");
  6. }
  7. };

此时的效果图
image.png

4.2.怎么让第一个点为上一个点

  • [x] 先声明一个 last 变量

    1. let last; //声明一个 last 变量
  • [x] 第一个点没有上一个点,所以在第一个点加上上一个点,同时要定义一个在 canvas.onmousedown上定义一个值,这里是定义的 e

    1. canvas.onmousedown = (e) => {
    2. painting = true;
    3. last = [e.clientX, e.clientY]; //第一的点的上一个点也设置成第一个点
    4. };
  • [x] 实时更新 last

    1. canvas.onmousemove = (e) => {
    2. if (painting === true) {
    3. drawLine(last[0], last[1], e.clientX, e.clientY);
    4. last = [e.clientX, e.clientY]; //实时更新 last,画完一个点就让这个点变成下一个点的上一个点
    5. } else {
    6. console.log("什么都不做");
    7. }
    8. };

    此时效果图
    image.png

    4.3.设置线宽

    1. ctx.lineWidth = 8;

    此时会出现一个问题,线比较宽(>4px)时,转角的地方会出现空缺
    image.png
    明显一点点图
    image.png

    4.4.处理转角的地方,使其更圆滑

    加上一句代码即可

    1. ctx.lineCap = "round";

    再宽的线也不会出问题了
    image.png

    4.5.画线-手机模式调试

    此时就先需要加一个起始点 canvas.ontouchstart
    再调整 canvas.ontouchmove

    1. canvas.ontouchstart = (e) => {
    2. let x = e.touches[0].clientX;
    3. let y = e.touches[0].clientY; //声明x,y
    4. last = [x, y];
    5. };
    6. canvas.ontouchmove = (e) => {
    7. let x = e.touches[0].clientX;
    8. let y = e.touches[0].clientY; //声明x,y
    9. drawLine(last[0], last[1], x, y);
    10. last = [x, y];
    11. };

补充

解析 canvas.onmousemove = (e) => {}

浏览器会调用 canvas.onmousemove,其中的e可以改成别的任意代替
canvas.onmousemove (事件相关信息)

let、var、const的区别

let 的用法类似于 var,但是 let 只在所在的代码块内有效,所以我们一般使用 let 替代 var。而 const 用来声明常量。

iOS系统弹性滚动未处理

微信下拉框