<!DOCTYPE html><html> <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>頭像大作戰</title> <style> </style>
</head> <body> <header><h1>頭像大作戰</h1></header> <article> <section> </section> </article> <footer> <script> </script> </footer> </body></html>然後,我們要做到可以預覽用戶選擇的頭像,我們先來給網頁加上一個文件選擇控制項,和圖片標籤,標籤上加 上 id,以便後面通過 Javascript 控制。
<p> <input type="file" name="" id="upload" accept="image/*"> </p> <p id="avatar"> <img src="" alt="" id="avatar_img"> </p>接著,我們來寫預覽圖片的代碼,藉助於 URL.createObjectURL 來加載圖片。
function loadImage(){ var imgUrl = window.URL.createObjectURL(document.getElementById('upload').files[0]); document.getElementById('avatar_img').src = imgUrl;}當用戶選擇圖片時,就要載入圖片,所以我們把 loadImage 綁定在 upload 的 onchange 事件裡面:
<input type="file" name="" id="upload" accept="image/*" onchange="loadImage()">接著,我們要頭像疊加的效果,我已經事先從騰訊的網站把素材爬下來了。可以在這兒下載:https://github.com/szisa/avatar_maker/tree/master/img
我們把圖片都存放在 img 目錄。總共 4 種外框,分別命名為 head0.png, head1.png, head2.png, head3.png,另外,還抓多一張 bg.png 做背景。
我們先用 head0.png 做樣式。在頭像預覽的地方加入一個 img 標籤,用來顯示外框圖片。
<p id="avatar"> <img src="./img/head0.png" alt="0" id="avatar_template"> <img src="" alt="" id="avatar_img"></p>這不是我們要的,外框太大,而且也沒重疊在一起,這時就要靠 CSS 大法來幫忙了。在 style 加入下面代碼:
body { background: #000 url(./img/bg.png) no-repeat center; text-align: center; } #avatar { width: 300px; height: 300px; position: relative; margin: auto; overflow: hidden; }#avatar img { width: 100%; } #avatar_template { position: absolute; top: 0; right: 0; }ok,到這裡來有幾個知識點重點講解一下,只想趕快做出來的可以略過這部分。
margin: auto;
HTML 元素中,按照默認樣式,可以被分為內聯元素和塊級元素。內聯元素可以被 text-align 居 中,而塊級元素,則要靠外邊距的的補齊來實現左右居中。當設置塊級元素的 margin 為 auto 時,瀏覽器就會自動計算左右外邊距,將剩餘空間平分到左右外邊 距,這樣就實現了左右居中。
position: absolute;
為了實現把外框覆蓋在頭像上,我們需要讓外框圖片脫離正常文檔流,而絕對定位可以幫我們實現這一 點。絕對定位的定位原點則是通過包含塊來決定的。我們需要讓外框圖片精準對齊 #avatar 的左上角,那麼 就需要讓 #avatar 成為絕對定位的包含塊,而只要給 #avatar 設置 position 且值不等於 static,他 就會自動成為包含塊。當如果設置 fixed 或 absolute,則會讓標籤脫離文檔流,影響樣式,因此,我 們就給 #avatar 設置了 position: relative。
現在就要來做保存圖片的代碼了,我們沒辦法直接把標籤變成圖片。但是,我們可以通過 canvas,依次繪製兩張圖片,就可以實現圖片的疊加了!
首先,我們要給 HTML 裡加入一個 canvas 標籤:
<p> <canvas width="300" height="300" id="cvs"></canvas></p>然後,就要開始用圖片繪製了。定義一個函數 drawImage,傳入圖片地址,繪製圖片到畫布:
function drawImage(img) { // 取得 Canvas var cvs = document.getElementById('cvs'); var size = 300; // 設定 canvas 寬高 cvs.width = size; cvs.height = size; // 取得 2d 畫布 var ctx = cvs.getContext('2d'); // 新建圖片對象,加載圖片 var image = new Image; image.src = img; image.onload = function() { // 加載完成後繪製 image 到(0,0)坐標,長寬重設為 size ctx.drawImage(image, 0, 0, size, size); }}然後,當用戶選擇圖片後,我們就要把他畫上去,所以在 loadImage 最後要加上 drawImage :
function loadImage() { var imgUrl = window.URL.createObjectURL(document.getElementById('upload').files[0]); document.getElementById('avatar_img').src = imgUrl; drawImage(imgUrl)}接著,我們還得把外框繪製上去,因為後面還要提供更換外框的功能,把外框的地址作為參數傳入到 drawImage :
function drawImage(img, frame) { var cvs = document.getElementById('cvs'); var size = 300; cvs.width = size; cvs.height = size; var ctx = cvs.getContext('2d'); var image = new Image; image.src = img; image.onload = function() { ctx.drawImage(image, 0, 0, size, size); image = new Image; image.src = frame; image.onload = function() { ctx.drawImage(image, 0, 0, size, size); } }}function loadImage() { // 載入圖片生成 blob 連結 var imgUrl = window.URL.createObjectURL(document.getElementById('upload').files[0]); document.getElementById('avatar_img').src = imgUrl; // 再傳入 avatar_template 的圖片地址 drawImage(imgUrl, document.getElementById('avatar_template').src)}這個 canvas 只是用來保存,那麼可以把他隱藏起來,加上 CSS 樣式 style="display:none" 在 canvas 上。
接著,我們來做保存的部分。canvas 有一個方法 toDataURL 用來將內容生成成圖片的 DataURL。那麼我們只 要把這個 DataURL 作為 a 標籤的地址,利用 a 標籤的 download 屬性,模擬點擊即可實現圖片下載了。具體代碼:
function downloadImage() { var canvas = document.getElementById('cvs'); var image = canvas.toDataURL("image/png") var save_link = document.createElement('a'); save_link.href = image; save_link.download ='avatar.png'; var clickevent = document.createEvent('MouseEvents'); clickevent.initEvent('click', true, false); save_link.dispatchEvent(clickevent); }我們創建一個下載按鈕用來下載圖片,並把 downloadImage 綁定在按鈕上
<p> <button id="download" onclick="downloadImage()">下載</button></p>選擇頭像,點擊下載,瀏覽器就會下載圖片了,最後生成的圖片:
你學會了嗎?你滿足了嗎?不!我不滿足,我還要做到可以選擇不同的外框。那麼,讓我們繼續~
我們可以通過兩個按鈕,前後切換頭像邊框。那麼,先加上兩個按鈕,就放在下載按鈕的左右兩側:
<button id="prev">上一個</button><button id="download" onclick="downloadImage()">下載</button><button id="next">下一個</button>上下切換邊框很簡單,只要計算邊框的地址,然後更新 avatar_template 的圖片地址就行了。為了節省解析 當前切換到哪張邊框的功夫,我們把當前邊框的 Index 存放在圖片的 alt 屬性。
function prevTemplate() { var current = parseInt(document.getElementById('avatar_template').alt); current = (current - 1 + 4) % 4; document.getElementById('avatar_template').src = 'img/head' + current + '.png'; document.getElementById('avatar_template').alt = current; loadImage();}
function nextTemplate() { var current = parseInt(document.getElementById('avatar_template').alt); current = (current + 1) % 4; document.getElementById('avatar_template').src = 'img/head' + current + '.png'; document.getElementById('avatar_template').alt = current; loadImage();}接著,把函數綁定到按鈕的 onclick 事件上,就大功告成了。
<button id="prev" onclick="prevTemplate()">上一個</button><button id="download" onclick="downloadImage()">下載</button><button id="next" onclick="nextTemplate()">下一個</button>最後成品(http://avatar.m.sxisa.com/sample.html):
完整代碼可以來這看哦:https://github.com/szisa/avatar_maker/blob/master/sample.html
認真跟著做到這一步的同學們都很棒哦~細心的同學可能會發現,預覽的部分似乎不要也可以,直接使用 canvas 作為預覽不就可以了?事實上,確實是這樣的。不過,加多了一個 HTML 的預覽,是為了別的頭像生成 器去特地保留的!
10月來了,12月還會遠嗎~如果把邊框換成聖誕帽,是不是就可以用來生成聖誕帽頭像了呢!但是聖誕 帽可不會固定在一個位置,這就需要給用戶自行調整的機會,所以,我們就需要通過 HTML 預覽的部分提供給 用戶交互,因為 canvas 幾乎沒辦法做交互。那麼到底要怎麼實現呢?且聽下回分解!
(點擊 閱讀原文 查看原始碼,給個 star 吧~👇)