针对之前的图片粘贴上传方法进行封装,并给出使用案例,如下:

目录

一.封装的文件

1.css文件:paste-img-util.css

2.js文件:paste-img-util.js

3.表单上传js:jquery.form.js

二.页面使用方法

1.顶部css引用

2.中间表单设置

3.底部js应用


一.封装的文件

1.css文件:paste-img-util.css

/*图片粘贴功能的样式*/
.img-class {width: 525px;height: 290px;cursor: pointer;
}.img-paste-class {width: 530px;height: 330px;
}.a-file {position: relative;display: inline-block;background: #D0EEFF;border: 1px solid #99D3F5;border-radius: 4px;padding: 4px 12px;overflow: hidden;color: #1E88C7;text-decoration: none;text-indent: 0;line-height: 20px;
}.a-file input {position: absolute;font-size: 100px;right: 0;top: 0;opacity: 0;
}.a-file:hover {background: #AADFFD;border-color: #78C3F3;color: #004974;text-decoration: none;
}

2.js文件:paste-img-util.js

// 初始化配置
$(function () {//照片不存在显示粘贴框if ($("#photoPath").attr("src") == "") {if (isIE()) {$("#inputImg").show();$("#pasteShapeIcon").hide();} else {$("#inputImg").hide();document.getElementById("pasteShapeIcon").style.border = "dashed";$("#pasteShapeIconTitle").text("在此框中粘贴图片");}$("#photoPath").hide();} else {if (isIE()) {$("#inputImg").show();}document.getElementById("pasteShapeIcon").style.border = "0";$("#pasteShapeIconTitle").text("");document.getElementById("photoPath").style.border = "solid";$("#photoPath").show();}// 非ie浏览器则使用粘贴方式if (!isIE()) {// 粘贴事件document.getElementById('pasteShapeIcon').addEventListener("paste", function (event) {paste_img(event);}, false);// 拖拽事件document.getElementById('pasteShapeIcon').addEventListener("drop", function (e) {e.stopPropagation();e.preventDefault();handleFiles(e.dataTransfer.files);}, false);}});// 判断是否是ie浏览器
function isIE() {if (!!window.ActiveXObject || "ActiveXObject" in window)return true;elsereturn false;
}// 非ie浏览器图片预览方法
function preViewImg(file){var reader = new FileReader()reader.onload = function (event) {document.getElementById("pasteShapeIcon").style.border = "0";$("#pasteShapeIconTitle").text("");document.getElementById("photoPath").style.border = "solid";$("#photoPath").show();$("#photoPath").attr("src", event.target.result);}reader.readAsDataURL(file);
}// 粘贴上传图片方法
function paste_img(event) {if (event.clipboardData || event.originalEvent) {//not for ie11  某些chrome版本使用的是event.originalEventvar clipboardData = (event.clipboardData || window.clipboardData || event.originalEvent.clipboardData);if (clipboardData.items) {var items = clipboardData.items,file = null;//阻止默认行为即不让剪贴板内容在div中显示出来event.preventDefault();if (items && items.length) {// 搜索剪切板itemsfor (var i = 0; i < items.length; i++) {if (items[i].type.indexOf('image') !== -1) {//getAsFile() 此方法只是living standard firefox ie11 并不支持file = items[i].getAsFile();break;}}} else {log.innerHTML = '<span style="color:red;">当前浏览器不支持桌面图片复制和粘贴上传</span>';return;}if (!file) {log.innerHTML = '<span style="color:red;">粘贴内容非图片</span>';return;} else {// 预览图片preViewImg(file);// 提示是否上传showTip(file);}} else {//其他不兼容的浏览器log.innerHTML = '<span style="color:red;">当前浏览器不支持上传</span>';return;}} else {//ie 浏览器要手动上传log.innerHTML = '<span style="color:red;">请选择图片提交上传</span>';return;}
}// 拖拽上传图片方法
function handleFiles(files) {for (var i = 0; i < files.length; i++) {var file = files[i];//如果拖住进来的是图片文件则显示if (file.type.match(/image*/)) {$("#pasteShapeIcon").focus();// 预览图片preViewImg(file);showTip(file);} else {st.layer.alert('请上传图片格式文件!', {icon : 3, time : default_close_time});continue;}}
}// 保存前确认提示
function showTip(file) {//提示是否替换图片st.layer.confirm('确定上传保存该图片?', {time: 0,closeBtn: 2,btn: ['确定', '取消'],yes: function (index, layero) {//保存图片sendFile(file);st.layer.close(index);},cancel: function (index) {st.layer.alert('您已取消上传,图片不会被保存!', {icon : 4, time : default_close_time});return;}});}// 保存图片
function sendFile(file) {// 上传必传参数(记录主键ID)var alarmId = $("#alarmId").val();var xhr = new XMLHttpRequest();// 上传进度if (xhr.upload) {xhr.upload.addEventListener('progress', function (event) {log.innerHTML = '<span style="color:blue;">正在上传,进度:</span><span style="color:red;">' + Math.round(100 * event.loaded / event.total) / 100 + '%</span>';}, false);}// 上传结束xhr.onload = function () {var res = xhr.responseText;var obj;if (res) { //返回值可能为空,就会报错obj = eval('(' + res + ')');}if (obj.successful) {log.innerHTML = '<span style="color:blue;">上传成功,地址是:' + obj.successInfo + '</span>';} else {log.innerHTML = '<span style="color:red;">' + obj.errorInfo + '</span>';}};xhr.onerror = function () {log.innerHTML = '<span style="color:red;">网络异常,上传失败</span>';};xhr.open('POST', path + '/berthChargeRecord/uploadShapeIcon', true);xhr.setRequestHeader('FILENAME', encodeURIComponent(file.name));var fd = new FormData();fd.append("file", file);fd.append("alarmId", alarmId);xhr.send(fd);}// ie浏览器上传附件按钮优化 ,加入图片判断
function getImgName(file) {var filePath = $(file).val();var parent = $(file).parent();var arr = filePath.split('\\');var fileName = arr[arr.length - 1];if (filePath == "") {log.innerHTML = '<span style="color:red;">请选择图片</span>';return false;} else {if (!/\.(gif|jpg|jpeg|png|bmp|pic|GIF|JPG|JPEG|PNG|BMP|PIC)$/.test(fileName)) {parent.text("选择图片").prepend($(file));log.innerHTML = '<span style="color:red;">仅限于png、gif、jpeg、jpg、bmp、pic图片格式文件上传</span>';return false;} else {log.innerHTML = '';if (fileName.length > 16) {var name1 = fileName.substring(0, 8) + "...";var name2 = "..." + fileName.substring(fileName.length - 8, fileName.length);fileName = name1 + name2;}parent.text(fileName).prepend($(file));//图片预览var $file = $(file);var fileObj = $file[0];var windowURL = window.URL || window.webkitURL;var dataURL;var $img = $("#photoPath");var $paste = $("#pasteShapeIcon");// 区别是否支持if (fileObj && fileObj.files && fileObj.files[0]) {dataURL = windowURL.createObjectURL(fileObj.files[0]);} else {dataURL = $file.val();var imgObj = document.getElementById("photoPath");imgObj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";imgObj.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = dataURL;}$paste.removeAttr('title');$paste.show();$img.show();$img.attr('border', 'solid');$img.attr('src', dataURL);//提示是否替换图片st.layer.confirm('确定上传保存该图片?', {time: 0,closeBtn: 2,btn: ['确定', '取消'],yes: function (index, layero) {st.layer.close(index);//给form添加action地址并执行提交var options = {url: path + "/berthChargeRecord/uploadShapeIcon",type: 'post',//target:'formUpFile',  //服务器返回的响应数据显示在元素(Id)号确定//clearForm:true,       //提交成功后是否清空表单中的字段值//restForm:true,        //提交成功后是否重置表单中的字段值,即恢复到页面加载时的状态//timeout:6000,         //设置请求时间,超过该时间后,自动退出请求,单位(毫秒)。dataType: 'json',success: function (obj) {if (obj) {if (obj.successful) {$("#photoPath").attr("src", obj.successInfo);log.innerHTML = '<span style="color:blue;">上传成功,地址是:' + obj.successInfo + '</span>';} else {log.innerHTML = '<span style="color:red;">' + obj.errorInfo + '</span>';}} else {log.innerHTML = '<span style="color:red;">图片已保存</span>';}},error: function (xhr, status, error) {var data = xhr.responseText;if (data != null && data != '') {data = park.util.parseJSON(data);if (null != data && null != data.errorInfo) {log.innerHTML = '<span style="color:red;">' + data.errorInfo + '</span>';} else {log.innerHTML = '<span style="color:red;">请求失败,请重试</span>';}} else {log.innerHTML = '<span style="color:red;">请求失败,请重试</span>';}},complete: function (xhr, status) {st.layer.closeAll('loading');}};$("#applyFrom").ajaxSubmit(options);},cancel: function (index) {st.layer.alert('您已取消上传,图片不会被保存!', {icon : 4, time : default_close_time});return;}});}}}// 插件显示图片
function getImg(cellvalue, alarmId) {//清理原图片缓存$('[data-show=add]').remove();if(cellvalue == "" || cellvalue == null || cellvalue == "0"){// 加载遮罩st.layer.load(3);$.ajax({url : path + '/alarm/getAlarmImgs',type : 'POST',timeout : 300000,// 超时时间设置为300sdataType : 'json',data : {'alarmId' : alarmId},complete : function() {st.layer.closeAll('loading');},success : function(data, status) {if (data.successful) {var imgObjectList = data.resultValue.split("#split#");if (null != imgObjectList && imgObjectList.length > 0) {for (var i = 0, j = 1; i < imgObjectList.length; i++, j++) {if (null != imgObjectList[i] && "" != imgObjectList[i] && imgObjectList[i] != "null") {$("#alarmImg").append('<img data-show="add"  data-caption="图' + j + '(共' + imgObjectList.length + '张)" data-src="' + imgObjectList[i] + '"  src="' + imgObjectList[i] + '" >');}}//初始化新增的图片对象$('[data-show=add]').magnify(options);if($('[data-show=add]').length>0){$('[data-show=add]').first().click();}else{$('#alarmImg img').magnify(options);$('[data-show=default]').click();}}} else {st.layer.alert(data.errorInfo, {icon : 0});}},error : function(data, status) {}});} else {// 视频方案有两张图片var imgObjectList = cellvalue.split("#split#");if (null != imgObjectList && imgObjectList.length > 0) {for (var i = 0, j = 1; i < imgObjectList.length; i++, j++) {if (null != imgObjectList[i] && "" != imgObjectList[i] && imgObjectList[i] != "null") {$("#alarmImg").append('<img data-show="add"  data-caption="图' + j + '(共' + imgObjectList.length + '张)" data-src="' + imgObjectList[i] + '"  src="' + imgObjectList[i] + '" >');}}//初始化新增的图片对象$('[data-show=add]').magnify(options);if($('[data-show=add]').length>0){$('[data-show=add]').first().click();}else{$('#alarmImg img').magnify(options);$('[data-show=default]').click();}}}
}

3.表单上传js:jquery.form.js

/*!* jQuery Form Plugin* version: 3.50.0-2014.02.05* Requires jQuery v1.5 or later* Copyright (c) 2013 M. Alsup* Examples and documentation at: http://malsup.com/jquery/form/* Project repository: https://github.com/malsup/form* Dual licensed under the MIT and GPL licenses.* https://github.com/malsup/form#copyright-and-license*/
/*global ActiveXObject */// AMD support
(function (factory) {"use strict";if (typeof define === 'function' && define.amd) {// using AMD; register as anon moduledefine(['jquery'], factory);} else {// no AMD; invoke directlyfactory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );}
}(function($) {
"use strict";/*Usage Note:-----------Do not use both ajaxSubmit and ajaxForm on the same form.  Thesefunctions are mutually exclusive.  Use ajaxSubmit if you wantto bind your own submit handler to the form.  For example,$(document).ready(function() {$('#myForm').on('submit', function(e) {e.preventDefault(); // <-- important$(this).ajaxSubmit({target: '#output'});});});Use ajaxForm when you want the plugin to manage all the event bindingfor you.  For example,$(document).ready(function() {$('#myForm').ajaxForm({target: '#output'});});You can also use ajaxForm with delegation (requires jQuery v1.7+), so theform does not have to exist when you invoke ajaxForm:$('#myForm').ajaxForm({delegation: true,target: '#output'});When using ajaxForm, the ajaxSubmit function will be invoked for youat the appropriate time.
*//*** Feature detection*/
var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;var hasProp = !!$.fn.prop;// attr2 uses prop when it can but checks the return type for
// an expected string.  this accounts for the case where a form
// contains inputs with names like "action" or "method"; in those
// cases "prop" returns the element
$.fn.attr2 = function() {if ( ! hasProp ) {return this.attr.apply(this, arguments);}var val = this.prop.apply(this, arguments);if ( ( val && val.jquery ) || typeof val === 'string' ) {return val;}return this.attr.apply(this, arguments);
};/*** ajaxSubmit() provides a mechanism for immediately submitting* an HTML form using AJAX.*/
$.fn.ajaxSubmit = function(options) {/*jshint scripturl:true */// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)if (!this.length) {log('ajaxSubmit: skipping submit process - no element selected');return this;}var method, action, url, $form = this;if (typeof options == 'function') {options = { success: options };}else if ( options === undefined ) {options = {};}method = options.type || this.attr2('method');action = options.url  || this.attr2('action');url = (typeof action === 'string') ? $.trim(action) : '';url = url || window.location.href || '';if (url) {// clean url (don't include hash vaue)url = (url.match(/^([^#]+)/)||[])[1];}options = $.extend(true, {url:  url,success: $.ajaxSettings.success,type: method || $.ajaxSettings.type,iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'}, options);// hook for manipulating the form data before it is extracted;// convenient for use with rich editors like tinyMCE or FCKEditorvar veto = {};this.trigger('form-pre-serialize', [this, options, veto]);if (veto.veto) {log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');return this;}// provide opportunity to alter form data before it is serializedif (options.beforeSerialize && options.beforeSerialize(this, options) === false) {log('ajaxSubmit: submit aborted via beforeSerialize callback');return this;}var traditional = options.traditional;if ( traditional === undefined ) {traditional = $.ajaxSettings.traditional;}var elements = [];var qx, a = this.formToArray(options.semantic, elements);if (options.data) {options.extraData = options.data;qx = $.param(options.data, traditional);}// give pre-submit callback an opportunity to abort the submitif (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {log('ajaxSubmit: submit aborted via beforeSubmit callback');return this;}// fire vetoable 'validate' eventthis.trigger('form-submit-validate', [a, this, options, veto]);if (veto.veto) {log('ajaxSubmit: submit vetoed via form-submit-validate trigger');return this;}var q = $.param(a, traditional);if (qx) {q = ( q ? (q + '&' + qx) : qx );}if (options.type.toUpperCase() == 'GET') {options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;options.data = null;  // data is null for 'get'}else {options.data = q; // data is the query string for 'post'}var callbacks = [];if (options.resetForm) {callbacks.push(function() { $form.resetForm(); });}if (options.clearForm) {callbacks.push(function() { $form.clearForm(options.includeHidden); });}// perform a load on the target only if dataType is not providedif (!options.dataType && options.target) {var oldSuccess = options.success || function(){};callbacks.push(function(data) {var fn = options.replaceTarget ? 'replaceWith' : 'html';$(options.target)[fn](data).each(oldSuccess, arguments);});}else if (options.success) {callbacks.push(options.success);}options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd argvar context = options.context || this ;    // jQuery 1.4+ supports scope contextfor (var i=0, max=callbacks.length; i < max; i++) {callbacks[i].apply(context, [data, status, xhr || $form, $form]);}};if (options.error) {var oldError = options.error;options.error = function(xhr, status, error) {var context = options.context || this;oldError.apply(context, [xhr, status, error, $form]);};}if (options.complete) {var oldComplete = options.complete;options.complete = function(xhr, status) {var context = options.context || this;oldComplete.apply(context, [xhr, status, $form]);};}// are there files to upload?// [value] (issue #113), also see comment:// https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });var hasFileInputs = fileInputs.length > 0;var mp = 'multipart/form-data';var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);var fileAPI = feature.fileapi && feature.formdata;log("fileAPI :" + fileAPI);var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;var jqxhr;// options.iframe allows user to force iframe mode// 06-NOV-09: now defaulting to iframe mode if file input is detectedif (options.iframe !== false && (options.iframe || shouldUseFrame)) {// hack to fix Safari hang (thanks to Tim Molendijk for this)// see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5dif (options.closeKeepAlive) {$.get(options.closeKeepAlive, function() {jqxhr = fileUploadIframe(a);});}else {jqxhr = fileUploadIframe(a);}}else if ((hasFileInputs || multipart) && fileAPI) {jqxhr = fileUploadXhr(a);}else {jqxhr = $.ajax(options);}$form.removeData('jqxhr').data('jqxhr', jqxhr);// clear element arrayfor (var k=0; k < elements.length; k++) {elements[k] = null;}// fire 'notify' eventthis.trigger('form-submit-notify', [this, options]);return this;// utility fn for deep serializationfunction deepSerialize(extraData){var serialized = $.param(extraData, options.traditional).split('&');var len = serialized.length;var result = [];var i, part;for (i=0; i < len; i++) {// #252; undo param space replacementserialized[i] = serialized[i].replace(/\+/g,' ');part = serialized[i].split('=');// #278; use array instead of object storage, favoring array serializationsresult.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);}return result;}// XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)function fileUploadXhr(a) {var formdata = new FormData();for (var i=0; i < a.length; i++) {formdata.append(a[i].name, a[i].value);}if (options.extraData) {var serializedData = deepSerialize(options.extraData);for (i=0; i < serializedData.length; i++) {if (serializedData[i]) {formdata.append(serializedData[i][0], serializedData[i][1]);}}}options.data = null;var s = $.extend(true, {}, $.ajaxSettings, options, {contentType: false,processData: false,cache: false,type: method || 'POST'});if (options.uploadProgress) {// workaround because jqXHR does not expose upload propertys.xhr = function() {var xhr = $.ajaxSettings.xhr();if (xhr.upload) {xhr.upload.addEventListener('progress', function(event) {var percent = 0;var position = event.loaded || event.position; /*event.position is deprecated*/var total = event.total;if (event.lengthComputable) {percent = Math.ceil(position / total * 100);}options.uploadProgress(event, position, total, percent);}, false);}return xhr;};}s.data = null;var beforeSend = s.beforeSend;s.beforeSend = function(xhr, o) {//Send FormData() provided by userif (options.formData) {o.data = options.formData;}else {o.data = formdata;}if(beforeSend) {beforeSend.call(this, xhr, o);}};return $.ajax(s);}// private function for handling file uploads (hat tip to YAHOO!)function fileUploadIframe(a) {var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;var deferred = $.Deferred();// #341deferred.abort = function(status) {xhr.abort(status);};if (a) {// ensure that every serialized input is still enabledfor (i=0; i < elements.length; i++) {el = $(elements[i]);if ( hasProp ) {el.prop('disabled', false);}else {el.removeAttr('disabled');}}}s = $.extend(true, {}, $.ajaxSettings, options);s.context = s.context || s;id = 'jqFormIO' + (new Date().getTime());if (s.iframeTarget) {$io = $(s.iframeTarget);n = $io.attr2('name');if (!n) {$io.attr2('name', id);}else {id = n;}}else {$io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });}io = $io[0];xhr = { // mock objectaborted: 0,responseText: null,responseXML: null,status: 0,statusText: 'n/a',getAllResponseHeaders: function() {},getResponseHeader: function() {},setRequestHeader: function() {},abort: function(status) {var e = (status === 'timeout' ? 'timeout' : 'aborted');log('aborting upload... ' + e);this.aborted = 1;try { // #214, #257if (io.contentWindow.document.execCommand) {io.contentWindow.document.execCommand('Stop');}}catch(ignore) {}$io.attr('src', s.iframeSrc); // abort op in progressxhr.error = e;if (s.error) {s.error.call(s.context, xhr, e, status);}if (g) {$.event.trigger("ajaxError", [xhr, s, e]);}if (s.complete) {s.complete.call(s.context, xhr, e);}}};g = s.global;// trigger ajax global events so that activity/block indicators work like normalif (g && 0 === $.active++) {$.event.trigger("ajaxStart");}if (g) {$.event.trigger("ajaxSend", [xhr, s]);}if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {if (s.global) {$.active--;}deferred.reject();return deferred;}if (xhr.aborted) {deferred.reject();return deferred;}// add submitting element to data if we know itsub = form.clk;if (sub) {n = sub.name;if (n && !sub.disabled) {s.extraData = s.extraData || {};s.extraData[n] = sub.value;if (sub.type == "image") {s.extraData[n+'.x'] = form.clk_x;s.extraData[n+'.y'] = form.clk_y;}}}var CLIENT_TIMEOUT_ABORT = 1;var SERVER_ABORT = 2;function getDoc(frame) {/* it looks like contentWindow or contentDocument do not* carry the protocol property in ie8, when running under ssl* frame.document is the only valid response document, since* the protocol is know but not on the other two objects. strange?* "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy*/var doc = null;// IE8 cascading access checktry {if (frame.contentWindow) {doc = frame.contentWindow.document;}} catch(err) {// IE8 access denied under ssl & missing protocollog('cannot get iframe.contentWindow document: ' + err);}if (doc) { // successful getting contentreturn doc;}try { // simply checking may throw in ie8 under ssl or mismatched protocoldoc = frame.contentDocument ? frame.contentDocument : frame.document;} catch(err) {// last attemptlog('cannot get iframe.contentDocument: ' + err);doc = frame.document;}return doc;}// Rails CSRF hack (thanks to Yvan Barthelemy)var csrf_token = $('meta[name=csrf-token]').attr('content');var csrf_param = $('meta[name=csrf-param]').attr('content');if (csrf_param && csrf_token) {s.extraData = s.extraData || {};s.extraData[csrf_param] = csrf_token;}// take a breath so that pending repaints get some cpu time before the upload startsfunction doSubmit() {// make sure form attrs are setvar t = $form.attr2('target'), a = $form.attr2('action'), mp = 'multipart/form-data',et = $form.attr('enctype') || $form.attr('encoding') || mp;// update form attrs in IE friendly wayform.setAttribute('target',id);if (!method || /post/i.test(method) ) {form.setAttribute('method', 'POST');}if (a != s.url) {form.setAttribute('action', s.url);}// ie borks in some cases when setting encodingif (! s.skipEncodingOverride && (!method || /post/i.test(method))) {$form.attr({encoding: 'multipart/form-data',enctype:  'multipart/form-data'});}// support timoutif (s.timeout) {timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);}// look for server abortsfunction checkState() {try {var state = getDoc(io).readyState;log('state = ' + state);if (state && state.toLowerCase() == 'uninitialized') {setTimeout(checkState,50);}}catch(e) {log('Server abort: ' , e, ' (', e.name, ')');cb(SERVER_ABORT);if (timeoutHandle) {clearTimeout(timeoutHandle);}timeoutHandle = undefined;}}// add "extra" data to form if provided in optionsvar extraInputs = [];try {if (s.extraData) {for (var n in s.extraData) {if (s.extraData.hasOwnProperty(n)) {// if using the $.param format that allows for multiple values with the same nameif($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {extraInputs.push($('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value).appendTo(form)[0]);} else {extraInputs.push($('<input type="hidden" name="'+n+'">').val(s.extraData[n]).appendTo(form)[0]);}}}}if (!s.iframeTarget) {// add iframe to doc and submit the form$io.appendTo('body');}if (io.attachEvent) {io.attachEvent('onload', cb);}else {io.addEventListener('load', cb, false);}setTimeout(checkState,15);try {form.submit();} catch(err) {// just in case form has element with name/id of 'submit'var submitFn = document.createElement('form').submit;submitFn.apply(form);}}finally {// reset attrs and remove "extra" input elementsform.setAttribute('action',a);form.setAttribute('enctype', et); // #380if(t) {form.setAttribute('target', t);} else {$form.removeAttr('target');}$(extraInputs).remove();}}if (s.forceSync) {doSubmit();}else {setTimeout(doSubmit, 10); // this lets dom updates render}var data, doc, domCheckCount = 50, callbackProcessed;function cb(e) {if (xhr.aborted || callbackProcessed) {return;}doc = getDoc(io);if(!doc) {log('cannot access response document');e = SERVER_ABORT;}if (e === CLIENT_TIMEOUT_ABORT && xhr) {xhr.abort('timeout');deferred.reject(xhr, 'timeout');return;}else if (e == SERVER_ABORT && xhr) {xhr.abort('server abort');deferred.reject(xhr, 'error', 'server abort');return;}if (!doc || doc.location.href == s.iframeSrc) {// response not received yetif (!timedOut) {return;}}if (io.detachEvent) {io.detachEvent('onload', cb);}else {io.removeEventListener('load', cb, false);}var status = 'success', errMsg;try {if (timedOut) {throw 'timeout';}var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);log('isXml='+isXml);if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {if (--domCheckCount) {// in some browsers (Opera) the iframe DOM is not always traversable when// the onload callback fires, so we loop a bit to accommodatelog('requeing onLoad callback, DOM not available');setTimeout(cb, 250);return;}// let this fall through because server response could be an empty document//log('Could not access iframe DOM after mutiple tries.');//throw 'DOMException: not available';}//log('response detected');var docRoot = doc.body ? doc.body : doc.documentElement;xhr.responseText = docRoot ? docRoot.innerHTML : null;xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;if (isXml) {s.dataType = 'xml';}xhr.getResponseHeader = function(header){var headers = {'content-type': s.dataType};return headers[header.toLowerCase()];};// support for XHR 'status' & 'statusText' emulation :if (docRoot) {xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;}var dt = (s.dataType || '').toLowerCase();var scr = /(json|script|text)/.test(dt);if (scr || s.textarea) {// see if user embedded response in textareavar ta = doc.getElementsByTagName('textarea')[0];if (ta) {xhr.responseText = ta.value;// support for XHR 'status' & 'statusText' emulation :xhr.status = Number( ta.getAttribute('status') ) || xhr.status;xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;}else if (scr) {// account for browsers injecting pre around json responsevar pre = doc.getElementsByTagName('pre')[0];var b = doc.getElementsByTagName('body')[0];if (pre) {xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;}else if (b) {xhr.responseText = b.textContent ? b.textContent : b.innerText;}}}else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {xhr.responseXML = toXml(xhr.responseText);}try {data = httpData(xhr, dt, s);}catch (err) {status = 'parsererror';xhr.error = errMsg = (err || status);}}catch (err) {log('error caught: ',err);status = 'error';xhr.error = errMsg = (err || status);}if (xhr.aborted) {log('upload aborted');status = null;}if (xhr.status) { // we've set xhr.statusstatus = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';}// ordering of these callbacks/triggers is odd, but that's how $.ajax does itif (status === 'success') {if (s.success) {s.success.call(s.context, data, 'success', xhr);}deferred.resolve(xhr.responseText, 'success', xhr);if (g) {$.event.trigger("ajaxSuccess", [xhr, s]);}}else if (status) {if (errMsg === undefined) {errMsg = xhr.statusText;}if (s.error) {s.error.call(s.context, xhr, status, errMsg);}deferred.reject(xhr, 'error', errMsg);if (g) {$.event.trigger("ajaxError", [xhr, s, errMsg]);}}if (g) {$.event.trigger("ajaxComplete", [xhr, s]);}if (g && ! --$.active) {$.event.trigger("ajaxStop");}if (s.complete) {s.complete.call(s.context, xhr, status);}callbackProcessed = true;if (s.timeout) {clearTimeout(timeoutHandle);}// clean upsetTimeout(function() {if (!s.iframeTarget) {$io.remove();}else { //adding else to clean up existing iframe response.$io.attr('src', s.iframeSrc);}xhr.responseXML = null;}, 100);}var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)if (window.ActiveXObject) {doc = new ActiveXObject('Microsoft.XMLDOM');doc.async = 'false';doc.loadXML(s);}else {doc = (new DOMParser()).parseFromString(s, 'text/xml');}return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;};var parseJSON = $.parseJSON || function(s) {/*jslint evil:true */return window['eval']('(' + s + ')');};var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4var ct = xhr.getResponseHeader('content-type') || '',xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,data = xml ? xhr.responseXML : xhr.responseText;if (xml && data.documentElement.nodeName === 'parsererror') {if ($.error) {$.error('parsererror');}}if (s && s.dataFilter) {data = s.dataFilter(data, type);}if (typeof data === 'string') {if (type === 'json' || !type && ct.indexOf('json') >= 0) {data = parseJSON(data);} else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {$.globalEval(data);}}return data;};return deferred;}
};/*** ajaxForm() provides a mechanism for fully automating form submission.** The advantages of using this method instead of ajaxSubmit() are:** 1: This method will include coordinates for <input type="image" /> elements (if the element*    is used to submit the form).* 2. This method will include the submit element's name/value data (for the element that was*    used to submit the form).* 3. This method binds the submit() method to the form for you.** The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely* passes the options argument along after properly binding events for submit elements and* the form itself.*/
$.fn.ajaxForm = function(options) {options = options || {};options.delegation = options.delegation && $.isFunction($.fn.on);// in jQuery 1.3+ we can fix mistakes with the ready stateif (!options.delegation && this.length === 0) {var o = { s: this.selector, c: this.context };if (!$.isReady && o.s) {log('DOM not ready, queuing ajaxForm');$(function() {$(o.s,o.c).ajaxForm(options);});return this;}// is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));return this;}if ( options.delegation ) {$(document).off('submit.form-plugin', this.selector, doAjaxSubmit).off('click.form-plugin', this.selector, captureSubmittingElement).on('submit.form-plugin', this.selector, options, doAjaxSubmit).on('click.form-plugin', this.selector, options, captureSubmittingElement);return this;}return this.ajaxFormUnbind().bind('submit.form-plugin', options, doAjaxSubmit).bind('click.form-plugin', options, captureSubmittingElement);
};// private event handlers
function doAjaxSubmit(e) {/*jshint validthis:true */var options = e.data;if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceede.preventDefault();$(e.target).ajaxSubmit(options); // #365}
}function captureSubmittingElement(e) {/*jshint validthis:true */var target = e.target;var $el = $(target);if (!($el.is("[type=submit],[type=image]"))) {// is this a child element of the submit el?  (ex: a span within a button)var t = $el.closest('[type=submit]');if (t.length === 0) {return;}target = t[0];}var form = this;form.clk = target;if (target.type == 'image') {if (e.offsetX !== undefined) {form.clk_x = e.offsetX;form.clk_y = e.offsetY;} else if (typeof $.fn.offset == 'function') {var offset = $el.offset();form.clk_x = e.pageX - offset.left;form.clk_y = e.pageY - offset.top;} else {form.clk_x = e.pageX - target.offsetLeft;form.clk_y = e.pageY - target.offsetTop;}}// clear form varssetTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
}// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {return this.unbind('submit.form-plugin click.form-plugin');
};/*** formToArray() gathers form element data into an array of objects that can* be passed to any of the following ajax functions: $.get, $.post, or load.* Each object in the array has both a 'name' and 'value' property.  An example of* an array for a simple login form might be:** [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]** It is this array that is passed to pre-submit callback functions provided to the* ajaxSubmit() and ajaxForm() methods.*/
$.fn.formToArray = function(semantic, elements) {var a = [];if (this.length === 0) {return a;}var form = this[0];var formId = this.attr('id');var els = semantic ? form.getElementsByTagName('*') : form.elements;var els2;if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390els = $(els).get();  // convert to standard array}// #386; account for inputs outside the form which use the 'form' attributeif ( formId ) {els2 = $(':input[form=' + formId + ']').get();if ( els2.length ) {els = (els || []).concat(els2);}}if (!els || !els.length) {return a;}var i,j,n,v,el,max,jmax;for(i=0, max=els.length; i < max; i++) {el = els[i];n = el.name;if (!n || el.disabled) {continue;}if (semantic && form.clk && el.type == "image") {// handle image inputs on the fly when semantic == trueif(form.clk == el) {a.push({name: n, value: $(el).val(), type: el.type });a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});}continue;}v = $.fieldValue(el, true);if (v && v.constructor == Array) {if (elements) {elements.push(el);}for(j=0, jmax=v.length; j < jmax; j++) {a.push({name: n, value: v[j]});}}else if (feature.fileapi && el.type == 'file') {if (elements) {elements.push(el);}var files = el.files;if (files.length) {for (j=0; j < files.length; j++) {a.push({name: n, value: files[j], type: el.type});}}else {// #180a.push({ name: n, value: '', type: el.type });}}else if (v !== null && typeof v != 'undefined') {if (elements) {elements.push(el);}a.push({name: n, value: v, type: el.type, required: el.required});}}if (!semantic && form.clk) {// input type=='image' are not found in elements array! handle it herevar $input = $(form.clk), input = $input[0];n = input.name;if (n && !input.disabled && input.type == 'image') {a.push({name: n, value: $input.val()});a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});}}return a;
};/*** Serializes form data into a 'submittable' string. This method will return a string* in the format: name1=value1&amp;name2=value2*/
$.fn.formSerialize = function(semantic) {//hand off to jQuery.param for proper encodingreturn $.param(this.formToArray(semantic));
};/*** Serializes all field elements in the jQuery object into a query string.* This method will return a string in the format: name1=value1&amp;name2=value2*/
$.fn.fieldSerialize = function(successful) {var a = [];this.each(function() {var n = this.name;if (!n) {return;}var v = $.fieldValue(this, successful);if (v && v.constructor == Array) {for (var i=0,max=v.length; i < max; i++) {a.push({name: n, value: v[i]});}}else if (v !== null && typeof v != 'undefined') {a.push({name: this.name, value: v});}});//hand off to jQuery.param for proper encodingreturn $.param(a);
};/*** Returns the value(s) of the element in the matched set.  For example, consider the following form:**  <form><fieldset>*      <input name="A" type="text" />*      <input name="A" type="text" />*      <input name="B" type="checkbox" value="B1" />*      <input name="B" type="checkbox" value="B2"/>*      <input name="C" type="radio" value="C1" />*      <input name="C" type="radio" value="C2" />*  </fieldset></form>**  var v = $('input[type=text]').fieldValue();*  // if no values are entered into the text inputs*  v == ['','']*  // if values entered into the text inputs are 'foo' and 'bar'*  v == ['foo','bar']**  var v = $('input[type=checkbox]').fieldValue();*  // if neither checkbox is checked*  v === undefined*  // if both checkboxes are checked*  v == ['B1', 'B2']**  var v = $('input[type=radio]').fieldValue();*  // if neither radio is checked*  v === undefined*  // if first radio is checked*  v == ['C1']** The successful argument controls whether or not the field element must be 'successful'* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).* The default value of the successful argument is true.  If this value is false the value(s)* for each element is returned.** Note: This method *always* returns an array.  If no valid value can be determined the*    array will be empty, otherwise it will contain one or more values.*/
$.fn.fieldValue = function(successful) {for (var val=[], i=0, max=this.length; i < max; i++) {var el = this[i];var v = $.fieldValue(el, successful);if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {continue;}if (v.constructor == Array) {$.merge(val, v);}else {val.push(v);}}return val;
};/*** Returns the value of the field element.*/
$.fieldValue = function(el, successful) {var n = el.name, t = el.type, tag = el.tagName.toLowerCase();if (successful === undefined) {successful = true;}if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||(t == 'checkbox' || t == 'radio') && !el.checked ||(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||tag == 'select' && el.selectedIndex == -1)) {return null;}if (tag == 'select') {var index = el.selectedIndex;if (index < 0) {return null;}var a = [], ops = el.options;var one = (t == 'select-one');var max = (one ? index+1 : ops.length);for(var i=(one ? index : 0); i < max; i++) {var op = ops[i];if (op.selected) {var v = op.value;if (!v) { // extra pain for IE...v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;}if (one) {return v;}a.push(v);}}return a;}return $(el).val();
};/*** Clears the form data.  Takes the following actions on the form's input fields:*  - input text fields will have their 'value' property set to the empty string*  - select elements will have their 'selectedIndex' property set to -1*  - checkbox and radio inputs will have their 'checked' property set to false*  - inputs of type submit, button, reset, and hidden will *not* be effected*  - button elements will *not* be effected*/
$.fn.clearForm = function(includeHidden) {return this.each(function() {$('input,select,textarea', this).clearFields(includeHidden);});
};/*** Clears the selected form elements.*/
$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this listreturn this.each(function() {var t = this.type, tag = this.tagName.toLowerCase();if (re.test(t) || tag == 'textarea') {this.value = '';}else if (t == 'checkbox' || t == 'radio') {this.checked = false;}else if (tag == 'select') {this.selectedIndex = -1;}else if (t == "file") {if (/MSIE/.test(navigator.userAgent)) {$(this).replaceWith($(this).clone(true));} else {$(this).val('');}}else if (includeHidden) {// includeHidden can be the value true, or it can be a selector string// indicating a special test; for example://  $('#myForm').clearForm('.special:hidden')// the above would clean hidden inputs that have the class of 'special'if ( (includeHidden === true && /hidden/.test(t)) ||(typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {this.value = '';}}});
};/*** Resets the form data.  Causes all form elements to be reset to their original value.*/
$.fn.resetForm = function() {return this.each(function() {// guard against an input with the name of 'reset'// note that IE reports the reset function as an 'object'if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {this.reset();}});
};/*** Enables or disables any matching elements.*/
$.fn.enable = function(b) {if (b === undefined) {b = true;}return this.each(function() {this.disabled = !b;});
};/*** Checks/unchecks any matching checkboxes or radio buttons and* selects/deselects and matching option elements.*/
$.fn.selected = function(select) {if (select === undefined) {select = true;}return this.each(function() {var t = this.type;if (t == 'checkbox' || t == 'radio') {this.checked = select;}else if (this.tagName.toLowerCase() == 'option') {var $sel = $(this).parent('select');if (select && $sel[0] && $sel[0].type == 'select-one') {// deselect all other options$sel.find('option').selected(false);}this.selected = select;}});
};// expose debug var
$.fn.ajaxSubmit.debug = false;// helper fn for console logging
function log() {if (!$.fn.ajaxSubmit.debug) {return;}var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');if (window.console && window.console.log) {window.console.log(msg);}else if (window.opera && window.opera.postError) {window.opera.postError(msg);}
}}));

二.页面使用方法

1.顶部css引用

<head><title>漏费补入</title><%@include file="/WEB-INF/jsp/common/head.jsp" %><link rel="stylesheet" href="<%=path%>/static/common/magnify/docs/css/paste-img-util.css">
</head>

2.中间表单设置

<form id="applyFrom" name="applyFrom" class="form-inline" method="post" enctype="multipart/form-data"style="margin: 15px 0 0 10px; padding-right: inherit;"><input type="hidden" value="${alarmRecord.alarmId}" id="alarmId" name="alarmId"/>.....此处省略<div class="control-group"><div class="control-label">入车图片:</div><div class="controls" style="position: relative;"><p id="log" style="width: 490px;word-break:break-all;"></p><div id="inputImg" style="display: none;"><a href="javascript:void(0);" class="a-file">选择图片<input type="file" id="file" name="file"onchange='getImgName(this);'/></a></div><c:if test="${ not empty alarmRecord.imgUrl}"><div id="pasteShapeIcon" contenteditable="true" class="img-paste-class" title="粘贴上传图片"><span id="pasteShapeIconTitle"></span><img id="photoPath" src="${alarmRecord.imgUrl}" class="img-class"onclick="getImg('${alarmRecord.imgUrls}', '${alarmRecord.alarmId}')"></div></c:if><c:if test="${ empty alarmRecord.imgUrl}"><div id="pasteShapeIcon" contenteditable="true" class="img-paste-class" title="粘贴上传图片"><span id="pasteShapeIconTitle"></span><img id="photoPath" src="" class="img-class"></div></c:if></div></div>
</form><!-- 应用mangify插件图片弹出框 --><div id="alarmImg" style="display: none;"><img data-show="default" data-caption="暂无图片" data-src="<%=path%>/static/images/notExistImg.jpg"src="<%=path%>/static/images/notExistImg.jpg"></div>

3.底部js应用

<script type="text/javascript" src="<%=path%>/static/common/js/jquery.form.js"></script>
<script src="<%=path%>/static/common/magnify/dist/paste-img-util.js"></script>
<script type="text/javascript">// 应用mangify插件获取图片function getImg(imgUrl, alarmId) {parent.getImg(imgUrl, alarmId);}
</script>

注意:mangify插件见https://github.com/peak-chen/project-dialog-magnify-util

图片粘贴上传(方法二)相关推荐

  1. Kindeditor图片粘贴上传(chrome)

    图片粘贴后设置图片属性可参看:https://blog.csdn.net/Dongguabai/article/details/100399904 kindeditor4.1.x版本已支持图片批量上传 ...

  2. Kindeditor 图片粘贴上传后设置图片属性

    之前转载过一篇 Kindeditor 图片粘贴上传(https://blog.csdn.net/Dongguabai/article/details/100116608)的博客.但是还是存在一个问题, ...

  3. 百度UEditor 图片粘贴上传,实现图文粘贴,图片自动上传

    1.4.2之后官方并没有做功能的改动,1.4.2在word复制这块没有bug,其他版本会出现手动无法转存的情况 本文使用的后台是Java.前端为Jsp(前端都一样,后台如果语言不通得自己做 Base6 ...

  4. Word图片粘贴上传控件,直接粘贴图片到编辑器-DEDE

    如何做到 ueditor批量上传word图片? 1.前端引用代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional// ...

  5. KindEditor 图片粘贴上传,实现图文粘贴,图片自动上传

    tinymce是很优秀的一款富文本编辑器,可以去官网下载.https://www.tiny.cloud 这里分享的是它官网的一个收费插件powerpaste的旧版本源码,但也不影响功能使用. umed ...

  6. php js 异步上传图片,javascript实现异步图片上传方法实例

    如何通过javascript写出异步图片上传?本文我们就和大家分享一些实例代码javascript实现异步图片上传.我们首先看下HTML代码实现的form提交部分.其中大家在测试的时候需要把test的 ...

  7. .net mvc + layui做图片上传(二)—— 使用流上传和下载图片

    摘要:上篇文章写到一种上传图片的方法,其中提到那种方法的局限性,就是上传的文件只能保存在本项目目录下,在其他目录中访问不到该文件.这与浏览器的安全性机制有关,浏览器不允许用户用任意的路径访问服务器上的 ...

  8. JavaScript移动端图片上传方法

    移动端图片上传方法 实现效果 文件下载 http://files.cnblogs.com/files/sntetwt/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%9B%BE%E7%8 ...

  9. Typora+PicGo+又拍云实现图片快速上传的两种方法

    Typora+PicGo+又拍云实现图片快速上传 第一步:注册个又拍云账户,加入又拍云联盟 又拍云 官网注册地址:又拍云联盟 - 开发者帮助计划,为开发者加速 - 又拍云 注册认证后有 10G 永久免 ...

最新文章

  1. 容器化方案Docker的使用方法
  2. sonar 报错日志分析(根据日志跟踪源码执行)
  3. matlab柱状斜线_Matlab小练习:按斜线方向依次赋值矩阵
  4. 布尔运算_3dmax教程 - 布尔运算
  5. 面向对象要点(构造函数)
  6. 请求zabbix_快速部署zabbix
  7. 腾讯-004-两个排序数组的中位数
  8. centos mysql phpmyadmin_CentOS下phpMyAdmin安装
  9. UIScrollView 遇到的小坑
  10. 对付U盘病毒彻底免疫
  11. 【python 作日期的折线图和柱状图组合图】
  12. 腾讯云服务器安装win10
  13. NVIDIA NCCL优化——利用共享内存实现比NCCL更快的集合通信
  14. 测试还是国外的香?走进海外测试开发工程师
  15. 用C语言对数据或文件内容进行加密
  16. 霍尼韦尔启动在武汉的新兴市场中国总部;红牛商标所有者​天丝集团扩建在华生产基地 | 美通企业日报...
  17. iphone 屏幕大小
  18. IOS开发学习周报(二)
  19. Zrou株肉与造洋饭书及摩卡站联名发布“平衡新生”
  20. 20180620学习记录(根据情态动词将文本归类,美国总统演说中‘American’和‘citizen’出现次数的变化

热门文章

  1. 什么是小端模式,什么是大端模式
  2. 正则表达式及bash脚本(二)
  3. 6位中国民间艺术家在美国纽约法拉盛图书馆庆猪年
  4. [Python]使用折线图统计水果店一周内销售额的变化曲线
  5. 3.1 Python 字符串类型常用操作及内置方法
  6. 轻型社交圈系统交友及时聊天集成商城/语音聊天派对/交友广场,仿小红书
  7. MATLAB点云处理(十二):欧式聚类分割(pcsegdist)
  8. 解决mac下的Sourcetree每次拉取提交都需要输入密码
  9. Untiy 帧同步的探索之路一 位置帧同步
  10. 计算机组装要哪些硬件,电脑配件,教您电脑组装需要哪些配件