最近做了一个项目,这个项目中需要实现的一个功能是:用户自定义头像(用户在本地选择一张图片,在本地将图片裁剪成满足系统要求尺寸的大小)。这个功能的需求是:头像最初剪切为一个正方形。如果选择的图片小于规定的头像要求尺寸,那么这整张图片都会作为头像。如果大于规定的尺寸,那么用户可以选择要裁剪的区域。用户点击确定按钮,就将裁剪得到的图片数据发送到服务器,在后端将图片数据保存成一个文件。

要完成上述功能,涉及到的知识有:ajax,canvas和html5中的files接口。我将实现这个功能的代码封装到了4个模块中,分别是ajax.js,preview.js,shear.js和customerImg.js。

ajax.js:用于发送ajax请求。

preview.js:用于图片预览

shear.js:用于裁剪图片

customer.js:自定义头像。在这个模块中药引入ajax.js,preview.js和shear.js

我使用webpack进行打包。我还使用了jquery和jquery-ui。

我从这个项目中抽离出了这个功能。下面是这个功能的详细代码。

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>预览</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:;
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:;
top:;
left:;
bottom:;
right:;
background-color: rgba(0,0,0,.4);
}
.cvsMove{
position: absolute;
z-index:;
outline: 2px dotted #333;
cursor: move;
display: none;
}

有了css和html的运行结果如下:

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 操作区域 jquery节点
*/
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;
}
//判断操作区域示范存在
if(warp && warp.length > 0){
this.warp = warp;
}else{
return this;
}
//预览
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');
/**
* 预览类
* @constructor
*/
function Preview() {
this.boxElem = null;
this.callback = null;
this.type = null;
}
/**
* 入口
* @param boxElem 操作区域
* @param callback 预览结束的回调函数
*/
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对象
*/
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');
//确保图片加载完成后再执行回调
img.on('load',function () {
if(me.callback){
me.callback(me.type);
}
});
img.attr('src',reader.result);
};
/**
* 是否支持预览
* @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 预览元素的父元素
* @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显示出来
this.cvsMove.show();
//将canvas置于(0,0)
this.cvsMove
.css({
"left":'0',
'top':'0'
});
h = preImg.height();
w = preImg.width();
//规定裁剪出的图片尺寸为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可以移动
this.cvsMove.draggable(
{
containment: "parent",
drag:function (event,ui) {
var left,top;
left = ui.position.left;
top = ui.position.top;
//canvas每次移动都有从新绘制图案
me.__drawImg(preImg,left/rateW,top/rateH,cvsW/rateW,cvsH/rateH,0,0,cvsW,cvsH);
}
}
)
};
/**
* 在canvas上显示图片
* @param myImg 要显示的图片节点
* @param sx 图片的起点在原图片上的x坐标
* @param sy 图片的起点在原图上的y坐标
* @param sW 在原图上的宽度
* @param sH 在原图上的高度
* @param dx 起点在canvas上的x坐标
* @param dy 起点在canvas上的y坐标
* @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上的图案显示到右侧
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() { }
/**
* 上传图片数据
*/
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;

最后在另一个文件中,调用customerImg对象的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]));
}

HTML5本地图片裁剪并上传的更多相关文章

  1. HTML5实现图片文件异步上传

    原文:HTML5实现图片文件异步上传 利用HTML5的新特点做文件异步上传非常简单方便,本文主要展示JS部分,html结构.下面的代码并未使用第三发库,如果有参照,请注意一些未展现出来的代码片段.我这 ...

  2. HTML5多图片拖拽上传带进度条

    前言 昨天利用css2的clip属性实现了网页进度条觉得还不错,但是很多情况下,我们在那些时候用进度条呢,一般网页加载的时候如果有需要可以用,那么问题就来了,怎么才算整个加载完毕呢,是页面主要模块加载 ...

  3. struts2+jsp+jquery+Jcrop实现图片裁剪并上传

    <1> 使用html标签上传需要裁剪的大图. <2> 在页面呈现大图,使用Jcrop(Jquery)对大图进行裁剪,并且可以进行预览. <3> 选择好截取部分之后发 ...

  4. 使用cropper插件进行图片裁剪 并上传

    cropper插件的使用和 github地址: github 官方实例 我参考的中文文档: https://www.cnblogs.com/baka-sky/p/8001577.html 因为我是.n ...

  5. HTML5——将图片拖拽上传

    如下图所示: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  6. 【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

    web网站中常常有的功能:上传头像.上传封面等:一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传. 本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并 ...

  7. html5+php实现文件拖动上传功能

    界面样式我是参考了一个国外的相册网站,改动不大,只是把鸟语转换成中文,以及上传时的样式也进行了改动,之所以选这个的原因就是,我很容易做扩展,它支持3种方式添加图片,一种拖拽上传,一种常规的选择文件上传 ...

  8. Resumable.js – 基于 HTML5 File API 的文件上传

    Resumable.js 是一个 JavaScript 库,通过 HTML5 文件 API 提供,稳定和可恢复的批量上传功能.在上传大文件的时候通过每个文件分割成小块,每块在上传失败的时候,上传会不断 ...

  9. 基于h5的图片无刷新上传(uploadifive)

    基于h5的图片无刷新上传(uploadifive) uploadifive简介 了解uploadify之前,首先了解来一下什么是uploadify,uploadfy官网,uploadify和uploa ...

随机推荐

  1. jquery 高级 学习笔记

    --jquery 和 原生js可以共存,但不能混用.jquery 可以通过get()方法 转换为原生js. $("#div1").get(0).innerHTML; get() 需 ...

  2. asp.net core mvc权限控制:在视图中控制操作权限

    在asp.net core mvc中提供了权限验证框架,前面的文章中已经介绍了如何进行权限控制配置,权限配置好后,权限验证逻辑自动就会执行,但是在某些情况下,我们可能需要在代码里或者视图中通过手工方式 ...

  3. JAVA--可变长参数

    可变长参数: 可变长参数可以接受任意个数的实参,形参实际上是一个数组. 语法形式: 方法名称(类型 参数1,类型 参数2,类型...可变长参数) *可变长参数一定是方法的最后一个参数 public v ...

  4. 初学bootstrap ---栅格系统

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. ReactNative入门(1)初识ReactJs

    现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...

  6. js设计模式--单体模式

    GOF里的23种设计模式, 也是在软件开发中早就存在并反复使用的模式. 如果程序员没有明确意识到他使用过某些模式, 那么下次他也许会错过更合适的设计 (这段话来自<松本行弘的程序世界>). ...

  7. sizeof和strlen的区别和联系总结

    link:http://blog.csdn.net/ghevinn/article/details/9974967    strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头 ...

  8. 《经久不衰的Spring框架:@ResponseBody 中文乱码》

    问题背景 本文并不是介绍@ResponseBody注解,也不是中文乱码问题的大汇总笔记,这些网上都有很多内容了.这边仅对几年前,一个卡壳了挺久时间的问题的解决过程做一个记录,以警惕自己,达到自醒得目的 ...

  9. GDOI2015 解题报告

    首先嘛现在发现题目这么水我还啥都没想出来正是呵呵了.接下来就口胡下GDOI的题解吧 PS:代码什么的要请联系我 题目:快戳我 Day1: T1:这个嘛,可以先找到起点所能到达的每个点然后判断该点能否到 ...

  10. Android开发9:网络访问&Web服务开发

    前言 啦啦啦各位小伙伴们好~ 一起进入我们今天的主题.今天我们将和大家学习网络访问和Web服务开发的相关知识,一起学习熟练使用 HttpURLConnection 访问 WebService,熟悉使用 ...