基于HTML5+JS實(shí)現(xiàn)本地圖片裁剪并上傳功能
最近做了一個(gè)項(xiàng)目,這個(gè)項(xiàng)目中需要實(shí)現(xiàn)的一個(gè)功能是:用戶自定義頭像(用戶在本地選擇一張圖片,在本地將圖片裁剪成滿足系統(tǒng)要求尺寸的大?。?。這個(gè)功能的需求是:頭像最初剪切為一個(gè)正方形。如果選擇的圖片小于規(guī)定的頭像要求尺寸,那么這整張圖片都會(huì)作為頭像。如果大于規(guī)定的尺寸,那么用戶可以選擇要裁剪的區(qū)域。用戶點(diǎn)擊確定按鈕,就將裁剪得到的圖片數(shù)據(jù)發(fā)送到服務(wù)器,在后端將圖片數(shù)據(jù)保存成一個(gè)文件。
要完成上述功能,涉及到的知識(shí)有:ajax,canvas和html5中的files接口。我將實(shí)現(xiàn)這個(gè)功能的代碼封裝到了4個(gè)模塊中,分別是ajax.js,preview.js,shear.js和customerImg.js。
ajax.js:用于發(fā)送ajax請(qǐng)求。
preview.js:用于圖片預(yù)覽
shear.js:用于裁剪圖片
customer.js:自定義頭像。在這個(gè)模塊中藥引入ajax.js,preview.js和shear.js
我使用webpack進(jìn)行打包。我還使用了jquery和jquery-ui。
我從這個(gè)項(xiàng)目中抽離出了這個(gè)功能。下面是這個(gè)功能的詳細(xì)代碼。
1.HTML代碼
<div class="m-warp" id="warp">
<div class="item">
<input type="file" name="img" id="img" hidden>
<label for="img">選擇圖片</label>
</div>
<div class="item clearfix">
<div class="col col-1">
<div class="preview" id="preview">
<div class="mask"></div>
<canvas class="cvsMove" id="cvsMove"></canvas>
</div>
</div>
<div class="thum col-2 col">
<p>預(yù)覽</p>
<img src="" id="thum">
<p class="f-text-l f-marTop-20">
<button class="shear" id="submit">確定</button>
</p>
</div>
</div>
</div>
2.CSS代碼
.clearfix:after{
content: "";
display: block;
clear: both;
height: 0;
overflow: hidden;
visibility: hidden;
}
img{
vertical-align: middle;
max-width:100%
}
.m-warp{
width: 800px;
}
.item{
margin-top: 20px;
}
.col{
float: left;
}
.col-1{
position: relative;
width: 450px;
height: 450px;
outline: 1px solid #333;
}
.preview{
display: inline-block;
}
.col-2{
width: 300px;
margin-left: 50px;
}
label{
display: block;
text-align: center;
width: 100px;
font-size: 16px;
color: #fff;
background-color: #888888;
height: 30px;
line-height: 30px;
}
.mask{
position: absolute;
z-index: 1;
top:0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0,0,0,.4);
}
.cvsMove{
position: absolute;
z-index: 2;
outline: 2px dotted #333;
cursor: move;
display: none;
}
有了css和html的運(yùn)行結(jié)果如下:

3.js代碼
customerImg.js
var $ = require('jquery');
var ajax = require('./ajax.js');
var preview = require('./preview.js');
var shear = require('./shear.js');
/**
* 自定義頭像
* @constructor
*/
function CustomerImg() {
this.isSupport = null;
this.previewBox = null;
this.warp = null;
}
/**
* 入口
* @param warp 操作區(qū)域 jquery節(jié)點(diǎn)
*/
CustomerImg.prototype.start = function (warp) {
var info,me,warpBox;
me = this;
this.isSupport = this.__isSupport();
if(!this.isSupport) {
info = $('<p>你的瀏覽器不支持自定義頭像,可更換高版本的瀏覽器自定義頭像</p>');
$('body').html(info);
return this;
}
//判斷操作區(qū)域示范存在
if(warp && warp.length > 0){
this.warp = warp;
}else{
return this;
}
//預(yù)覽
preview.start(warp,shear.start.bind(shear,warp));
this.previewBox = warp.find('#preview');
//確定
warp
.find('#submit')
.unbind('click')
.on('click',me.__submit.bind(me));
};
/**
* 提交
* @private
*/
CustomerImg.prototype.__submit = function () {
var cvsMove,data,fd;
cvsMove = this.previewBox.find('#cvsMove');
data = cvsMove[0].toDataURL('image/jpg',1);
fd = {
'customerImg':data
};
ajax.upload(fd);
};
/**
* 判斷是否支持自定義頭像
* @returns {boolean}
* @private
*/
CustomerImg.prototype.__isSupport = function () {
var canvas,context;
canvas= document.createElement('canvas');
if(typeof FileReader === 'function'&& canvas.getContext && canvas.toDataURL){
return true;
}else{
return false;
}
};
var customerImg = new CustomerImg();
module.exports = customerImg;
preview.js
/**
* Created by star on 2017/3/7.
*/
var $ = require('jquery');
/**
* 預(yù)覽類
* @constructor
*/
function Preview() {
this.boxElem = null;
this.callback = null;
this.type = null;
}
/**
* 入口
* @param boxElem 操作區(qū)域
* @param callback 預(yù)覽結(jié)束的回調(diào)函數(shù)
*/
Preview.prototype.start = function (boxElem,callback) {
var chooseFile,me;
me = this;
if(! boxElem || boxElem.length <= 0) return this;
this.boxElem = boxElem;
if(typeof callback === 'function'){
this.callback = callback;
}
if(this.__isSupport()){
chooseFile = boxElem.find('input[type="file"]');
chooseFile
.on('change',me.fileChange.bind(me))
}
};
/**
* 選擇圖片的事件處理程序
* @param event
*/
Preview.prototype.fileChange = function (event) {
var target,reader,file,me,type;
target = event.target;
me = this;
file = target.files[0];
type = file.type;
this.type = type;
if(type !== 'image/png' && type !== 'image/jpg' && type !== 'image/jpeg'){
alert('文件格式不正確');
return this;
}
reader = new FileReader();
if(file){
reader.readAsDataURL(file);
}
reader.onload = function () {
me.show(reader);
}
};
/**
* 顯示從本地選擇的圖片
* @param reader fileReader對(duì)象
*/
Preview.prototype.show = function (reader) {
var preView,img,me;
preView = this.boxElem.find('#preview');
img = preView.find('#preImg');
me = this;
if(img.length <= 0){
preView.append($('<img id="preImg">'));
}
img = preView.find('#preImg');
//確保圖片加載完成后再執(zhí)行回調(diào)
img.on('load',function () {
if(me.callback){
me.callback(me.type);
}
});
img.attr('src',reader.result);
};
/**
* 是否支持預(yù)覽
* @returns {boolean}
* @private
*/
Preview.prototype.__isSupport = function () {
return typeof FileReader === 'function';
};
var preview = new Preview();
module.exports = preview;
shear.js
var $ = require('jquery');
//由于要使用jquery-ui,所以將$暴露到window上。
window.$ = $;
require('./jquery-ui.min.js');
/**
* 切割
* @constructor
*/
function Shear() {
this.previewBox = null;
this.cvsMove = null;
this.maxW = 200;
this.maxH = 200;
this.thum = null;
this.fileType = 'image/jpeg';
}
/**
* 入口
* @param previewBox 預(yù)覽元素的父元素
* @param fileType 裁剪的圖片的類型 如:'image/jpg'
* @returns {Shear}
*/
Shear.prototype.start = function (previewBox,fileType) {
if(!arguments.length) return this;
var me = this;
this.previewBox = previewBox;
if(fileType){
this.fileType = fileType;
}
this.thum = this.previewBox.find('#thum');
this.cvsMove = this.previewBox.find('#cvsMove');
this.showCanvas();
return this;
};
/**
* 顯示出canvas
*/
Shear.prototype.showCanvas = function () {
var preImg,h,w,me,cvsH,cvsW,rateH,rateW,naturalH,naturalW,preview;
me = this;
preImg = this.previewBox.find('#preImg');
preview = this.previewBox.find('#preview');
naturalH = preImg[0].naturalHeight;
naturalW = preImg[0].naturalWidth;
//將canvas顯示出來(lái)
this.cvsMove.show();
//將canvas置于(0,0)
this.cvsMove
.css({
"left":'0',
'top':'0'
});
h = preImg.height();
w = preImg.width();
//規(guī)定裁剪出的圖片尺寸為200px*200px
//要保證裁剪的圖片不變形
if(h < this.maxH || w < this.maxW){
this.cvsMove[0].width = cvsW = Math.min(h,w);
this.cvsMove[0].height = cvsH = Math.min(h,w);
}else{
this.cvsMove[0].width= cvsW = this.maxW;
this.cvsMove[0].height= cvsH = this.maxH;
}
rateH = h/naturalH;
rateW = w/naturalW;
this.__drawImg(preImg,0,0,cvsW/rateW,cvsH/rateH,0,0,cvsW,cvsH);
//使用jquery-ui中的功能使canvas可以移動(dòng)
this.cvsMove.draggable(
{
containment: "parent",
drag:function (event,ui) {
var left,top;
left = ui.position.left;
top = ui.position.top;
//canvas每次移動(dòng)都有從新繪制圖案
me.__drawImg(preImg,left/rateW,top/rateH,cvsW/rateW,cvsH/rateH,0,0,cvsW,cvsH);
}
}
)
};
/**
* 在canvas上顯示圖片
* @param myImg 要顯示的圖片節(jié)點(diǎn)
* @param sx 圖片的起點(diǎn)在原圖片上的x坐標(biāo)
* @param sy 圖片的起點(diǎn)在原圖上的y坐標(biāo)
* @param sW 在原圖上的寬度
* @param sH 在原圖上的高度
* @param dx 起點(diǎn)在canvas上的x坐標(biāo)
* @param dy 起點(diǎn)在canvas上的y坐標(biāo)
* @param dW 在canvas上的寬度
* @param dH 在canvas上的高度
* @private
*/
Shear.prototype.__drawImg = function (myImg,sx,sy,sW,sH,dx,dy,dW,dH) {
var cxt,thum,me;
me = this;
cxt = this.cvsMove[0].getContext('2d');
cxt.drawImage(myImg[0],sx,sy,sW,sH,dx,dy,dW,dH);
thum = this.thum;
//將canvas上的圖案顯示到右側(cè)
thum
.attr('src',this.cvsMove[0].toDataURL(me.fileType,1))
.width(this.maxW)
.height(this.maxH)
};
var shear = new Shear();
module.exports = shear;
ajax.js
var $ = require('jquery');
function Ajax() {
}
/**
* 上傳圖片數(shù)據(jù)
*/
Ajax.prototype.upload = function (data) {
$.ajax({
type:'POST',
data:data,
dataType:'json',
url:'/test/PHP/upload.php',
success:function (result) {
if(result.status){
location.reload();
}else{
alert(result.msg);
}
}
});
};
var ajax = new Ajax();
module.exports = ajax;
最后在另一個(gè)文件中,調(diào)用customerImg對(duì)象的start方法
var $ = require('jquery');
var customerImg =require('./customerImg.js');
customerImg.start($('#warp'));
webpack的配置文件如下:
var webpack = require('webpack');
module.exports = {
entry:{
'customerImg':'./js/test.js',
'jQuery':['jquery']
},
output:{
filename:'[name].js',
library:'jQuery',
libraryTarget:'umd'
},
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name:'jQuery',
filename:'jquery.js'
})
]
};
效果:

4.php代碼
if(!empty($_POST) && isset($_POST['customerImg'])){
$img = $_POST['customerImg'];
$imgdata = explode(',', $img);
$uniName = md5 ( uniqid ( microtime ( true ), true ) );
$a = file_put_contents('./../uploads/'.$uniName.'.jpg', base64_decode($imgdata[1]));
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于原生JS實(shí)現(xiàn)圖片裁剪
- js+jquery實(shí)現(xiàn)圖片裁剪功能
- php+js實(shí)現(xiàn)圖片的上傳、裁剪、預(yù)覽、提交示例
- Cropper.js 實(shí)現(xiàn)裁剪圖片并上傳(PC端)
- 使用ImageMagick進(jìn)行圖片縮放、合成與裁剪(js+python)
- 使用JavaScript+canvas實(shí)現(xiàn)圖片裁剪
- vue-cli結(jié)合Element-ui基于cropper.js封裝vue實(shí)現(xiàn)圖片裁剪組件功能
- Nodejs下使用gm圓形裁剪并合成圖片的示例
- cropper js基于vue的圖片裁剪上傳功能的實(shí)現(xiàn)代碼
- cropperjs實(shí)現(xiàn)裁剪圖片功能
相關(guān)文章
詳解JavaScript中Arguments對(duì)象用途
本文主要介紹了詳解JavaScript中Arguments對(duì)象用途,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
使用openSpeDiv方法實(shí)現(xiàn)Ecshop登錄彈窗框效果
在ECSHOP的目錄/JS/common.js中有一個(gè)openSpeDiv方法是實(shí)現(xiàn)ECSHOP的彈窗效果的。接下來(lái)通過(guò)本文給大家分享使用openSpeDiv方法實(shí)現(xiàn)Ecshop登錄彈窗框效果,需要的朋友參考下2017-03-03
JavaScript兼容性總結(jié)之獲取非行間樣式案例
這篇文章主要介紹了JavaScript兼容性總結(jié)之獲取非行間樣式的相關(guān)資料,需要的朋友可以參考下2016-08-08
JavaScript判斷用戶名和密碼不能為空的實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇JavaScript判斷用戶名和密碼不能為空的實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧2016-05-05
微信小程序?qū)崿F(xiàn)購(gòu)物車(chē)代碼實(shí)例詳解
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)購(gòu)物車(chē)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
javascript 處理HTML元素必須避免使用的一種方法
我們?cè)诰帉?xiě)前臺(tái)頁(yè)面的時(shí)候,可能經(jīng)常會(huì)用到“javascript+數(shù)據(jù)”生成頁(yè)面元素的方法,但當(dāng)我們要處理的數(shù)據(jù)量較大,導(dǎo)致頁(yè)面需要展現(xiàn)過(guò)多的控件的時(shí)候,頁(yè)面的響應(yīng)速度也會(huì)直線下降2009-07-07
javascript實(shí)現(xiàn)的時(shí)間格式加8小時(shí)功能示例
這篇文章主要介紹了javascript實(shí)現(xiàn)的時(shí)間格式加8小時(shí)功能,涉及javascript日期時(shí)間轉(zhuǎn)換與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2019-06-06

