0%

js | 上传图片

之所以,有这样一篇博文,主要是,我的需求如下。

  • input 标签不好看,我想隐藏它
  • 不使用 form 标签,而是根据按钮,来选择性的提交内容,增大灵活性
  • 涉及文本和图片上传
  • 上传图片的前端展示

开发环境


  • js ES6
  • python + flask

前端


标签展示

1
2
3
4
5
6
7
8
9
<input type="text" class="form-control" id="title" aria-describedby="basic-addon3">
<input type="file" class="form-control-file" id="real_upload" style="display:none">
<div class="row text-center" style="display: none" id="canvas-image">
<div class="canvas-box" style="width: 100%;margin-top: 30px">
<canvas id="cvs" style="width: 100%;">对不起,该浏览器不支持标注操作,请使用谷歌浏览器!</canvas>
</div>
</div>
<button type="button" id="upload">上传图片</button>
<button type="button" style="margin-left: 30px" id="submit">提交</button>

ps: 实际标签不可能这么排列,这里只是把功能讲清楚。

上面,输入框是显示的,文件上传是不显示的,可以用一个好看的标签来代替。上面的就是用 id="upload" 的标签来替代。

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
import axios from 'axios';

let canvas = document.getElementById("cvs");
let ctx = canvas.getContext("2d");

// 将图片绘制到canvas
const renderImageToCanvas = (image, size, ctx) => {
ctx.drawImage(image, 0, 0, size[0], size[1]);
}

// 点击上传图片控件的时候,相当于点击了真正的上传图片的控件。
$("#upload").click(function () {
$("#real_upload").click();
})

$("#real_upload").change(function () {
let reads = new FileReader();
let f = $(this).get(0).files[0]; // 得到第一个文件
reads.readAsDataURL(f);
reads.onload = function (e) {
$("#upload").attr("style", "display:none");
var data = e.target.result;
var image = new Image();
image.src = data;
image.onload = () => { // 用 canvas 绘制图片
$("#canvas-image").attr("style", "display:block");
let size = canvas.getBoundingClientRect(); // 获取 canvas 的实际大小
let key = size.width / image.width; // 根据所显示宽度来调整自适应调整图片大小
canvas.setAttribute("width", parseInt(image.width * key) + "px");
canvas.setAttribute("height", parseInt(image.height * key) + "px");
renderImageToCanvas(image, [image.width * key, image.height * key], ctx);
}
};
});

// 上传相关
// 在这里不要关心具体的参数,而是要关心最核心的上传方法
$("#submit").click((e) => {
let title = document.getElementById("title").value;
let size = canvas.getBoundingClientRect();
let width = size.width;
let height = size.height;
if (file) {
let formData = new FormData();
formData.append('width', width);
formData.append('height', height);
formData.append('image', file);
formData.append('title', title);
axios.post(api.manage + "/v1/add_points", formData).then((response) => {
if (response.data.code === 1) {
alert("success")
} else if (response.data.code === 0) {
alert("fail")
}
window.location.reload();
});
}
});

根据 canvas 大小,自适应前端显示图片如下:


后端


这里不张贴具体的细节了,只是大概贴一下,很容易理解。

main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@app.route("/dang/v1/add_points", methods=['POST'])
def add_points():
status = infos.add_points(request)
if status:
result = {
"code": Code.success,
"msg": "success",
"data": ""
}
else:
result = {
"code": Code.fail,
"msg": "fail",
"data": ""
}
return jsonify(result)

info.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def add_points(self, request):
# 图片重命名
m = hashlib.md5()
m.update(str(time.time()).encode("UTF-8"))
f = request.files.get("image")
name = m.hexdigest() + '.' + f.filename.split('.')[1]
width = float(str(request.form.get("width")).strip())
height = float(str(request.form.get("height")).strip())
title = request.form.get("title")

# 数据库存储
status = self.info.add_points(... ...)

# 图片存储
if status:
image_dir = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + "../")
f.save(image_dir + '/static/' + name)
return 1
else:
return 0
请我喝杯咖啡吧~