欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript實(shí)現(xiàn)簽名板功能

 更新時(shí)間:2024年10月23日 08:27:22   作者:周尛先森  
簽名板在網(wǎng)頁(yè)應(yīng)用中扮演著重要角色,它們能夠記錄用戶的手寫(xiě)簽名或者繪圖,下面就跟隨小編一起來(lái)學(xué)習(xí)一下如何使用JavaScript實(shí)現(xiàn)簽名板功能

簽名板在網(wǎng)頁(yè)應(yīng)用中扮演著重要角色,它們能夠記錄用戶的手寫(xiě)簽名或者繪圖,從而提升了用戶體驗(yàn)。

在接下來(lái)的內(nèi)容中,我將指導(dǎo)你如何利用 JavaScript 來(lái)開(kāi)發(fā)一個(gè)功能豐富的簽名板。這個(gè)簽名板不僅支持自定義和響應(yīng)式設(shè)計(jì),還具備對(duì)觸摸設(shè)備的兼容、多樣的筆觸樣式選擇,以及將簽名導(dǎo)出為不同格式圖片的能力。此外,我們還將探索如何整合像 signature_pad 這樣的先進(jìn)工具來(lái)增強(qiáng)簽名板的功能。

開(kāi)始

讓我們使用純 HTML、CSS 和 JavaScript 創(chuàng)建一個(gè)簡(jiǎn)單的簽名板。

首先,HTML 文件——在你的工作目錄中創(chuàng)建一個(gè) index.html 文件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript簽名板</title>
    <link rel="stylesheet" href="styles.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >
  </head>
  <body>
    <div class="signature-container">
      <canvas id="signature-pad" width="400" height="200"></canvas>
      <button id="clear">清除</button>
    </div>
    <script src="script.js"></script>
  </body>
</html>

我們將采用 <canvas> 標(biāo)簽來(lái)構(gòu)建簽名板。選擇畫(huà)布作為工具是因?yàn)樗鼮槲覀兲峁┝艘韵鹿δ埽?/p>

  • 利用 JavaScript 實(shí)現(xiàn)自由手寫(xiě),這對(duì)于獲取簽名是必不可少的。
  • 對(duì)畫(huà)布的外觀和行為進(jìn)行個(gè)性化定制,包括線條的顏色、粗細(xì)以及風(fēng)格。
  • 兼容多樣的鼠標(biāo)和觸摸事件,捕捉用戶在繪圖、移動(dòng)以及提筆或松手時(shí)的互動(dòng)。
  • 利用 toDataURL 方法將簽名以圖像形式導(dǎo)出(如 PNG 或 JPEG),這在保存簽名或?qū)⑵渖蟼髦练?wù)器時(shí)非常有用。

接下來(lái),我們將通過(guò) styles.css 為這個(gè)頁(yè)面添加一些樣式,以提升其視覺(jué)效果。

body {
  display: flex;
  justify - content: center;
  align - items: center;
  height: 100vh;
  background - color: #f0f0f0;
  margin: 0;
}

.signature - container {
  display: flex;
  flex - direction: column;
  align - items: center;
}

canvas {
  border: 1px solid#000;
  background - color: #fff;
}

button {
  margin - top: 10px;
  padding: 5px 10px;
  cursor: pointer;
}

然后向目錄中添加一個(gè) script.js 文件:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;
  canvas.addEventListener('mousedown',
  function(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX, e.offsetY);
  });
  canvas.addEventListener('mousemove',
  function(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX, e.offsetY);
      ctx.stroke();
    }
  });
  canvas.addEventListener('mouseup',
  function() {
    drawing = false;
  });
  canvas.addEventListener('mouseout',
  function() {
    drawing = false;
  });
  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });
});

讓我們?cè)敿?xì)解釋一下這段代碼的工作原理:

  • 我們首先通過(guò) canvas 變量來(lái)綁定到頁(yè)面上的 <canvas> 元素。
  • 接著,ctx 變量用于獲取該畫(huà)布的 2D 渲染上下文,它包含了繪制圖形所需的各種方法和屬性。
  • 當(dāng)用戶按下鼠標(biāo)按鈕時(shí),我們通過(guò)一個(gè) mousedown 事件監(jiān)聽(tīng)器來(lái)觸發(fā)繪圖動(dòng)作。此時(shí),ctx.beginPath() 用于開(kāi)啟新的繪圖路徑,而 ctx.moveTo(e.offsetX, e.offsetY) 則將畫(huà)筆定位到鼠標(biāo)點(diǎn)擊的準(zhǔn)確位置。
  • 用戶移動(dòng)鼠標(biāo)時(shí),mousemove 事件監(jiān)聽(tīng)器會(huì)根據(jù)鼠標(biāo)的當(dāng)前位置繪制線條。ctx.lineTo(e.offsetX, e.offsetY) 命令畫(huà)筆繪制一條直線到新位置,隨后 ctx.stroke() 將這條線實(shí)際畫(huà)到畫(huà)布上。
  • 為了結(jié)束繪圖,我們?cè)O(shè)置了 mouseup 和 mouseout 兩個(gè)事件監(jiān)聽(tīng)器,分別在鼠標(biāo)按鈕釋放和鼠標(biāo)光標(biāo)移出畫(huà)布時(shí)停止繪圖。此外,當(dāng)用戶點(diǎn)擊清除按鈕時(shí),ctx.clearRect(0, 0, canvas.width, canvas.height); 用于清除整個(gè)畫(huà)布,為新的繪圖做準(zhǔn)備。

添加觸摸支持

這個(gè)示例主要是為鼠標(biāo)事件設(shè)置的,但它也可以很容易地?cái)U(kuò)展到支持觸摸設(shè)備。以下是 JavaScript 處理觸摸事件:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;

  function startDrawing(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
  }

  function draw(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
      ctx.stroke();
    }
  }

  function stopDrawing() {
    drawing = false;
  }

  // 鼠標(biāo)事件
  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 觸摸事件
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);
  canvas.addEventListener('touchcancel', stopDrawing);

  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });
});

對(duì)于觸摸事件,使用 e.touches[0].clientXe.touches[0].clientY 來(lái)獲取觸摸坐標(biāo)。為了考慮畫(huà)布的位置,使用 canvas.offsetLeftcanvas.offsetTop 進(jìn)行調(diào)整:

自定義

讓我們給簽名板增添一些新功能,比如讓用戶能夠挑選不同的筆觸效果。為此,我們將執(zhí)行以下關(guān)鍵步驟:

  • 在 HTML 代碼中嵌入一個(gè) <select> 標(biāo)簽,它將包含兩個(gè)選項(xiàng):Pen 和 Brush,從而讓用戶可以挑選他們喜歡的筆觸風(fēng)格。
  • 為這些新增的控件編寫(xiě)相應(yīng)的 CSS 樣式,確保它們?cè)陧?yè)面上正確地顯示。
  • 為下拉選擇菜單設(shè)置一個(gè)事件監(jiān)聽(tīng)器,以便在用戶選擇不同的選項(xiàng)時(shí),動(dòng)態(tài)地改變筆觸樣式。
  • 根據(jù)用戶所選擇的筆觸樣式,調(diào)整 ctx.lineWidth(線寬)和 ctx.lineCap(線帽形狀)的值,以反映不同的視覺(jué)效果。

以下是需要添加到 HTML 文件中的代碼片段:

<div class="controls">
  <select id="stroke-style">
    <option value="pen">
      鋼筆
    </option>
    <option value="brush">
      刷子
    </option>
  </select>
  <button id="clear">
    JavaScript簽名板
  </button>
</div>

然后我們更新我們的 CSS:

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f0f0f0;
    margin: 0;
}

.signature-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

canvas {
    border: 1px solid #000;
    background-color: #fff;
}

.controls {
    margin-top: 10px;
    display: flex;
    gap: 10px;
}

button, select {
    padding: 5px 10px;
    cursor: pointer;
}

最后,更新 script.js

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;
  var strokeStyle = 'pen';

  function startDrawing(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
  }

  function draw(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
      ctx.stroke();
    }
  }

  function stopDrawing() {
    drawing = false;
  }

  // 鼠標(biāo)事件
  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 觸摸事件
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);
  canvas.addEventListener('touchcancel', stopDrawing);

  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  document.getElementById('stroke-style').addEventListener('change',
  function(e) {
    strokeStyle = e.target.value;
    if (strokeStyle === 'pen') {
      ctx.lineWidth = 2;
      ctx.lineCap = 'round';
    } else if (strokeStyle === 'brush') {
      ctx.lineWidth = 5;
      ctx.lineCap = 'round';
    }
  });

  // 設(shè)置初始筆畫(huà)樣式
  ctx.lineWidth = 2;
  ctx.lineCap = 'round';
});

處理響應(yīng)性

當(dāng)屏幕縮小時(shí),簽名板可能因?yàn)槿鄙夙憫?yīng)式設(shè)計(jì)而無(wú)法正常工作。為了改善這一點(diǎn),我們可以增強(qiáng)應(yīng)用的響應(yīng)性,使其在小屏幕設(shè)備上也能輕松進(jìn)行簽名操作。

關(guān)鍵在于確保畫(huà)布及其容器能夠靈活適應(yīng)不同的屏幕尺寸。這需要我們根據(jù)瀏覽器窗口的大小來(lái)動(dòng)態(tài)調(diào)整畫(huà)布的尺寸。

具體來(lái)說(shuō),我們需要做出以下調(diào)整:

  • 為 .signature-container 設(shè)置一個(gè)靈活的寬度,比如占滿90%的可用空間,并設(shè)定一個(gè)最大寬度限制,比如600像素。
  • 將畫(huà)布元素的寬度設(shè)置為 width: 100%,高度設(shè)置為 height: auto,以實(shí)現(xiàn)響應(yīng)式效果。

在 JavaScript 代碼中,我們需要執(zhí)行以下操作:

  • 創(chuàng)建一個(gè)名為 resizeCanvas 的函數(shù),用以根據(jù)其容器尺寸的變化來(lái)調(diào)整畫(huà)布的大小。
  • 在頁(yè)面加載時(shí)首先調(diào)用 resizeCanvas 函數(shù),并在窗口大小發(fā)生變化時(shí)添加一個(gè)事件監(jiān)聽(tīng)器,確保畫(huà)布能夠隨著窗口大小的變化而動(dòng)態(tài)調(diào)整尺寸。

按照上述說(shuō)明,我們需要更新 styles.css 文件,以實(shí)現(xiàn)所需的樣式調(diào)整。

body {
  display: flex;
  justify - content: center;
  align - items: center;
  height: 100vh;
  background - color: #f0f0f0;
  margin: 0;
}

.signature - container {
  display: flex;
  flex - direction: column;
  align - items: center;
  width: 90 % ;
  max - width: 600px;
}

canvas {
  border: 1px solid#000;
  background - color: #fff;
  width: 100 % ;
  height: auto;
}

.controls {
  margin - top: 10px;
  display: flex;
  gap: 10px;
}

button,
select {
  padding: 5px 10px;
  cursor: pointer;
}

這是在添加之后 script.js 的樣子:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;
  var strokeStyle = 'pen';

  function resizeCanvas() {
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    ctx.lineWidth = strokeStyle === 'pen' ? 2 : 5;
    ctx.lineCap = 'round';
  }

  function startDrawing(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
  }

  function draw(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
      ctx.stroke();
    }
  }

  function stopDrawing() {
    drawing = false;
  }

  // 鼠標(biāo)事件
  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 觸摸事件
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);
  canvas.addEventListener('touchcancel', stopDrawing);

  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  document.getElementById('stroke-style').addEventListener('change',
  function(e) {
    strokeStyle = e.target.value;
    ctx.lineWidth = strokeStyle === 'pen' ? 2 : 5;
  });

  // 初始畫(huà)布設(shè)置
  resizeCanvas();
  window.addEventListener('resize', resizeCanvas);
});

你可能會(huì)觀察到,當(dāng)改變?yōu)g覽器窗口大小時(shí),畫(huà)布上的簽名會(huì)消失,這是因?yàn)檎{(diào)整畫(huà)布尺寸會(huì)自動(dòng)清除其內(nèi)容。這是 <canvas> 元素的標(biāo)準(zhǔn)行為。不過(guò),我們可以通過(guò)一些技巧來(lái)避免這個(gè)問(wèn)題。

為了在縮放畫(huà)布時(shí)保持簽名的完整性,并且能夠正確地對(duì)其進(jìn)行縮放,我們需要先保存畫(huà)布上的簽名,然后在調(diào)整畫(huà)布尺寸后再重新繪制它。我們可以通過(guò) toDataURL 方法來(lái)保存畫(huà)布上的簽名。

HTMLCanvasElement.toDataURL() 方法能夠根據(jù)你指定的圖片格式,將畫(huà)布上的內(nèi)容轉(zhuǎn)換成一個(gè)數(shù)據(jù) URL。

現(xiàn)在,讓我們來(lái)看一下如何保存簽名,以便在窗口大小調(diào)整后可以將其恢復(fù)。我們需要做的調(diào)整如下:

  • 定義一個(gè) signatureData 變量來(lái)存儲(chǔ)簽名的當(dāng)前狀態(tài),以數(shù)據(jù) URL 的形式。
  • 修改 resizeCanvas 函數(shù),使其能在調(diào)整畫(huà)布大小時(shí),先保存簽名,再調(diào)整尺寸,并最終重新繪制簽名。
  • 創(chuàng)建一個(gè) Image 對(duì)象來(lái)加載保存的簽名,并在調(diào)整尺寸后的畫(huà)布上將其恢復(fù)。
  • 當(dāng)完成繪畫(huà)時(shí),使用 canvas.toDataURL() 方法更新 signatureData 變量,以便存儲(chǔ)當(dāng)前的畫(huà)布內(nèi)容。
  • 當(dāng)用戶點(diǎn)擊清除按鈕時(shí),將 signatureData 變量重置為 null,以清除保存的簽名數(shù)據(jù)。

實(shí)施了上述更改后,我們的 JavaScript 文件將如下所示:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;
  var strokeStyle = 'pen';
  var signatureData = null;

  function resizeCanvas() {
    if (signatureData) {
      var img = new Image();
      img.src = signatureData;
      img.onload = function() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        canvas.width = canvas.offsetWidth;
        canvas.height = canvas.offsetHeight;
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        setStrokeStyle();
      };
    } else {
      canvas.width = canvas.offsetWidth;
      canvas.height = canvas.offsetHeight;
      setStrokeStyle();
    }
  }

  function setStrokeStyle() {
    if (strokeStyle === 'pen') {
      ctx.lineWidth = 2;
      ctx.lineCap = 'round';
    } else if (strokeStyle === 'brush') {
      ctx.lineWidth = 5;
      ctx.lineCap = 'round';
    }
  }

  function startDrawing(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
  }

  function draw(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
      ctx.stroke();
    }
  }

  function stopDrawing() {
    drawing = false;
    signatureData = canvas.toDataURL();
  }

  // 鼠標(biāo)事件
  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 觸摸事件
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);
  canvas.addEventListener('touchcancel', stopDrawing);

  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    signatureData = null;
  });

  document.getElementById('stroke-style').addEventListener('change',
  function(e) {
    strokeStyle = e.target.value;
    setStrokeStyle();
  });

  // 初始畫(huà)布設(shè)置
  resizeCanvas();
  window.addEventListener('resize', resizeCanvas);
});

保存和導(dǎo)出

我們將進(jìn)一步增強(qiáng)功能,允許用戶將他們的簽名以 PNG 或 JPEG 格式導(dǎo)出,且這些圖片將擁有白色背景。為此,我們將執(zhí)行以下步驟:

  • 在 HTML 代碼中增加兩個(gè)按鈕,分別用于將簽名導(dǎo)出為 PNG 和 JPEG 文件。
  • 開(kāi)發(fā)一個(gè)名為 exportCanvas 的函數(shù),該函數(shù)負(fù)責(zé)將畫(huà)布內(nèi)容(包括白色背景)導(dǎo)出。這一過(guò)程涉及到創(chuàng)建一個(gè)新畫(huà)布,將白色填充為背景色,然后將當(dāng)前簽名繪制上去,最后將其保存為 PNG 或 JPEG 文件。

以下是經(jīng)過(guò)這些更改后的 HTML 代碼示例:

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
      JavaScript簽名板
    </title>
    <link rel="stylesheet" href="styles.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >
  </head>
  
  <body>
    <div class="signature-container">
      <canvas id="signature-pad" width="400" height="200">
      </canvas>
      <div class="controls">
        <button id="clear">
          清除
        </button>
        <button id="export-png">
          導(dǎo)出png格式
        </button>
        <button id="export-jpeg">
          導(dǎo)出jpeg格式
        </button>
      </div>
    </div>
    <script src="script.js">
    </script>
  </body>

</html>

這是在添加之后 JavaScript 文件的樣子:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var ctx = canvas.getContext('2d');
  var drawing = false;
  var strokeStyle = 'pen';
  var signatureData = null;

  function resizeCanvas() {
    if (signatureData) {
      var img = new Image();
      img.src = signatureData;
      img.onload = function() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        canvas.width = canvas.offsetWidth;
        canvas.height = canvas.offsetHeight;
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        setStrokeStyle();
      };
    } else {
      canvas.width = canvas.offsetWidth;
      canvas.height = canvas.offsetHeight;
      setStrokeStyle();
    }
  }

  function setStrokeStyle() {
    if (strokeStyle === 'pen') {
      ctx.lineWidth = 2;
      ctx.lineCap = 'round';
    } else if (strokeStyle === 'brush') {
      ctx.lineWidth = 5;
      ctx.lineCap = 'round';
    }
  }

  function startDrawing(e) {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
  }

  function draw(e) {
    if (drawing) {
      ctx.lineTo(e.offsetX || e.touches[0].clientX - canvas.offsetLeft, e.offsetY || e.touches[0].clientY - canvas.offsetTop);
      ctx.stroke();
    }
  }

  function stopDrawing() {
    drawing = false;
    signatureData = canvas.toDataURL();
  }

  function exportCanvas(format) {
    var exportCanvas = document.createElement('canvas');
    exportCanvas.width = canvas.width;
    exportCanvas.height = canvas.height;
    var exportCtx = exportCanvas.getContext('2d');

    // 用白色填充背景
    exportCtx.fillStyle = '#fff';
    exportCtx.fillRect(0, 0, exportCanvas.width, exportCanvas.height);

    // 繪制簽名
    exportCtx.drawImage(canvas, 0, 0);

    // 導(dǎo)出畫(huà)布
    var dataURL = exportCanvas.toDataURL(`image / $ {
      format
    }`);
    var link = document.createElement('a');
    link.href = dataURL;
    link.download = `signature.$ {
      format
    }`;
    link.click();
  }

  // 鼠標(biāo)事件
  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 觸摸事件
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);
  canvas.addEventListener('touchcancel', stopDrawing);

  document.getElementById('clear').addEventListener('click',
  function() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    signatureData = null;
  });

  document.getElementById('stroke-style').addEventListener('change',
  function(e) {
    strokeStyle = e.target.value;
    setStrokeStyle();
  });

  document.getElementById('export-png').addEventListener('click',
  function() {
    exportCanvas('png');
  });

  document.getElementById('export-jpeg').addEventListener('click',
  function() {
    exportCanvas('jpeg');
  });

  // 初始畫(huà)布設(shè)置
  resizeCanvas();
  window.addEventListener('resize', resizeCanvas);
});

添加更多功能

通過(guò)引入外部庫(kù),我們可以簡(jiǎn)化簽名板中一些復(fù)雜功能的實(shí)現(xiàn)過(guò)程。我們將采用 signature_pad 這個(gè)庫(kù),它非常出色,能夠幫助我們輕松地實(shí)現(xiàn)之前討論過(guò)的眾多功能,并且它還能讓我們生成更加流暢的簽名效果。

首先,我們需要在 HTML 文檔中引入 signature_pad 庫(kù):

<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js"></script>

然后添加必要的按鈕。這是最終 HTML 的樣子:

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
      JavaScript簽名板
    </title>
    <link rel="stylesheet" href="styles.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >
    <script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js">
    </script>
  </head>
  
  <body>
    <div class="signature-container">
      <canvas id="signature-pad" width="600" height="400">
      </canvas>
      <div class="controls">
        <button id="undo">
          撤銷
        </button>
        <button id="redo">
          重做
        </button>
        <button id="clear">
          清除
        </button>
        <button id="save-png">
          導(dǎo)出png格式
        </button>
        <button id="save-jpeg">
          導(dǎo)出jpeg格式
        </button>
      </div>
    </div>
    <script src="script.js">
    </script>
  </body>

</html>

更新樣式:

body {
  display: flex;
  justify - content: center;
  align - items: center;
  height: 100vh;
  background - color: #f0f0f0;
  margin: 0;
}

.signature - container {
  display: flex;
  flex - direction: column;
  align - items: center;
  width: 90 % ;
  max - width: 600px;
}

canvas {
  border: 1px solid#000;
  background - color: #fff;
  width: 100 % ;
  height: auto;
}

.controls {
  margin - top: 10px;
  display: flex;
  gap: 10px;
  flex - wrap: wrap;
}

button {
  padding: 5px 10px;
  cursor: pointer;
}

為了進(jìn)一步完善我們的簽名板功能,script.js 腳本需要進(jìn)行以下更新:

  • 實(shí)現(xiàn)兩個(gè)棧,undoStack 和 redoStack,分別用來(lái)追蹤撤銷和重做的歷史狀態(tài)。
  • 創(chuàng)建一個(gè) saveState 函數(shù),該函數(shù)負(fù)責(zé)將簽名板的當(dāng)前狀態(tài)存儲(chǔ)到撤銷棧中。
  • 定義 undo 和 redo 函數(shù),分別用于執(zhí)行撤銷和重做的操作。

經(jīng)過(guò)這些修改,script.js 腳本將具備完整的撤銷和重做功能。以下是更新后的 script.js 腳本:

document.addEventListener('DOMContentLoaded',
function() {
  var canvas = document.getElementById('signature-pad');
  var signaturePad = new SignaturePad(canvas);
  var undoStack = [];
  var redoStack = [];
  function saveState() {
    undoStack.push(deepCopy(signaturePad.toData()));
    redoStack = [];
  }
  function undo() {
    if (undoStack.length > 0) {
      redoStack.push(deepCopy(signaturePad.toData()));
      undoStack.pop();
      signaturePad.clear();
      if (undoStack.length) {
        var lastStroke = undoStack[undoStack.length - 1];
        signaturePad.fromData(lastStroke, {
          clear: false
        });
      }
    }
  }
  function redo() {
    if (redoStack.length > 0) {
      undoStack.push(deepCopy(signaturePad.toData()));
      var nextState = redoStack.pop();
      signaturePad.clear();
      if (nextState.length) {
        signaturePad.fromData(nextState);
      }
    }
  }
  document.getElementById('undo').addEventListener('click', undo);
  document.getElementById('redo').addEventListener('click', redo);
  document.getElementById('clear').addEventListener('click',
  function() {
    signaturePad.clear();
    undoStack = [];
    redoStack = [];
  });
  document.getElementById('save-png').addEventListener('click',
  function() {
    if (!signaturePad.isEmpty()) {
      var dataURL = signaturePad.toDataURL('image/png');
      var link = document.createElement('a');
      link.href = dataURL;
      link.download = 'signature.png';
      link.click();
    }
  });
  document.getElementById('save-jpeg').addEventListener('click',
  function() {
    if (!signaturePad.isEmpty()) {
      var dataURL = signaturePad.toDataURL('image/jpeg');
      var link = document.createElement('a');
      link.href = dataURL;
      link.download = 'signature.jpeg';
      link.click();
    }
  });
  // 繪圖結(jié)束時(shí)保存狀態(tài)
  signaturePad.addEventListener("endStroke", () = >{
    console.log("Signature end");
    saveState();
  });
  // 初始畫(huà)布設(shè)置
  function resizeCanvas() {
    var ratio = Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
    signaturePad.clear(); // 否則 isEmpty() 可能會(huì)返回錯(cuò)誤值
    if (undoStack.length > 0) {
      signaturePad.fromData(undoStack[undoStack.length - 1]);
    }
  }
  function deepCopy(data) {
    return JSON.parse(JSON.stringify(data));
  }
  window.addEventListener('resize', resizeCanvas);
  resizeCanvas();
});

應(yīng)用場(chǎng)景介紹:JavaScript 簽名板

掌握上述代碼能夠讓我們應(yīng)對(duì)多種實(shí)際應(yīng)用場(chǎng)景。

電子簽名在網(wǎng)頁(yè)表單中的應(yīng)用

通過(guò)在網(wǎng)頁(yè)表單中集成簽名板,用戶可以輕松地電子簽名文檔,這在處理合同、協(xié)議和同意書(shū)時(shí)尤為重要。在法律、房地產(chǎn)、醫(yī)療和金融等行業(yè)內(nèi),電子簽名的收集成為工作流程中不可或缺的一環(huán),有效減少了紙質(zhì)文件的使用。

在線繪圖工具的集成

開(kāi)發(fā)者可以將簽名板整合到需要用戶進(jìn)行繪圖或注釋的在線應(yīng)用中。無(wú)論是協(xié)作白板、設(shè)計(jì)軟件還是交互式反饋環(huán)節(jié),簽名板都能發(fā)揮重要作用。例如,在在線教育平臺(tái)上,學(xué)生可以利用簽名板在直播課程中繪制圖表或解答數(shù)學(xué)題目,教師也能即時(shí)給予反饋。

網(wǎng)絡(luò)文檔和圖像編輯器中的注釋功能

簽名板可作為網(wǎng)絡(luò)文檔和圖像編輯器中的注釋工具,讓用戶能夠直接在文檔或圖像上添加手寫(xiě)注釋、評(píng)論或草圖。

訪客登記管理

在訪客登記管理中,簽名板可用于記錄訪客的數(shù)字化簽到和簽出信息,這在企業(yè)管理和活動(dòng)策劃中非常實(shí)用。

總結(jié)

在本篇文章中,我們探索了如何使用純 JavaScript 來(lái)創(chuàng)建一個(gè)功能豐富的簽名板,包括觸摸支持、筆觸樣式選擇、響應(yīng)式設(shè)計(jì)以及導(dǎo)出功能。我們學(xué)習(xí)了如何利用 HTML 的 <canvas> 元素來(lái)捕捉用戶的手寫(xiě)簽名,并通過(guò) JavaScript 為簽名板添加了撤銷、重做等高級(jí)功能。此外,我們還通過(guò)引入 signature_pad 庫(kù)進(jìn)一步簡(jiǎn)化了開(kāi)發(fā)過(guò)程,使得實(shí)現(xiàn)平滑的簽名體驗(yàn)變得更加容易。

通過(guò)這些技術(shù),我們不僅能夠創(chuàng)建一個(gè)基本的簽名板,還能夠?yàn)槠涮砑痈鞣N實(shí)用的功能,使其適應(yīng)不同的應(yīng)用場(chǎng)景。無(wú)論是在網(wǎng)頁(yè)表單中收集電子簽名,還是在在線教育平臺(tái)中作為繪圖工具,或是作為網(wǎng)絡(luò)文檔編輯器中的注釋工具,JavaScript 簽名板都能提供出色的用戶體驗(yàn)。

此外,我們還討論了如何將簽名數(shù)據(jù)導(dǎo)出為不同格式的圖片,這對(duì)于保存簽名或?qū)⑵浒l(fā)送到服務(wù)器進(jìn)行進(jìn)一步處理非常有用。例如,簽名驗(yàn)證功能可以提高在線交易的安全性,確保用戶的身份得到確認(rèn)。

總的來(lái)說(shuō),JavaScript 簽名板的靈活性和可定制性使其成為現(xiàn)代網(wǎng)絡(luò)應(yīng)用的理想選擇。隨著技術(shù)的不斷進(jìn)步,我們可以預(yù)見(jiàn),JavaScript 簽名板將在未來(lái)的網(wǎng)絡(luò)應(yīng)用中扮演越來(lái)越重要的角色,為用戶提供更加豐富和便捷的手寫(xiě)簽名體驗(yàn)。通過(guò)本文的指導(dǎo),開(kāi)發(fā)者可以輕松地在自己的項(xiàng)目中實(shí)現(xiàn)這些功能,無(wú)論是簡(jiǎn)單的簽名收集還是復(fù)雜的交互式繪圖和注釋,都能輕松應(yīng)對(duì)。這種技術(shù)的應(yīng)用不僅提高了工作效率,也為用戶帶來(lái)了更加直觀和個(gè)性化的交互方式。

以上就是JavaScript實(shí)現(xiàn)簽名板功能的詳細(xì)內(nèi)容,更多關(guān)于JavaScript簽名板的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用webpack和rollup打包組件庫(kù)的方法

    使用webpack和rollup打包組件庫(kù)的方法

    這篇文章主要介紹了使用webpack和rollup打包組件庫(kù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 淺談JavaScript 聲明提升

    淺談JavaScript 聲明提升

    這篇文章主要介紹了JavaScript 聲明提升的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下
    2020-09-09
  • 20個(gè)常見(jiàn)的JavaScript數(shù)組操作總結(jié)

    20個(gè)常見(jiàn)的JavaScript數(shù)組操作總結(jié)

    JavaScript中的Array對(duì)象與其他編程語(yǔ)言中的數(shù)組一樣,是一組數(shù)據(jù)的集合。在JavaScript中,數(shù)組里面的數(shù)據(jù)可以是不同類型的,并具有用于執(zhí)行數(shù)組常見(jiàn)操作的方法,本文整理了一些常用的,需要的可以參考一下
    2022-09-09
  • 基于vue實(shí)現(xiàn)可搜索下拉框定制組件

    基于vue實(shí)現(xiàn)可搜索下拉框定制組件

    這篇文章主要為大家詳細(xì)介紹了基于vue實(shí)現(xiàn)可搜索下拉框定制組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • 原生JS實(shí)現(xiàn)音樂(lè)播放器

    原生JS實(shí)現(xiàn)音樂(lè)播放器

    這篇文章主要為大家詳細(xì)介紹了原生JS音樂(lè)播放器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • JavaScript 原型繼承之構(gòu)造函數(shù)繼承

    JavaScript 原型繼承之構(gòu)造函數(shù)繼承

    JavaScript 是基于原型的面向?qū)ο笳Z(yǔ)言。也就是說(shuō),每個(gè)實(shí)例對(duì)象都具有一個(gè)原型。對(duì)象從該原型中繼承屬性和方法。這一篇將具體說(shuō)說(shuō)構(gòu)造函數(shù)的繼承。
    2011-08-08
  • 基于Bootstrap模態(tài)對(duì)話框只加載一次 remote 數(shù)據(jù)的解決方法

    基于Bootstrap模態(tài)對(duì)話框只加載一次 remote 數(shù)據(jù)的解決方法

    下面小編就為大家?guī)?lái)一篇基于Bootstrap模態(tài)對(duì)話框只加載一次 remote 數(shù)據(jù)的解決方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • 用Js實(shí)現(xiàn)的動(dòng)態(tài)增加表格示例自己寫(xiě)的

    用Js實(shí)現(xiàn)的動(dòng)態(tài)增加表格示例自己寫(xiě)的

    動(dòng)態(tài)增加表格的方法有很多,但大多說(shuō)實(shí)現(xiàn)起來(lái)比較繁瑣,本文的這個(gè)示例是作者自己手寫(xiě)的,經(jīng)測(cè)試效果還不錯(cuò),但唯獨(dú)不兼容FF,感興趣的朋友可以參考下
    2013-10-10
  • web前端開(kāi)發(fā)upload上傳頭像js示例代碼

    web前端開(kāi)發(fā)upload上傳頭像js示例代碼

    這篇文章主要為大家詳細(xì)介紹了web前端開(kāi)發(fā)upload上傳頭像js示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 微信JSSDK調(diào)用微信掃一掃功能的方法

    微信JSSDK調(diào)用微信掃一掃功能的方法

    這篇文章主要為大家詳細(xì)介紹了微信JSSDK調(diào)用微信掃一掃功能的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07

最新評(píng)論