继续跟着前面的文章走,前面的文章从第一篇开始:
快速搭建系统
后续又增加了两篇:
模块化 + 跨域问题
数据库连接池 + JS异步
今天准备继续,算上之前的三篇,今天的这篇算是第四篇了。统一加上标题:【填坑日记】,今天是第四篇,前面三篇就懒得改了。
后续文章的结构基本上是分成两个部分:
第一部分贴出项目中的成品代码,在成品代码中会写一写自己改代码的过程。
第二部分针对改代码(也就是填坑)过程中涉及到的技术点进行分析和记录。
接第三篇,那一篇的内容还是在折腾后台,把后台的一个关键部分–数据库连接池做好了。基本流程就是通的了。
那么今天的这一篇就要开始做业务了,我们的业务是要上传一张图像,然后把这个图像的内容做一个OCR–文字识别。
我设计的上传界面很简单:就两个部分
在vue对象的methods里面增加一个函数:
通过input组件上传一个文件,然后获得这个对象后,定义一个FileReader,转换成BASE-64格式,通过POST请求发送到后台保存。
代码一:
upload_img: function () {
const selectedFile = this.$refs.refFile.files[0]
let name = selectedFile.name
let size = selectedFile.size
console.log('name: ' + name + 'size: ' + size)
const reader = new FileReader()
reader.readAsDataURL(selectedFile)
reader.onload = function (evt) {
let data = {'filename': name, 'content': evt.target.result, 'type': 'base64'}
axios.post('http://localhost:3000/data/getdata', qs.stringify(data)).then(res => {
console.log('success post')
outputResult() //这里是伪代码,从逻辑上是将识别出来的结果显示出来。在后面的章节补充上去,放在CANVAS的图像处理那部分一起说
})
}
showImg() //伪代码,显示上传的图像
}
这里原来的设计是两个按钮的,一个按钮上传图像,显示之后使用者确认然后再点击确认,再发送到后台保存和识别。
原来打算的代码是这样的:
代码二:
data() { //VUE
return {
imgvalue_base64: ‘’
}
}
upload_img: function () {
const selectedFile = this.$refs.refFile.files[0]
let name = selectedFile.name
let size = selectedFile.size
console.log('name: ' + name + 'size: ' + size)
const reader = new FileReader()
reader.readAsDataURL(selectedFile)
reader.onload = function (evt) {
let data = {'filename': name, 'content': evt.target.result, 'type': 'base64'}
this.imgvalue_base64 = data
}
showImg() //伪代码,显示上传的图像
},
confirm: function() {
axios.post('http://localhost:3000/data/getdata', qs.stringify(data)).then(res => {
console.log('success post')
outputResult()
})
}
confirm是另外一个按钮的onclick响应函数。但是fr.onload这个回调函数中的this调用,根本就不会调用到VUE对象里的data部分的变量。理由在上一篇中描述异步调用的时候已经提过了。
但是对于我自己对this这个关键字的使用起了兴趣,所以文章的下半部分就是记录一下this关键字的趟坑记录。
// CANVAS用于显示上传的图像。
这里本来是考虑用元素的,后来想着后面是不是可以在原图上做一些操作,而且canvas的功能更强大,更灵活,所以就用的canvas元素
在上面的upload_img函数接上下面这段代码:
代码三:
let canvas = this.$refs.canvas
let ctx = canvas.getContext('2d')
const arrayReader = new FileReader()
arrayReader.readAsArrayBuffer(selectedFile)
arrayReader.onload = function (evt) {
let content = evt.target.result
console.log('abcdefg')
console.log(content.byteLength)
let c = ctx.getImageData(0, 0, 480, 960)
let c1 = new ImageData(Uint8ClampedArray.from(content), c.width, c.height)
c1.data.buffer = content
ctx.putImageData(c1, 100, 100)
后续补上成品代码。
一个搞JS的大神同事告诉我,this调用的原则主要有两点:
先说第一点,在“代码一”和“代码二”部分,第一句代码:
const selectedFile = this.$refs.refFile.files[0]
这里用到了this关键字,根据第一条原则,找到this所在的函数:upload_img(),而这个函数呢?属于VUE对象。因此,这里的this引用的对象就是VUE对象,就可以通过代码$refs来引用前面的插件。
在代码二中的
this.imgvalue_base64
我原本以为这里的这个this和情况一里面的this一样,引用的是VUE对象。但是从输出结果来看不是的。所以肯定是分析错了,我们根据原则一看一下,这一句代码的调用者是匿名函数
function () {
let data = {'filename': name, 'content': evt.target.result, 'type': 'base64'}
this.imgvalue_base64 = data
}
然后把这个函数作为回调函数赋值给FileReader。所以这个调用this的是回调这个函数的某个对象,在带事件参数的回调函数中,this 表示接收事件的元素。
回到上面的代码中:
reader.onload = function (evt) {
let data = {'filename': name, 'content': evt.target.result, 'type': 'base64'}
this.imgvalue_base64 = data
}
我们获取filerender读取的文件内容用的是: evt.target.result。或者可以用this.result。那么为什么不是this.target.result呢?我们可以用console.log(evt)输出这个对象的结构来看一下:
可以看到evt对象是一个ProgressEvent对象(现在不知道这个对象具体是啥情况,暂时不管吧),这里面有一个target的成员,这个成员就是FileReader类型的。
根据原则3,this就表示接受事件的对象,应该就是这个target了,所以就可以用this.result来表示了。
这里我自己的理解是:BOM或者浏览器框架或者是某个环境(现在不清楚)组装了一个ProgressEvent的对象,用于调用回调函数之间传递参数,在这个对象中把接受这个事件的对象也塞进去了(虽然不知道为什么要这么做),所以this就可以表示event.target了。 现在就理解到这个程度了,后续再来补这个坑。
看下面的这一段代码:
ex_canvas
这里的输出结果是:
定义在script元素中的变量x(全局变量),直接作为了window顶层对象(BOM)的成员了。
这里的一个问题是:
都是在函数imgload()中,代码:
var x = 'x2'
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d')
let img = document.getElementById('img')
console.log(this.x)
var f = function () {
console.log(this.x)
}
f()
在定义的匿名函数中,this.x还是script中定义的全局变量x,而代码
var x = 'x2'
只是定义了一个imgload方法的方法变量。
而代码:
console.log(this.y)
var obj = {
y: 'y2',
func: function () {
console.log(this.y)
}
}
obj.func()
则是输出了y2,也就是说浏览器把语句var obj定义为了一个对象。而func这个方法中调用了this,自然指的就是obj这个对象。
其实,这里还有另外一个问题,就是说JS本身不是一个面向对象的语言,那么什么样的东西可以称之为一个对象呢?在很多技术资料里面也使用了对象这个名词,而且使用typeof关键字输出的话,也会输出object。那么是不是和java一样,有完整的类和对象的特性:封装、继承和多态。
这一块的东西,暂时了解到的是原型和原型链,这个坑还没怎么看懂,后续再填。
在网上搜canvas绘制图像这个话题,一般的技术资料都是很简单的介绍: