日本免费精品_最新日韩一区_亚洲视频一区在线_a在线视频观看_天天射夜夜骑_粉嫩av一区二区三区_欧美中日韩免费视频_综合图区欧美_国内精品美女在线观看_午夜精品久久久久久久男人的天堂

首頁(yè) > 編程 > HTML > 正文

手把手教你實(shí)現(xiàn)一個(gè)canvas智繪畫(huà)板的方法

2024-08-26 00:21:22
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本文主要介紹:

  • 項(xiàng)目介紹
  • 項(xiàng)目效果展示
  • 一步步實(shí)現(xiàn)項(xiàng)目效果
  • 踩坑

 一、項(xiàng)目介紹

名稱(chēng):智繪畫(huà)板

技術(shù)棧:HTML5,CSS3,JavaScript,移動(dòng)端

功能描述:

  • 支持PC端和移動(dòng)端在線繪畫(huà)功能
  • 實(shí)現(xiàn)任意選擇畫(huà)筆顏色、調(diào)整畫(huà)筆粗細(xì)以及橡皮檫擦除等繪畫(huà)功能
  • 實(shí)現(xiàn)在線畫(huà)板的本地保存功能
  • 支持撤銷(xiāo)和返回操作
  • 自定義背景顏色

 二、項(xiàng)目效果展示

項(xiàng)目地址 預(yù)覽地址

預(yù)覽圖

PC端的預(yù)覽圖:

canvas,智繪畫(huà)板

移動(dòng)端的預(yù)覽圖:

canvas,智繪畫(huà)板

看完上面的預(yù)覽圖和體驗(yàn)過(guò) 智繪畫(huà)板 覺(jué)得還可以的,記得點(diǎn)個(gè)贊哦,不管你是否十分激動(dòng),反正我是挺激動(dòng)的,畢竟自己實(shí)現(xiàn)出現(xiàn)的項(xiàng)目效果,挺自豪的,說(shuō)了一堆廢話,下面就可以動(dòng)起手來(lái)敲代碼,實(shí)現(xiàn)自己想要的效果?。?!

注:下面實(shí)現(xiàn)項(xiàng)目效果主要是關(guān)于JavaScript方面的,下面僅僅是提供 實(shí)現(xiàn)思路的代碼 , 并非全部代碼 。

三、一步步實(shí)現(xiàn)項(xiàng)目效果

(一)分析頁(yè)面

通過(guò) 用例圖 ,我們知道用戶(hù)進(jìn)入我們這個(gè)網(wǎng)站有哪些功能?

用戶(hù)可以進(jìn)行的操作:

  • 畫(huà)畫(huà)
  • 改變畫(huà)筆的粗細(xì)
  • 切換畫(huà)筆的顏色
  • 使用橡皮檫擦除不想要的部分
  • 清空畫(huà)板
  • 將自己畫(huà)的東西保存成圖片
  • 進(jìn)行撤銷(xiāo)和重做操作
  • 切換畫(huà)板背景顏色
  • 兼容移動(dòng)端(支持觸摸)

(二)進(jìn)行HTML布局

我書(shū)寫(xiě)html的同時(shí),引入了css文件和js文件

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>智繪畫(huà)板</title>    <link rel="shortcut icon" href="./image/favicon.png" type="image/x-icon">    <link rel="stylesheet" href="./css/style.css"></head><body>    <canvas id="canvas"></canvas>    <div class="bg-btn"></div>    <div class="color-group" id="bgGroup">        <h3>選擇背景顏色:</h3>        <ul class="clearfix">            <li class="bgcolor-item" style="background-color: blue;"></li>            <li class="bgcolor-item" style="background-color: black;"></li>            <li class="bgcolor-item" style="background-color: #FF3333;"></li>            <li class="bgcolor-item" style="background-color: #0066FF;"></li>            <li class="bgcolor-item" style="background-color: #FFFF33;"></li>            <li class="bgcolor-item" style="background-color: #33CC66;"></li>            <li class="bgcolor-item" style="background-color: gray;"></li>            <li class="bgcolor-item" style="background-color: #F34334;"></li>            <li class="bgcolor-item" style="background-color: #fff;box-shadow: 0 1px 2px 0 rgba(32,33,36,0.28);"></li>            <li class="bgcolor-item" style="background-color: #9B27AC;"></li>            <li class="bgcolor-item" style="background-color: #4CB050;"></li>            <li class="bgcolor-item" style="background-color: #029688;"></li>        </ul>        <i class="closeBtn"></i>    </div>    <div class="tools">        <div class="container">            <button class="save"  id="save"            <button class="brush active" id="brush"            <button class="eraser" id="eraser"            <button class="clear" id="clear"            <button class="undo"  id="undo"            <button class="redo"  id="redo"        </div>    </div>    <div class="pen-detail" id="penDetail">        <i class="closeBtn"></i>        <p>筆大小</p>        <span class="circle-box"><i id="thickness"></i></span> <input type="range" id="range1" min="1" max="10" value="1">        <p>筆顏色</p>        <ul class="pen-color clearfix">            <li class="color-item active" style="background-color: black;"></li>            <li class="color-item" style="background-color: #FF3333;"></li>            <li class="color-item" style="background-color: #99CC00;"></li>            <li class="color-item" style="background-color: #0066FF;"></li>            <li class="color-item" style="background-color: #FFFF33;"></li>            <li class="color-item" style="background-color: #33CC66;"></li>        </ul>        <p>不透明度</p>        <i class="showOpacity"></i> <input type="range" id="range2" min="1" max="10" value="1">    </div>    <script src="./js/main.js"></script></body></html>

(三)用CSS美化界面

css代碼可以根據(jù)個(gè)人習(xí)慣進(jìn)行美化界面,所以這里就不寫(xiě)css的代碼了,大家可以直接看 項(xiàng)目代碼 或者從開(kāi)發(fā)者工具中審查元素觀看。如果有問(wèn)題可以私聊我,我覺(jué)得問(wèn)題不大。

(四)使用JS實(shí)現(xiàn)項(xiàng)目的具體功能

1.準(zhǔn)備工作

首先,準(zhǔn)備個(gè)容器,也就是畫(huà)板了,前面的html已經(jīng)書(shū)寫(xiě)好這個(gè)容器,這里純屬是廢話。

<canvas id="canvas"></canvas>

然后初始化js

let canvas = document.getElementById('canvas');let context = canvas.getContext('2d');

我打算把畫(huà)板做成全屏的,所以接下來(lái)設(shè)置一下 canvas 的寬高

let pageWidth = document.documentElement.clientWidth;let pageHeight = document.documentElement.clientHeight;canvas.width = pageWidth;canvas.height = pageHeight;

由于部分IE不支持 canvas ,如果要兼容IE,我們可以創(chuàng)建一個(gè) canvas ,然后使用 excanvas 初始化,針對(duì)IE加上exCanvas.js,這里我們明確不考慮IE。

但是我在電腦上對(duì)瀏覽器的窗口進(jìn)行改變,畫(huà)板不會(huì)自適應(yīng)的放縮。解決辦法:

// 記得要執(zhí)行autoSetSize這個(gè)函數(shù)哦function autoSetSize(){    canvasSetSize();    // 當(dāng)執(zhí)行這個(gè)函數(shù)的時(shí)候,會(huì)先設(shè)置canvas的寬高    function canvasSetSize(){        let pageWidth = document.documentElement.clientWidth;        let pageHeight = document.documentElement.clientHeight;                canvas.width = pageWidth;        canvas.height = pageHeight;    }    // 在窗口大小改變之后,就會(huì)觸發(fā)resize事件,重新設(shè)置canvas的寬高    window.onresize = function(){        canvasSetSize();    }}

2.實(shí)現(xiàn)畫(huà)畫(huà)的功能

實(shí)現(xiàn)思路:監(jiān)聽(tīng)鼠標(biāo)事件, 用 drawLine() 方法把記錄的數(shù)據(jù)畫(huà)出來(lái)。

  • 初始化當(dāng)前畫(huà)板的畫(huà)筆狀態(tài), painting = false 。
  • 當(dāng)鼠標(biāo)按下時(shí)( mousedown ),把 painting 設(shè)為 true ,表示正在畫(huà),鼠標(biāo)沒(méi)松開(kāi)。把鼠標(biāo)點(diǎn)記錄下來(lái)。
  • 當(dāng)按下鼠標(biāo)的時(shí)候,鼠標(biāo)移動(dòng)( mousemove )就 把點(diǎn)記錄 下來(lái)并畫(huà)出來(lái)。 如果鼠標(biāo)移動(dòng)過(guò)快,瀏覽器跟不上繪畫(huà)速度,點(diǎn)與點(diǎn)之間會(huì)出現(xiàn)間隙,所以我們需要將畫(huà)出的點(diǎn)用線連起來(lái)( lineTo() )。
  • 鼠標(biāo)松開(kāi)的時(shí)候( mouseup ),把 painting 設(shè)為 false 。

注: drawCircle 這個(gè)方法其實(shí)可以不用書(shū)寫(xiě),這個(gè)只是為了讓大家能夠理解開(kāi)始點(diǎn)擊的位置在哪里?

function listenToUser() {    // 定義一個(gè)變量初始化畫(huà)筆狀態(tài)    let painting = false;    // 記錄畫(huà)筆最后一次的位置    let lastPoint = {x: undefined, y: undefined};    // 鼠標(biāo)按下事件    canvas.onmousedown = function(e){        painting = true;        let x = e.clientX;        let y = e.clientY;        lastPoint = {'x':x,'y':y};        drawCircle(x,y,5);    }    // 鼠標(biāo)移動(dòng)事件    canvas.onmousemove = function(e){        if(painting){            let x = e.clientX;            let y = e.clientY;            let newPoint = {'x':x,'y':y};            drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);            lastPoint = newPoint;        }    }    // 鼠標(biāo)松開(kāi)事件    canvas.onmouseup = function(){        painting = false;    }}// 畫(huà)點(diǎn)函數(shù)function drawCircle(x,y,radius){    // 新建一條路徑,生成之后,圖形繪制命令被指向到路徑上生成路徑。    context.beginPath();    // 畫(huà)一個(gè)以(x,y)為圓心的以radius為半徑的圓弧(圓),    // 從startAngle開(kāi)始到endAngle結(jié)束,按照anticlockwise給定的方向(默認(rèn)為順時(shí)針)來(lái)生成。    context.arc(x,y,radius,0,Math.PI*2);    // 通過(guò)填充路徑的內(nèi)容區(qū)域生成實(shí)心的圖形    context.fill();    // 閉合路徑之后圖形繪制命令又重新指向到上下文中。    context.closePath();}function drawLine(x1,y1,x2,y2){    // 設(shè)置線條寬度    context.lineWidth = 10;    // 設(shè)置線條末端樣式。    context.lineCap = "round";    // 設(shè)定線條與線條間接合處的樣式    context.lineJoin = "round";    // moveTo(x,y)將筆觸移動(dòng)到指定的坐標(biāo)x以及y上    context.moveTo(x1,y1);    // lineTo(x, y) 繪制一條從當(dāng)前位置到指定x以及y位置的直線    context.lineTo(x2,y2);    // 通過(guò)線條來(lái)繪制圖形輪廓    context.stroke();    context.closePath();}

3.實(shí)現(xiàn)橡皮擦功能

實(shí)現(xiàn)思路:

  1. 獲取橡皮擦元素
  2. 設(shè)置橡皮擦初始狀態(tài), eraserEnabled = false 。
  3. 監(jiān)聽(tīng)橡皮擦 click 事件,點(diǎn)擊橡皮擦,改變橡皮擦狀態(tài), eraserEnabled = true ,并且切換class,實(shí)現(xiàn) 被激活 的效果。
  4. eraserEnabled 為 true 時(shí),移動(dòng)鼠標(biāo)用 context.clearRect() 實(shí)現(xiàn)了 橡皮檫。

但是我發(fā)現(xiàn)canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除區(qū)域矩形,畢竟大部分人的習(xí)慣中的橡皮擦都是圓形的,所以就引入了剪輯區(qū)域這個(gè)強(qiáng)大的功能,也就是clip方法。下面的代碼是使用 context.clearRect() 實(shí)現(xiàn)了 橡皮檫。請(qǐng)看踩坑部分,了解如何更好的實(shí)現(xiàn)橡皮檫。

let eraser = document.getElementById("eraser");let eraserEnabled = false;// 記得要執(zhí)行l(wèi)istenToUser這個(gè)函數(shù)哦function listenToUser() {   	// ... 代表省略了之前寫(xiě)的代碼    // ...    // 鼠標(biāo)按下事件    canvas.onmousedown = function(e){        // ...        if(eraserEnabled){//要使用eraser            context.clearRect(x-5,y-5,10,10)        }else{            lastPoint = {'x':x,'y':y}        }    }    // 鼠標(biāo)移動(dòng)事件    canvas.onmousemove = function(e){        let x = e.clientX;        let y = e.clientY;        if(!painting){return}        if(eraserEnabled){            context.clearRect(x-5,y-5,10,10);        }else{            var newPoint = {'x':x,'y':y};            drawLine(lastPoint.x, lastPoint.y,newPoint.x, newPoint.y);            lastPoint = newPoint;        }      }    // ...}// 點(diǎn)擊橡皮檫eraser.onclick = function(){    eraserEnabled = true;    eraser.classList.add('active');    brush.classList.remove('active');}

4.實(shí)現(xiàn)清屏功能

實(shí)現(xiàn)思路:

獲取元素節(jié)點(diǎn)。

點(diǎn)擊清空按鈕清空canvas畫(huà)布。

let reSetCanvas = document.getElementById("clear");// 實(shí)現(xiàn)清屏reSetCanvas.onclick = function(){    ctx.clearRect(0,0,canvas.width,canvas.height);    setCanvasBg('white');}// 重新設(shè)置canvas背景顏色function setCanvasBg(color) {    ctx.fillStyle = color;    ctx.fillRect(0, 0, canvas.width, canvas.height);}

5.實(shí)現(xiàn)保存成圖片功能

實(shí)現(xiàn)思路:

  • 獲取canvas.toDateURL
  • 在頁(yè)面里創(chuàng)建并插入一個(gè)a標(biāo)簽
  • a標(biāo)簽href等于canvas.toDateURL,并添加download屬性
  • 點(diǎn)擊保存按鈕,a標(biāo)簽觸發(fā)click事件
let save = document.getElementById("save");// 下載圖片save.onclick = function(){    let imgUrl = canvas.toDataURL('image/png');    let saveA = document.createElement('a');    document.body.appendChild(saveA);    saveA.href = imgUrl;    saveA.download = 'mypic'+(new Date).getTime();    saveA.target = '_blank';    saveA.click();}

6.實(shí)現(xiàn)改變背景顏色的功能

實(shí)現(xiàn)思路:

  1. 獲取相應(yīng)的元素節(jié)點(diǎn)。
  2. 給每一個(gè)class為bgcolor-item的標(biāo)簽添加點(diǎn)擊事件,當(dāng)點(diǎn)擊事件觸發(fā)時(shí),改變背景顏色。
  3. 點(diǎn)擊設(shè)置背景顏色的div之外的地方,實(shí)現(xiàn)隱藏那個(gè)div。
let selectBg = document.querySelector('.bg-btn');let bgGroup = document.querySelector('.color-group');let bgcolorBtn = document.querySelectorAll('.bgcolor-item');let penDetail = document.getElementById("penDetail");let activeBgColor = '#fff';// 實(shí)現(xiàn)了切換背景顏色for (let i = 0; i < bgcolorBtn.length; i++) {    bgcolorBtn[i].onclick = function (e) {        // 阻止冒泡        e.stopPropagation();        for (let i = 0; i < bgcolorBtn.length; i++) {            bgcolorBtn[i].classList.remove("active");            this.classList.add("active");            activeBgColor = this.style.backgroundColor;            setCanvasBg(activeBgColor);        }    }}document.onclick = function(){    bgGroup.classList.remove('active');}selectBg.onclick = function(e){    bgGroup.classList.add('active');    e.stopPropagation();}

7.實(shí)現(xiàn)改變畫(huà)筆粗細(xì)的功能

實(shí)現(xiàn)思路:

  1. 實(shí)現(xiàn)讓設(shè)置畫(huà)筆的屬性的對(duì)話框出現(xiàn)。
  2. 獲取相應(yīng)的元素節(jié)點(diǎn)。
  3. 當(dāng)input=range的元素發(fā)生改變的時(shí)候,獲取到的值賦值給lWidth。
  4. 然后設(shè)置context.lineWidth = lWidth。
let range1 = document.getElementById('range1');let lWidth = 2;let ifPop = false;range1.onchange = function(){    console.log(range1.value);    console.log(typeof range1.value)    thickness.style.transform = 'scale('+ (parseInt(range1.value)) +')';    console.log(thickness.style.transform )    lWidth = parseInt(range1.value*2);}// 畫(huà)線函數(shù)function drawLine(x1,y1,x2,y2){    // ...    context.lineWidth = lWidth;    // ...}// 點(diǎn)擊畫(huà)筆brush.onclick = function(){    eraserEnabled = false;    brush.classList.add('active');    eraser.classList.remove('active');    if(!ifPop){        // 彈出框        console.log('彈一彈')        penDetail.classList.add('active');    }else{        penDetail.classList.remove('active');    }    ifPop = !ifPop;}

8.實(shí)現(xiàn)改變畫(huà)筆顏色的功能

實(shí)現(xiàn)思路跟 改變畫(huà)板背景顏色 的思路類(lèi)似。

let aColorBtn = document.getElementsByClassName("color-item");getColor();function getColor(){    for (let i = 0; i < aColorBtn.length; i++) {        aColorBtn[i].onclick = function () {            for (let i = 0; i < aColorBtn.length; i++) {                aColorBtn[i].classList.remove("active");                this.classList.add("active");                activeColor = this.style.backgroundColor;                ctx.fillStyle = activeColor;                ctx.strokeStyle = activeColor;            }        }    }}

9.實(shí)現(xiàn)改變撤銷(xiāo)和重做的功能

實(shí)現(xiàn)思路:

  1. 保存快照:每完成一次繪制操作則保存一份 canvas 快照到 canvasHistory 數(shù)組(生成快照使用 canvas 的 toDataURL() 方法,生成的是 base64 的圖片);
  2. 撤銷(xiāo)和反撤銷(xiāo):把 canvasHistory 數(shù)組中對(duì)應(yīng)索引的快照使用 canvas 的 drawImage() 方法重繪一遍;
  3. 繪制新圖像:執(zhí)行新的繪制操作時(shí),刪除當(dāng)前位置之后的數(shù)組記錄,然后添加新的快照。
let undo = document.getElementById("undo");let redo = document.getElementById("redo");// ...canvas.onmouseup = function(){        painting = false;        canvasDraw();}let canvasHistory = [];let step = -1;// 繪制方法function canvasDraw(){    step++;    if(step < canvasHistory.length){        canvasHistory.length = step;  // 截?cái)鄶?shù)組    }    // 添加新的繪制到歷史記錄    canvasHistory.push(canvas.toDataURL());}// 撤銷(xiāo)方法function canvasUndo(){    if(step > 0){        step--;        // ctx.clearRect(0,0,canvas.width,canvas.height);        let canvasPic = new Image();        canvasPic.src = canvasHistory[step];        canvasPic.onload = function () { ctx.drawImage(canvasPic, 0, 0); }        undo.classList.add('active');    }else{        undo.classList.remove('active');        alert('不能再繼續(xù)撤銷(xiāo)了');    }}// 重做方法function canvasRedo(){    if(step < canvasHistory.length - 1){        step++;        let canvasPic = new Image();        canvasPic.src = canvasHistory[step];        canvasPic.onload = function () {             // ctx.clearRect(0,0,canvas.width,canvas.height);            ctx.drawImage(canvasPic, 0, 0);        }        redo.classList.add('active');    }else {        redo.classList.remove('active')        alert('已經(jīng)是最新的記錄了');    }}undo.onclick = function(){    canvasUndo();}redo.onclick = function(){    canvasRedo();}

10.兼容移動(dòng)端

實(shí)現(xiàn)思路:

  • 判斷設(shè)備是否支持觸摸
  • true ,則使用 touch 事件; false ,則使用 mouse 事件
// ...if (document.body.ontouchstart !== undefined) {    // 使用touch事件    anvas.ontouchstart = function (e) {        // 開(kāi)始觸摸    }    canvas.ontouchmove = function (e) {        // 開(kāi)始滑動(dòng)    }    canvas.ontouchend = function () {        // 滑動(dòng)結(jié)束    }}else{    // 使用mouse事件    // ...}// ...

四、踩坑

 問(wèn)題1:在電腦上對(duì)瀏覽器的窗口進(jìn)行改變,畫(huà)板不會(huì)自適應(yīng)

解決辦法:

onresize響應(yīng)事件處理中,獲取到的頁(yè)面尺寸參數(shù)是變更后的參數(shù) 。

當(dāng)窗口大小發(fā)生改變之后,重新設(shè)置canvas的寬高,簡(jiǎn)單來(lái)說(shuō),就是窗口改變之后,給canvas.width和canvas.height重新賦值。

// 記得要執(zhí)行autoSetSize這個(gè)函數(shù)哦function autoSetSize(){    canvasSetSize();    // 當(dāng)執(zhí)行這個(gè)函數(shù)的時(shí)候,會(huì)先設(shè)置canvas的寬高    function canvasSetSize(){        let pageWidth = document.documentElement.clientWidth;        let pageHeight = document.documentElement.clientHeight;                canvas.width = pageWidth;        canvas.height = pageHeight;    }    // 在窗口大小改變之后,就會(huì)觸發(fā)resize事件,重新設(shè)置canvas的寬高    window.onresize = function(){        canvasSetSize();    }}

問(wèn)題2:當(dāng)繪制線條寬度比較小的時(shí)候還好,一旦比較粗就會(huì)出現(xiàn)問(wèn)題

解決辦法:看一下文檔,得出方法,只需要簡(jiǎn)單修改一下 繪制線條的代碼 就行

// 畫(huà)線函數(shù)function drawLine(x1,y1,x2,y2){    context.beginPath();    context.lineWidth = lWidth;    //-----加入-----    // 設(shè)置線條末端樣式。    context.lineCap = "round";    // 設(shè)定線條與線條間接合處的樣式    context.lineJoin = "round";    //-----加入-----    context.moveTo(x1,y1);    context.lineTo(x2,y2);    context.stroke();    context.closePath();}

問(wèn)題3:如何實(shí)現(xiàn)圓形的橡皮檫?

解決辦法:

canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除區(qū)域矩形,畢竟大部分人的習(xí)慣中的橡皮擦都是圓形的,所以就引入了剪輯區(qū)域這個(gè)強(qiáng)大的功能,也就是clip方法。用法很簡(jiǎn)單:

ctx.save()ctx.beginPath()ctx.arc(x2,y2,a,0,2*Math.PI);ctx.clip()ctx.clearRect(0,0,canvas.width,canvas.height);ctx.restore();

上面那段代碼就實(shí)現(xiàn)了圓形區(qū)域的擦除,也就是先實(shí)現(xiàn)一個(gè)圓形路徑,然后把這個(gè)路徑作為剪輯區(qū)域,再清除像素就行了。有個(gè)注意點(diǎn)就是需要先保存繪圖環(huán)境,清除完像素后要重置繪圖環(huán)境,如果不重置的話以后的繪圖都是會(huì)被限制在那個(gè)剪輯區(qū)域中。

問(wèn)題4:如何兼容移動(dòng)端?

1.添加meta標(biāo)簽

因?yàn)闉g覽器初始會(huì)將頁(yè)面現(xiàn)在手機(jī)端顯示時(shí)進(jìn)行縮放,因此我們可以在meta標(biāo)簽中設(shè)置meta viewport屬性,告訴瀏覽器不將頁(yè)面進(jìn)行縮放,頁(yè)面寬度=用戶(hù)設(shè)備屏幕寬度

<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0"/>/*頁(yè)面寬度=移動(dòng)寬度 :width=device-width用戶(hù)不可以縮放:user-scalable=no縮放比例:initial-scale=1最大縮放比例:maximum-scale=1.0最小縮放比例:minimum-scale=1.0*/

2.在移動(dòng)端幾乎使用的都是touch事件,與PC端不同

由于移動(dòng)端是觸摸事件,所以要用到H5的屬性touchstart/touchmove/touchend,但是PC端只支持鼠標(biāo)事件,所以要進(jìn)行特性檢測(cè)。

在 touch 事件里,是通過(guò) .touches[0].clientX 和 .touches[0].clientY 來(lái)獲取坐標(biāo)的,這點(diǎn)要和 mouse 事件區(qū)別開(kāi)。

問(wèn)題5:出現(xiàn)一個(gè)問(wèn)題就是清空之后,重新畫(huà),然后出現(xiàn)原來(lái)的畫(huà)的東西

這個(gè)嘛,問(wèn)題不大,只不過(guò)是我漏寫(xiě)context.beginPath(); ,也花了一點(diǎn)時(shí)間在上面解決bug,讓我想起“代碼千萬(wàn)行,注釋第一行;編程不規(guī)范,同事兩行淚 ”,還是按照文檔操作規(guī)范操作好,真香!!!

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到HTML教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产丝袜一区| 国产乱国产乱300精品| 日韩 欧美 综合| 国产午夜在线观看| 91精品无人成人www| 国产婷婷一区二区| 亚洲福利在线视频| 色综合天天性综合| 日韩欧美国产高清91| 在线视频日韩欧美| 黄色国产网站在线观看| 国产福利免费在线观看| 日韩免费电影网站| 欧美一级一级性生活免费录像| av免费观看网站| 欧美三级一区二区三区| 精品全国在线一区二区| 欧美变态tickling挠脚心| 91精品国产自产| 99精品人妻国产毛片| av亚洲免费| 樱花草www在线| 91精品国产91久久久久久青草| 精品福利在线观看| 欧美亚洲另类制服自拍| 国产 日韩 欧美 综合 一区| 国产 欧美 在线| 免费在线国产| 久久久99免费| 中文字幕一区二区三区精品| 久久网站免费观看| 99久久久精品免费观看国产| 亚洲免费中文字幕| 在线观看一区| 欧美日韩在线观看成人| 一区二区精品| 在线看av的网址| 蜜桃视频一日韩欧美专区| 中文字幕视频在线免费欧美日韩综合在线看 | 国产中文在线观看| 久久精品久久精品亚洲人| 玖玖在线免费视频| 国产欧美日韩在线观看| 在线观看国产一级片| 日韩精品大片| 国产不卡一区| 99精品电影| 欧美日韩成人综合| 日韩欧美一级在线| 亚洲视频资源在线| 欧美变态tickling挠脚心| 亚洲成年人影院在线| 亚洲欧洲三级| 国产在线看一区| 国产极品嫩模在线视频一区 | 老司机久久99久久精品播放免费| 亚洲中文字幕在线一区| 影音先锋中文字幕在线观看| 欧美日韩亚州综合| 69堂精品视频在线播放| 亚洲国产91精品在线观看| 丰满少妇一区| 欧美日韩精品免费| www日韩欧美| 蜜桃视频一日韩欧美专区| 亚洲 欧美 中文字幕| 色综合久久六月婷婷中文字幕| 在线视频不卡国产V| 韩国av一区二区| 视频一区视频二区中文| 国产色在线 com| av一区在线观看| 中文在线视频| 精人妻一区二区三区| 欧美日韩精品免费看| 欧美 日韩 国产 在线观看| 欧美日韩亚洲国产综合| 亚洲经典中文字幕| 亚洲第一中文字幕在线观看| 欧美日韩国产免费观看视频| 亚洲一区视频在线观看视频| 婷婷精品视频| 在线看av的网址| 日韩精品视频中文在线观看| 91精品啪在线观看国产60岁| 蜜桃视频一日韩欧美专区| 亚洲日本精品视频| 伊人中文字幕在线观看| 91精品国产综合久久久久| 天堂精品高清1区2区3区| 亚洲欧美999| 欧美激情视频一区二区三区在线播放| 欧美日韩三级在线| 在线欧美日韩国产| 国产性一级片| 中文字幕在线视频久| 久久精品网站免费观看| 精品久久九九| av最新网址| 国产对白在线| 精品国产91乱高清在线观看| 阿v免费在线观看| aa国产成人| 蜜桃久久av一区| 91精品视频播放| 久久99久久久久久久噜噜| 国产丝袜欧美中文另类| 欧美日韩国产页| 精品久久人人做人人爽| 中文字幕 亚洲一区| 国产日韩av一区二区| 国产99精品| 国产永久在线观看| 国产99精品| 国产偷国产偷亚洲清高网站| 91精品国产自产在线观看永久∴| 91精品国产综合久久久久| 在线看的av| 精品乱人伦一区二区三区| 欧美 中文字幕| 精品在线99| 中文字幕在线中文字幕二区| 国产欧美久久久久久久久| 国产在线小视频| 中文字幕在线欧美| 国产在线视频不卡| 国产成人精品网址| 91精品视频播放| 欧美日韩国产一区中文午夜| 91精品在线视频观看| 中文字幕在线日韩| 日韩中文字幕| 亚洲欧美久久234| 日韩高清不卡| 日本亚洲视频在线| 69av亚洲| 国产福利在线播放| 中文字幕欧美人妻精品一区蜜臀| 中文在线第一页| 欧美亚洲视频在线看网址| 国产免费久久久| 日韩午夜中文字幕| 一区三区二区视频| 日韩激情一区| 日本不卡免费高清视频| 日本黄色一区二区三区| 日韩欧美三级| 中文字幕一区不卡| 中文国产字幕在线观看| 国产九九在线| 精品三级久久| 精品网站999www| 国产一级在线免费观看| 日韩欧美三级视频| 国产日韩精品电影| 91精品久久久久久蜜臀| 99综合精品久久| 久久久精品午夜少妇| 成人福利一区| 中文不卡在线| 亚洲国内精品视频| 日韩在线小视频| www中文字幕在线观看| 日韩精品第一区| 中文字幕在线国产| 亚洲v中文字幕| 欧美日韩国产不卡| 九七久久人人| 精品中文字幕视频| 国产91欧美| 中文字幕日韩高清| 亚洲福利精品| 国产在线一区二区视频| 亚洲综合在线不卡| 91精品在线视频观看| 亚洲专区一区| 日本精品在线播放| 国产视频三级在线观看播放| 日韩视频专区| 欧美 日韩 国产在线| 中文字幕 日韩 欧美| 欧美日韩三级在线| 亚洲一区在线观看视频| 久久视频在线免费观看| 第一页在线观看| 久久久精品国产99久久精品芒果| 91麻豆精品国产91久久久使用方法| 久久视频www| 91精品电影| 久久久精品日韩欧美| 精品亚洲国内自在自线福利| 一区二区视频免费看| 亚洲一区三区在线观看| 精品无人国产偷自产在线| 免费视频中文字幕| 成人无遮挡免费网站视频在线观看| 91一区二区| 日韩在线视频一区二区三区| 51精品免费网站| 国产男女av| 日韩视频国产视频| 欧美日韩精品欧美日韩精品| 日韩在线视频一区| 精品日韩欧美在线| 成人a在线观看| 欧美日韩亚洲国内综合网| 中文在线不卡视频| 欧美日韩国产在线播放| 中文字幕国产日韩| 久久精品夜夜夜夜久久| 亚洲免费播放| 日韩va亚洲va欧洲va国产| 国产午夜精品视频免费不卡69堂 | 亚洲免费观看在线观看| 精品播放一区二区| 日本亚洲欧美| 91精品国产手机| 不卡一区2区| a在线观看免费视频| а√天堂中文在线资源8| 日韩在线不卡| 国产最新在线| 国产欧美日韩亚州综合| 91精品视频播放| 色综合天天综合网天天狠天天 | 精品国自产在线观看| 粉嫩喷白浆久久| 在线视频不卡一区二区| 中文精品在线| 中文字幕在线看视频国产欧美| 一区二区精品区| wwww亚洲| 日韩av一区在线| 久久久99精品久久| 91精品国产亚洲| 日韩中文字幕网| 欧美亚洲视频在线看网址| www高清在线视频日韩欧美| 欧美日韩国产一中文字不卡| 视频一区二区中文字幕| 蜜臀91精品国产高清在线观看| 婷婷精品视频| 国产成人精品免费在线| 欧美日韩中文国产| 91精品xxx在线观看| 亚洲大片精品永久免费| 精品激情国产视频| 国产区视频在线观看| 亚洲福利视频在线| 精品欧美久久久| 欧美日韩国产专区| 在线亚洲免费| 欧美在线中文字幕| 久久99久久久久| 国产乱国产乱老熟300部视频| 国产免费久久久| 日韩字幕在线观看| 久久精品国产91精品亚洲| 亚洲免费中文字幕| 欧美中文字幕| 中文字幕不卡三区| 在线视频一区二区三区在线播放| 欧美日韩国产综合久久| 欧美三级免费观看| 国产丝袜欧美中文另类| 国产劲爆久久| 最近高清中文在线字幕在线观看 | 久久精品免费看| 精品国产99久久久久久| 日韩 欧美 综合| 欧美在线观看视频一区| 欧美一级手机免费观看片| 成年人黄国产| 国产亚洲欧美色| 日韩国产高清一区| 日韩在线视频一区二区三区| 国产拍揄自揄精品视频麻豆| 91精品视频观看| 在线黄色国产电影| 精品日韩视频在线观看| 欧美日韩免费视频| 日韩a一区二区| 精品激情国产视频| 精品在线一区二区| 最近高清中文在线字幕在线观看1| 亚洲人线精品午夜| 伊人亚洲视频| 日韩精品视频免费看| 国产欧美日韩在线观看| 樱花草www在线观看| 国产偷久久久精品专区| 精品日韩视频| 欧美中文字幕| 中文字幕成人乱码在线电影| 国产成人综合av| 日韩精品乱码av一区二区| 国产一级片播放| 欧美一级免费在线观看| 日本精品国语自产拍在线观看| 日韩欧美国产三级| 日韩一级网站| 亚洲大胆人体av| 亚洲免费观看在线观看| 亚洲综合视频一区| 在线中文免费视频| 欧美日韩中文在线| 日韩三级高清在线| 国产69精品久久久久孕妇国产69久久 | 国产婷婷在线观看| 国产三级第一页| 亚洲热在线观看| 一区二区三区精品99久久| 91精品在线观看视频| 亚洲va韩国va欧美va精品| 午夜伊人狠狠久久| 日韩欧美一级二级三级久久久| 欧美日韩综合在线观看| www.狠狠| 日韩精品视频中文在线观看| 国产三级视频网站| 国产欧美日韩最新| 欧美日韩中文另类| 在线观看免费国产成人软件| 欧美三级网址| 欧美色视频一区二区三区在线观看| 亚洲免费福利视频| 亚洲免费在线观看av| 一区二区中文字幕在线| 免费国产h视频在线观看86| 日韩精品资源二区在线| 日韩欧美看国产| 国产不卡精品在线| 国产字幕中文| 欧美日韩高清在线一区| 午夜av一区二区| 久久精品网站免费观看| 九九精品调教| 中文字幕乱码在线| 午夜国产欧美理论在线播放| 亚洲日本精品视频| 日韩中文字幕在线播放| 国产v日产∨综合v精品视频| 欧美国产三级| 蜜臀国产一区| 精品国产999| 午夜一区二区三区| 欧美日韩亚洲一| 欧美高清一级片在线| 国产小视频免费在线观看| 亚洲成av人综合在线观看| 91久久精品国产91性色69| 日韩久久99| 国产三级在线播放| 在线观看91精品国产入口| 人人做人人澡人人爽欧美| 日韩在线 中文字幕| 日韩 欧美 亚洲| 日韩色在线观看| 亚洲一区日韩在线| 国产成人精品av久久| 国产福利一区二区在线精品| 欧美日韩国产首页| 日韩三级视频在线播放| 欧美日韩精品在线视频| 精品一二三区视频| 国产黄在线观看| 欧美国产日韩在线播放| 亚洲娇小xxxx欧美娇小| 日韩免费看网站| 日韩欧美中文字幕一区| 欧美1234区| 精品一性一色一乱农村| 久久人人精品| 亚洲欧美中文在线视频| 免费精品国产自产拍观看| 中文字幕在线视频网| 91精品国产91久久久久久三级| 欧美日韩精品国产| 国产99对白在线播放| aa国产成人| 欧美日韩精品免费| 日韩在线不卡| 深夜福利一区| 国产色综合网| 久久久久久91| 日韩欧美专区在线| 伊人网站在线| 人成在线免费视频| 精品福利二区三区| 国产www在线观看| 中文字幕高清在线播放| 午夜国产在线| 欧美中日韩在线| 精品成a人在线观看| 一区二区日韩视频| 中文字幕日韩欧美| 国产亚洲短视频| 欧美日中文字幕| 第一页在线观看| 欧美日韩精品免费看|