适用于各浏览器支持图片预览,无刷新异步批量上传js插件

阅读: 评论:0

适用于各浏览器支持图片预览,无刷新异步批量上传js插件

适用于各浏览器支持图片预览,无刷新异步批量上传js插件

注:在下一篇文章中,已经对这个插件做了更好的优化,如有需要的童鞋可以看下一篇

文件上传无疑是web应用中一个非常常用的功能,不管是PHP、jsp还是aspx、mvc等都会需要文件上传,但是众所周知当使用自带的文件上传功能时总会出现页面刷新的情况。当然现在有了html5这个好东西,我们可以调用它的新的api来做文件的异步上传。但是非常可惜,这个新的api并非每个浏览器都支持。



如果你会flash这当然很好,你可以自己写一个flash的上传插件来支持上传,不过本文不会对flash这个技术做任何的讨论。


好了言归正传,我们还是来讨论下只使用js的情况下如何才能异步无刷新的上传文件,首先估计大家会想到ajax,不过很不幸在目前没有html5支持的浏览器中使用ajax上传文件是不行的,而在国内使用支持html5浏览器的用户还不是绝大多数,那么这种方案只能放弃。


还有没有办法喃?当然有那就是使用iframe,看下面的html代码:

<body><form action="WebForm1.aspx" target="dynamic_creation_upload_iframe" method="POST" enctype="multipart/form-data"><input type="file" name="upload1" /></form><iframe name="dynamic_creation_upload_iframe"></iframe>
</body>
这是一段我们经常使用的上传代码,如果你使用的是asp控件,它最终也会生成这样的html代码,其中的enctype就是指定需要上传文件的属性(action和method属性就不需要解释了吧)。不过在这个form上我添加了一个target属性,并且指定了它的值为下面那个iframe的name属性的值,这是为什么?其实很简单,就是当你提交这个form时(这样就开始了文件上传),等服务端接收到文件并保存成功响应客户端时,将响应的内容直接在这个iframe中刷新,这样这个iframe就起到了一个隔离的作用,此时我们只需要在这个iframe上绑定一个onload事件,那么当它刷新时这个事件将被触发,呵呵 我们就可以在这个load事件中做事情了(例如:在load的时候获取服务端响应的结果,从而得知上传是否成功)


有了这个思路事情就好办了,以下是根据这种思路构建的一个js插件

/*无刷新异步上传插件2013-10-16 Devotion Created
*/
(function ($) {var defaultSettings = {url: "",                                 //上传地址buttonFeature: true,                    //true:点击按钮时仅选择文件; false:选择完文件后立即上传fileSuffixs: ["jpg", "png"],             //允许上传的文件后缀名列表errorText: "不能上传后缀为 {0} 的文件!", //错误提示文本,其中{0}将会被上传文件的后缀名替换onCheckUpload: function (text) { //上传时检查文件后缀名不包含在fileSuffixs属性中时触发的回调函数,(text为错误提示文本)alert(text);},onComplete: function (msg) { //上传完成后的回调函数[不管成功或失败,它都将被触发](msg为服务端的返回字符串)},onChosen: function (file, obj) { //选择文件后的回调函数,(file为选中文件的本地路径;obj为当前的上传控件实例)//alert(file);},maximumFilesUpload: 5,//最大文件上传数(当此属性大于1时,buttonFeature属性只能为true)onSubmitHandle: function (uploadFileNumber) { //提交上传时的回调函数,uploadFileNumber为当前上传的文件数量//在此回调中返回false上传提交将被阻止return true;},onSameFilesHandle: function (file) { //当重复选择相同的文件时触发//在此回调中返回false当前选择的文件将从上传队列中取消return true;},perviewImageElementId: "",//用于预览上传图片的元素id(请传入一个div元素的id)perviewImgStyle: null//用于设置图片预览时的样式(可不设置,在不设置的情况下多文件上传时只能显示一张图片),如{ width: '100px', height: '100px', border: '1px solid #ebebeb' }};$.fn.uploadFile = function (settings) {settings = $.extend({}, defaultSettings, settings || {});if (settings.perviewImageElementId) {//设置图片预览元素的必须样式if (!settings.perviewImgStyle) {var perviewImg = ElementById(settings.perviewImageElementId);perviewImg.style.overflow = "hidden";}}return this.each(function () {var self = $(this);var upload = new UploadAssist(settings);ateIframe(this);//绑定当前按钮点击事件self.bind("click", function (e) {upload.chooseFile();});//将上传辅助类的实例,存放到当前对象中,方便外部获取self.data("uploadFileData", upload);//创建的iframe中的那个iframe,它的事件需要延迟绑定window.setTimeout(function () {//为创建的iframe内部的iframe绑定load事件$(IframeContentDocument().body.lastChild).on("load", function () {var dcmt = InsideIframeContentDocument();if (dcmt.body.innerHTML) {if (Complete) {Complete(dcmt.body.innerHTML);}dcmt.body.innerHTML = "";}});}, 100);});};
})(jQuery);//上传辅助类
function UploadAssist(settings) {//保存设置this.settings = settings;//已选择文件的路径集合this.choseFilePath = [];//创建的iframe唯一名称this.iframeName = "upload" + InputFileName();return this;
}UploadAssist.prototype = {//辅助类构造器constructor: UploadAssist,//创建iframecreateIframe: function (/*插件中指定的dom对象*/elem) {var html = "<html>"+ "<head>"+ "<title>upload</title>"+ "<script>"+ "function getDCMT(){return window.frames['dynamic_creation_upload_iframe'].document;}"+ "</" + "script>"+ "</head>"+ "<body>"+ "<form method='post' target='dynamic_creation_upload_iframe' enctype='multipart/form-data' action='" + this.settings.url + "'>"+ "</form>"+ "<iframe name='dynamic_creation_upload_iframe'></iframe>"+ "</body>"+ "</html>";this.iframe = $("<iframe name='" + this.iframeName + "'></iframe>")[0];this.iframe.style.width = "0px";this.iframe.style.height = "0px";this.iframe.style.border = "0px solid #fff";this.iframe.style.margin = "0px";elem.parentNode.insertBefore(this.iframe, elem);var iframeDocument = IframeContentDocument();iframeDocument.write(html);},//获取上传控件名称getInputFileName: function () {return (new Date()).valueOf();},//创建上传控件到创建的iframe中createInputFile: function () {var that = this;var dcmt = IframeContentDocument();var input = ateElement("input");pe = "file";input.setAttribute("name", "input" + InputFileName());hange = function () {var fileSuf = this.value.substring(this.value.lastIndexOf(".") + 1);//检查是否为允许上传的文件if (!that.checkFileIsUpload(fileSuf, that.settings.fileSuffixs)) {CheckUpload(place("{0}", fileSuf));return;}//选中后的回调Chosen(this.value, this);if (that.checkFileIsExist(this.value)) {//保存已经选择的文件路径that.choseFilePath.push({ "name": this.name, "value": this.value });var status = SameFilesHandle(this.value);if (typeof status === "boolean" && !status) {veFile(this.value);return;}} else {//保存已经选择的文件路径that.choseFilePath.push({ "name": this.name, "value": this.value });}//是否开启了图片预览if (that.settings.perviewImageElementId) {if (!that.settings.perviewImgStyle) {perviewImage.beginPerview(this, that.settings.perviewImageElementId);} else {var ul = PerviewRegion(that.settings.perviewImageElementId);var main = atePreviewElement(this.value);var li = ateElement("li");//li.style.float = "left";if ($.browser.msie) {li.style.styleFloat = "left";}else {li.style.cssFloat = "left";}li.style.margin = "5px";li.appendChild(main);ul.appendChild(li);var div = $(main).children("div").get(0);$(main).children("img").hover(function () {this.src = perviewImage.closeImg.after;}, function () {this.src = perviewImage.closeImg.before;}).click(function () {veFile($(this).attr("filepath"));$(this).parents("li").remove("li");});perviewImage.beginPerview(this, div, dcmt);}}if (!that.settings.buttonFeature) {that.submitUpload();}};dcmt.forms[0].appendChild(input);return input;},//获取创建的iframe中的document对象getIframeContentDocument: function () {return tDocument || tWindow.document;},//获取创建的iframe所在的window对象getIframeWindow: function () {return tWindow || tDocument.parentWindow;},//获取创建的iframe内部iframe的document对象getInsideIframeContentDocument: function () {IframeWindow().getDCMT();},//获取上传input控件getUploadInput: function () {var inputs = IframeContentDocument().getElementsByTagName("input");var len = inputs.length;if (len > 0) {if (!inputs[len - 1].value) {return inputs[len - 1];} else {ateInputFile();}}ateInputFile();},//forEach迭代函数forEach: function (/*数组*/arr, /*代理函数*/fn) {var len = arr.length;for (var i = 0; i < len; i++) {var tmp = arr[i];if (fn.call(tmp, i, tmp) == false) {break;}}},//提交上传submitUpload: function () {var status = SubmitHandle(this.choseFilePath.length);if (typeof status === "boolean") {if (!status) {return;}}this.clearedNotChooseFile();var dcmt = IframeContentDocument();dcmt.forms[0].submit();},//检查文件是否可以上传checkFileIsUpload: function (fileSuf, suffixs) {var status = false;this.forEach(suffixs, function (i, n) {if (LowerCase() === n.toLowerCase()) {status = true;return false;}});return status;},//检查上传的文件是否已经存在上传队列中checkFileIsExist: function (/*当前上传的文件*/file) {var status = false;this.forEach(this.choseFilePath, function (i, n) {if (n.value == file) {status = true;return false;}});return status;},//清除未选择文件的上传控件clearedNotChooseFile: function () {var files = IframeContentDocument().getElementsByTagName("input");this.forEach(files, function (i, n) {if (!n.value) {veChild(n);return false;}});},//将指定上传的文件从上传队列中删除removeFile: function (file) {var that = this;var files = IframeContentDocument().getElementsByTagName("input");this.forEach(this.choseFilePath, function (i, n) {if (n.value == file) {that.forEach(files, function (j, m) {if (m.name == n.name) {veChild(m);return false;}});that.choseFilePath.splice(i, 1);return false;}});},//清空上传队列clearUploadQueue: function () {this.choseFilePath.length = IframeContentDocument().forms[0].innerHTML = "";},//选择上传文件chooseFile: function () {var uploadfile;if (this.choseFilePath.length == this.settings.maximumFilesUpload) {if (this.settings.maximumFilesUpload <= 1) {this.choseFilePath.length = 0;var files = IframeContentDocument().getElementsByTagName("input");if (!files.length) {uploadfile = UploadInput();$(uploadfile).click();return;} else {uploadfile = files[0];$(uploadfile).click();return;}} else {return;}}uploadfile = UploadInput();$(uploadfile).click();}
};//图片预览操作
var perviewImage = {timers: [],closeImg: {before: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAOVSURBVHjaYtTUdGdAA4K/fv3U+Pv3rw+QLfT//3+Gf//+vWNiYtjCwsJyAyj2HiT2//8/sGKAAGJB1gkU9Pj581eNnJyctaamMgM/Py8DIyMDw+fPXxlu3rxfdfPmjaPMzIwtTEzMO2B6AAKIBaH5fw4LC1tHeHgQt7u7PYOOjhIDNzcb2IBfv/4x3LjxiGHr1n3WK1duXPPx45sKJiamKSB9AAHECPIC0GZ3ZmbWzQkJkazu7rYMLCyMDD9//gYZCzWcgYGVlRUozsxw9Oh5hv7+Gb8/fXrnC+TvBAggZhERZb7fv3/PdnCwV7C3twT69w+DlpYcw5s3HxkeP34FdP53IPsDg6qqNAMXFxvQIA4GoGXMFy9eVgK6eg1AADH9/ftbW0hIxEpFRQms0MBAlYGDg51BQ0OegZ2dneH58zdAMRUGKSlhBnFxQYY7dx4CvfSHQVBQyAqkFyCAmIWEFDOlpaVtgQHH8O7dB4aXLz8wqKjIMHBysoE1SUqKMCgoSIC90te3lGHNmu0MDx8+Yfjx4xvQmz9eAgQQCzAwhBiBIfX69RugwC+GR4+eAl3yliEx0Y+Bl5eDQU5ODBwG3d0LGdau3QH0AjMwLFiBruQEBjCTEEAAsYBC+du3HwxPnjxnAMY90JCfoLBlePXqLdAAabDNX778AHvl37+/QP9DYubfP0haAAggJlAi+fr1M8Pbt2+Bml4z8PBwMxQURDMoK0uDbf78+QfYJY2N2Qy2thZA//8CGsIMtOg70MI/7wACiAkYkluAfmH48+cPMOHwMbS1FTJoaspB/bwYqHE6w4cP3xn4+DgYWltzgAGqywCMNbABQBdsAQggJmAsX/3+/esxkPNAoX7jxgNQomKYMWMtw65dRxkuXLjGMHHiEobv338x3Lv3DEhDLAO6+hjQq1cBAohRWdkOqOGvOwcHz2Z1dU1WcXEJBgkJYYbbtx+AExIogH/9+s2gra0KDOgPwLTxmOHKlfO/v3z55AtM0jsBAggYjfKg0Lz769eP958/f7FnZ2djAyYUBhERQWBUcgLDhItBWFiY4f37j8AYeshw/frVr1++fCwFal4O8iZAAIENAKdpRoZTwLg99/Llc8VPnz7JffnyFWQwMAa+Mdy/fw+YmW4w3Lp1/eiPH19zgJqXwfIQQACBvQDNiaBsC/K/IDCQNICKfNjYWIVAYQNMH++AIb4FGPrg7IycgwECDADIUZC5UWvTuwAAAABJRU5ErkJggg==",after: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH1wwbFhkQHxvdFgAAArpJREFUeNplz1to1QUAx/HP/3/O2c7OrudsR8vmamOL2hw5LaQHgxKCLvQSRVgPFhJKo4cyMsmxKNQgfOuhfKxICQTpocvAIFhai/WSTNIcnK3pbu12tnO2cwsfbZ+H3+MXfgGbfURDgn0xHgiIFskUuPgOE/7njsBxahsYqAnDN1p3765N9/QIYzGL4+Myw8PlbC53fp23j5HZFBhgSxPft27f3tfX36+ure2O+sbKiitnzrg2MjK/xjNH+RUCeJbo41xsSyb3PtR/WLQuLhIGVAJKlEsUSyUBrp8966+xsdkl+o7zTwiP8mqSvffu6ZMLs+565YAVWRvL1xSWrpufvmHr/v3y1dVu30pHIuk4pxCEiCQ4nIyEYk15heakmm3bdR06Zrq0LjM3ruPNI+o7O8V7uy1NTkjV10vw4ns0Rw6Q7uCTdLwS1LfMyM+Mytxa0r73aVse2adp52Oau7pd/eGCq4MHNUxPKc4sy1dEylwOt3FPNUH09gTrWhILSr+d9N3pQfGGpHRXjz9/+tHoqRe0t8yqasyK1lKNKlrDdYpVCEqUixRLLBZTep98DkD7zofFO3pVGqlqJlJDDDEK4TkmQlbXc+QWGZ9P2TMwpHXHLpnL541+dVRtMuWp00NmGncpxCkUCLDGWDjJWp6LG0XmJtn6xOu2PrjLzUvn3fr6JdVXP3btmyNqGlN2vHbC/Dxry5SZ+pTfIyh3MN3Jyxt54cKVYYXVKZPn3peIFkTK5G5ckp34W+bLE7IjeWGOOT78gp8DQPwzBtt5dymkkqTmbuIpYnUEAblZsldIrLLB0AGeX2QlAEDD5xy7n7eWia2GlKsREhaIb9CEZS58wKFRplGJAGD9W36JMXwf9cmKdF1RIlGgrmS1zOU/GDjIyZv8iwoENguRQKqblnqiI8yUWUAWJQD4D4Cg/5i7WltRAAAAAElFTkSuQmCC"},//获取预览元素getElementObject: function (elem) {if (deType && deType === 1) {return elem;} else {ElementById(elem);}},//开始图片预览beginPerview: function (/*文件上传控件实例*/file, /*需要显示的元素id或元素实例*/perviewElemId,dcmt) {for (var t = 0; t < this.timers.length; t++) {window.clearInterval(this.timers[t]);}this.timers.length = 0;var preview_div = ElementObject(perviewElemId);var MAXWIDTH = preview_div.clientWidth;var MAXHEIGHT = preview_div.clientHeight;if (file.files && file.files[0]) { //此处为Firefox,Chrome以及IE10的操作preview_div.innerHTML = "";var img = ateElement("img");preview_div.appendChild(img);img.style.visibility = "hidden";load = function () {var rect = perviewImage.clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight);img.style.width = rect.width + 'px';img.style.height = rect.height + 'px';img.style.marginLeft = rect.left + 'px';img.style.marginTop = p + 'px';img.style.visibility = "visible";}var reader = new FileReader();load = function (evt) {img.src = sult;}adAsDataURL(file.files[0]);}else {//此处为IE6,7,8,9的操作file.select();var src = ateRange().text;var div_sFilter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='" + src + "')";var img_sFilter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src='" + src + "')";preview_div.innerHTML = "";var img = ateElement("div");preview_div.appendChild(img);img.style.filter = img_sFilter;img.style.visibility = "hidden";img.style.width = "100%";img.style.height = "100%";function setImageDisplay() {var rect = perviewImage.clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight);preview_div.innerHTML = "";var div = ateElement("div");div.style.width = rect.width + 'px';div.style.height = rect.height + 'px';div.style.marginLeft = rect.left + 'px';div.style.marginTop = p + 'px';div.style.filter = div_sFilter;preview_div.appendChild(div);}//图片加载计数var tally = 0;var timer = window.setInterval(function () {if (img.offsetHeight != MAXHEIGHT) {window.clearInterval(timer);setImageDisplay()} else {tally++;}//如果超过两秒钟图片还不能加载,就停止当前的轮询if (tally > 20) {window.clearInterval(timer);setImageDisplay()}}, 100);this.timers.push(timer);}},//按比例缩放图片clacImgZoomParam: function (maxWidth, maxHeight, width, height) {var param = { width: width, height: height };if (width > maxWidth || height > maxHeight) {var rateWidth = width / maxWidth;var rateHeight = height / maxHeight;if (rateWidth > rateHeight) {param.width = maxWidth;param.height = und(height / rateWidth);} else {param.width = und(width / rateHeight);param.height = maxHeight;}}param.left = und((maxWidth - param.width) / 2);p = und((maxHeight - param.height) / 2);return param;},//创建预览元素createPreviewElement: function (/*上传时的文件名*/file, /*预览时的样式*/style) {style = style || { width: '100px', height: '100px', border: '1px solid #ebebeb' };var img = ateElement("div");img.title = file;img.style.overflow = "hidden";for (var s in style) {img.style[s] = style[s];}var text = ateElement("div");text.style.width = style.width;text.style.overflow = "hidden";Overflow = "ellipsis";text.style.whiteSpace = "nowrap";text.innerHTML = file;var top = 0 - window.parseInt(style.width) - 15;var right = 0 - window.parseInt(style.width) + 14;var close = ateElement("img");close.setAttribute("filepath", file);close.src = this.closeImg.before;close.style.position = "relative";p = top + "px";close.style.right = right + "px";close.style.cursor = "pointer";var main = ateElement("div");main.appendChild(img);main.appendChild(text);main.appendChild(close);return main;},//获取预览区域getPerviewRegion: function (elem) {var perview = $(ElementObject(elem));if (!perview.find("ul").length) {var ul = ateElement("ul");ul.style.listStyleType = "none";ul.style.margin = "0px";ul.style.padding = "0px";var div = ateElement("div");div.style.clear = "both";perview.append(ul).append(div);return ul;} else {return perview.children("ul").get(0);}}
}


看看这个插件中的那个createIframe方法,对它做一点解释
//创建iframecreateIframe: function (/*插件中指定的dom对象*/elem) {var html = "<html>"+ "<head>"+ "<title>upload</title>"+ "<script>"+ "function getDCMT(){return window.frames['dynamic_creation_upload_iframe'].document;}"+ "</" + "script>"+ "</head>"+ "<body>"+ "<form method='post' target='dynamic_creation_upload_iframe' enctype='multipart/form-data' action='" + this.settings.url + "'>"+ "</form>"+ "<iframe name='dynamic_creation_upload_iframe'></iframe>"+ "</body>"+ "</html>";this.iframe = $("<iframe name='" + this.iframeName + "'></iframe>")[0];this.iframe.style.width = "0px";this.iframe.style.height = "0px";this.iframe.style.display = "none";elem.parentNode.insertBefore(this.iframe, elem);var iframeDocument = IframeContentDocument();iframeDocument.write(html);},
大家应该都看到了这个方法中有一个html变量,它保存的其实就是文章开头的那段html。在这段html中我添加了一个function名为getDCMT的函数,这是为了获取名为dynamic_creation_upload_iframe的iframe所在的document对象。在form中我也去掉了文件上传的input控件,这是因为我将动态创建input控件到这个form中,并且我会将这段html使用js的方式把它添加到一个动态创建的iframe中。为什么要这样呢?呵呵 我想聪明的你一定会明白的!


好了插件做好了,我们如何来使用呢?


首先 将那段插件js代码保存为notRefreshFilesUpload.js的文件,方便在页面上的引用,然后构建包含如下结构的page

<!DOCTYPE html>
<html xmlns="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>files upload</title><script src="Scripts/jquery-1.7.1.min.js"></script><script src="Scripts/notRefreshFilesUpload.js"></script><script>$(function () {var btn = $("#Button1");btn.uploadFile({url: "WebForm1.aspx",fileSuffixs: ["jpg", "png", "gif"],buttonFeature: true,errorText: "{0}",maximumFilesUpload: 5,//最大文件上传数onComplete: function (msg) {$("#testdiv").html(msg);},perviewImageElementId: "fileList", //设置预览图片的元素idperviewImgStyle: { width: '100px', height: '100px', border: '1px solid #ebebeb' }//设置预览图片的样式});var upload = btn.data("uploadFileData");$("#files").click(function () {upload.submitUpload();});});</script></head><body><div style="width: 400px; height: 300px; float:left"><input id="Button1" type="button" value="选择文件" /><input id="files" type="button" value="上传" /><div id="fileList" style="margin-top: 10px; padding-top:10px; border-top:1px solid #C0C0C0;font-size: 13px; width:400px"></div></div><div id="testdiv"></div></body>
</html>


上面的代码中已经包含了图片预览的功能,使用非常简单我就不多言了,只需要给定用于显示图片的元素id即可,一般用div作为图片预览的元素。

这是服务端的方法,在这里我使用了aspx作为服务端的接收方式,当然你可以换成其他任何语言或形式作为服务端的处理方案(可以是php、jsp、mvc等等)
    public partial class WebForm1 : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){List<string> filenames = new List<string>();HttpFileCollection files = Request.Files;for (int i = 0; i < files.Count; i++){filenames.Add(files[i].FileName);}Response.Write(string.Join("___", filenames));Response.Flush();Response.End();}}
服务端代码为多文件上传处理的方式,呵呵 也就是说这个插件也是支持多文件上传的,在服务端的代码中我仅仅返回了上传文件的名称作为对客户端的响应,当然你可以返回任何你希望的形式,你只需要在客户端用js做相应处理即可(即在插件的complete这个回调中处理响应,它其中的msg回调参数将把服务端的响应结果回传给你)。


好了 一个兼容各种浏览器,并且支持图片预览和无刷新异步上传的纯js插件就搞定了。上个图看看效果


本文发布于:2024-01-30 05:35:55,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170656415919592.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:适用于   批量   插件   浏览器   上传
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23