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

本站所有文章均为博主人工写作,绝无AI辅助成分,请放心参阅。

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

先说结果,最后实现出来是这样子的:
WordPress前端,自制拖放区域上传文件的轮子

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



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

1
2
3
4
5
6
7
<div class="dragarea js-drag">
<p>DRAG A FILE HERE,<br/>OR</p>
<span class="js-drag-fileinfo"></span>
<a href="###" class="button">Choose a File</a>
<a href="###" class="js-drag-clear">x Clear</a>
<input type="file" value="" name="pro_document" id="pro_document" placeholder="" class="js-drag-file" />
</div>

JS部分:

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

样式表:

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

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

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

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

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

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

本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.brain1981.com/2263.html。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

关注我们的微信公众号-JennyStudio 本站记录了近几年的工作中遇到的一些技术问题和解决过程,“作品集”还收录了本人的大部分作品展示。除了本博客外,我们的工作室网站 – JennyStudio,内有更多作品回顾和展示。
您也可以扫描左边的二维码,关注我们的微信公众号,在微信上查看我们的案例。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注