WordPress教程

WordPress前端自制拖放区域上传文件的轮子

阿里云

上个月写过一篇 WordPress 通过 Rest API 自定义附件上传接口,那篇文章主要介绍了如何打通前后端,利用 Rest API 保存“抓取”已知 URL 的文件。不过在更多的情况下,我们还是需要通过自己的表单上传文件。正好这个月有个项目,有个表单需要拖放文件到指定区域里,提交表单的时候上传文件。如果我用 Gravity Forms 给的文件上传域,它只有原生的点击选取本地的文件组件,并没有拖放选取文件的组件,所以这里就需要造一个轮子了。先说结果,最后实现出来是这样子的:

文件拖到区域上方,区域会变色;拖入后区域内显示文件名,判断文件格式和尺寸是否合规;点击清除,会重置区域。

HTML 结构

这里面#pro_document 这个就是真实的用来上传的输入项,把它隐藏,通过 JS 使.js-drag 整个区域可以接受拖放文件进来

也想出现在这里?联系我们
创客主机
  1. <div class="dragarea js-drag">
  2. <p>DRAG A FILE HERE,<br/>OR</p>
  3. <span class="js-drag-fileinfo"></span>
  4. <a href="###" class="button">Choose a File</a>
  5. <a href="###" class="js-drag-clear">x Clear</a>
  6. <input type="file" value="" name="pro_document" id="pro_document" placeholder="" class="js-drag-file" />
  7. </div>

JS 部分

  1. $(function(){
  2. 	//允许的格式
  3. 	var fileTypeArray = ['JPG','PNG','CAD','RAR','ZIP'];
  4. 	function FileListItems (files) {
  5. 		var b = new ClipboardEvent("").clipboardData || new DataTransfer()
  6. 		for (var i = 0, len = files.length; i<len; i++) b.items.add(files[i])
  7. 		return b.files
  8. 	}
  9. 	function FileVerify(file){
  10. 		if(file.size > 2*1024*1024){
  11. 			alert("文件不能大于2M");
  12. 			return false;
  13. 		}else if(file.size <= 0){
  14. 			alert("文件大小不能小于0");
  15. 			return false;
  16. 		}else{
  17. 			var arr = file.name.split('.');
  18. 		    var suffix = arr[arr.length-1].toUpperCase();
  19. 		    if(fileTypeArray.includes(suffix)){
  20. 				return true;
  21. 		    }else {
  22. 		        alert("暂时不支持" + suffix + "格式文件");
  23. 		        return false;
  24. 		    }
  25. 		}
  26.  
  27. 	}
  28.  
  29. 	var dragElement = $('.js-drag');
  30. 	//拖入结束
  31. 	$('.js-drag').on("drop", function(event){
  32. 	    event.preventDefault();
  33. 	    event.stopPropagation();
  34.  
  35. 	    var fileFieldDOM = $(this).find('.js-drag-file')[0];
  36. 	    var fileFieldDisplay = $(this).find('.js-drag-fileinfo');
  37. 	    console.log(event);
  38.  
  39. 	    event.dataTransfer = event.originalEvent.dataTransfer;
  40. 		var firstFile = event.dataTransfer.files[0];
  41. 		var firstFileArr = [ firstFile ];
  42. 		var newfileList = new FileListItems(firstFileArr);
  43.  
  44. 		if( FileVerify(firstFile)){
  45. 			console.log("file verified: "+ firstFile.name);
  46. 			console.log(firstFile);
  47. 			//.filled样式追加后,区域变成已添加文件的状态
  48. 			$(this).addClass("filled")
  49. 			fileFieldDisplay.html("selected file:</br>" + firstFile.name);
  50. 			fileFieldDOM.files= newfileList;
  51. 		}
  52. 		$(this).removeClass("dragenter");
  53.  
  54. 	});
  55. 	//点击开启选择文件窗口
  56. 	$('.js-drag').on("click", function(event){
  57. 		var fileFieldDOM = $(this).find('.js-drag-file')[0];
  58. 		var fileFieldDisplay = $(this).find('.js-drag-fileinfo');
  59. 		fileFieldDOM.click();
  60. 	});
  61. 	//拖入
  62. 	$('.js-drag').on("dragenter", function(event){
  63. 		event.preventDefault();
  64. 		event.stopPropagation();
  65. 		//console.log('dragenter');
  66. 		//增加样式.dragenter,其实就是一个背景色,以提示用户有文件正在拖进来
  67. 		$(this).addClass("dragenter");
  68. 	});
  69. 	//文件正在区域上方
  70. 	$('.js-drag').on("dragover", function(event){
  71. 	    event.preventDefault();
  72. 	    event.stopPropagation();
  73. 	});
  74. 	//拖离
  75. 	$('.js-drag').on("dragleave", function(event){
  76. 		//console.log('dragleave');
  77. 		$(this).removeClass("dragenter");
  78. 	});
  79. 	//所选的文件改变
  80. 	$('.js-drag-file').on("change",function(event){
  81. 		var firstFile = $(this)[0].files[0];
  82. 		if( FileVerify(firstFile)){
  83. 			console.log("file verified: "+ firstFile.name);
  84. 			console.log(firstFile);
  85. 			$(this).parent().addClass("filled");
  86. 			$(this).siblings('.js-drag-fileinfo').html("selected file:</br>" + firstFile.name);
  87.  
  88. 		}else{
  89. 			$(this)[0].files=new FileListItems("");
  90. 		}
  91. 	});
  92. 	//清空选定的文件
  93. 	$('.js-drag-clear').on("click",function(event){
  94. 		event.preventDefault();
  95. 	    event.stopPropagation();
  96. 		$(this).siblings('.js-drag-file')[0].files=new FileListItems("");
  97. 		$(this).siblings('.js-drag-fileinfo').html("");
  98. 		$(this).parent().removeClass("filled");
  99. 	});
  100.  
  101. });

CSS 样式

  1. .form-regular .dragarea{
  2. 	box-sizing: border-box;
  3. 	width: 100%;
  4. 	height: 150px;
  5. 	background:#f7f7f7;
  6. 	border-radius: 6px;
  7. 	border:2px dashed #d3d3d3;
  8. 	display: flex;
  9. 	flex-direction: column;
  10. 	flex-wrap: nowrap;
  11. 	justify-content:center;
  12. 	font-size: 13px;
  13. 	text-align: center;
  14. }
  15. .form-regular .dragarea.dragenter{
  16. 	background:#dedede;
  17. }
  18. .form-regular .dragarea p{
  19. 	font-size: 13px;
  20. 	margin:0 auto 6px auto;
  21. 	line-height: 1.3;
  22. }
  23. .form-regular .dragarea .button{
  24. 	margin:0 auto;
  25. }
  26. .js-drag-file{
  27. 	overflow: hidden;
  28. 	width: 1px;
  29. 	height: 1px;
  30. 	opacity: 0;
  31. }
  32. .js-drag .js-drag-fileinfo,
  33. .js-drag .js-drag-clear{
  34. 	display: none;
  35. 	color: #000;
  36. 	font-weight: 400;
  37. 	font-size: 15px;
  38. 	line-height: 1.5;
  39. }
  40. .js-drag .js-drag-clear{
  41. 	text-transform: uppercase;
  42. 	font-size: 13px;
  43. 	width: 80px;
  44. 	margin: 10px auto 0 auto;
  45. }
  46. .js-drag .js-drag-fileinfo:first-line{
  47. 	color: #b2b2b2;
  48. }
  49. .js-drag.filled .js-drag-fileinfo,
  50. .js-drag.filled .js-drag-clear{
  51. 	display: block;
  52. }
  53. .js-drag.filled p,
  54. .js-drag.filled .button{
  55. 	display: none;
  56. }

表单处理

还是通过 Rest API 保存文件,保存后获取到文件地址以做后续其他工作。注意要上传文件就必须要身份验证,身份验证的接口上一篇文章也说了,先安装Basic-Auth插件。

  1. //通过Rest API保存文件
  2. function brain_wp_api_upload( $filedata ){
  3. 	$file_url = $filedata['tmp_name'];
  4. 	$file_content=file_get_contents($file_url);
  5. 	$url_api = site_url("/wp-json/wp/v2/media/");
  6. 	$file_name = $filedata['name'];
  7. 	$ch = curl_init();
  8. 	curl_setopt($ch, CURLOPT_URL,            $url_api );
  9. 	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
  10. 	curl_setopt($ch, CURLOPT_POST,           1 );
  11. 	curl_setopt($ch, CURLOPT_POSTFIELDS,     $file_content); 
  12. 	curl_setopt($ch, CURLOPT_HTTPHEADER,     array(
  13. 		'content-disposition: attachment; filename="'.$file_name.'"',
  14. 		'authorization: Basic ' . base64_encode('username:password')
  15. 		//'authorization: ' . $_SERVER['HTTP_AUTHORIZATION']
  16. 		)
  17. 	); 
  18. 	$result=curl_exec($ch);
  19. 	if(json_decode($result)->id){
  20. 		return json_decode($result)->guid->rendered ;
  21. 	}else{
  22. 		return json_decode($result)->data->status . " " .json_decode($result)->message;
  23. 	}
  24. }
  25. //获取提交的内容,并调用brain_wp_api_upload这个函数返回的文件URL
  26. if(!empty($_FILES['pro_document']['tmp_name'])){
  27. 	$pro_document = brain_wp_api_upload( $_FILES['pro_document'] );
  28. 	echo "pro_document: ".$pro_document. "<br/>";
  29. }else{
  30. 	$pro_document = "";
  31. }
  32. ...
  33. //后续的一系列处理

最后,因为是对外使用的上传功能,还需要单独开设个子目录上传文件单独保存,以免和文章等其他附件混淆在一起。用 upload_dir 这个钩子,通过识别上传的用户 id 临时修改目录:

  1. add_filter( 'upload_dir', 'brain_change_upload_dir_ct' );
  2. function brain_change_upload_dir_ct( $upload ) {
  3. 	if( get_current_user_id()== 2 ){//basic认证的用户id
  4. 		$upload['subdir'] = '/subfolder'; //子目录名
  5. 		$upload['path'] = $upload['basedir'] . $upload['subdir'];
  6. 		$upload['url']  = $upload['baseurl'] . $upload['subdir'];
  7. 	}
  8. 	return $upload;
  9. }

其实后来找了下 Gravity Forms 也有实现类似功能的外挂,比如 这个,前端是原生的也有,比如 这个。可惜这些都不完全符合我的应用场景。在提交表单之前,我只想让用户先选定本地文件,而并不是立即上传,我表单里还有很多其他选项以及用了验证码系统,在表单提交后通过验证,再上传文件,这样可以避免网站被滥传一些无用的文件甚至是木马。

WordPress 前端自制拖放区域上传文件的轮子

已有 251 人购买
查看演示升级 VIP立刻购买

收藏
(0)

发表回复

热销模板

Ashade - 作品展示摄影相册WordPress汉化主题
LensNews

本站承接 WordPress / PbootCMS / DedeCMS 等
系统建站、仿站、开发、定制等业务!