Open toxic-johann opened 7 years ago
最近这两周压力比较大,手上这个项目遇到的坑还是挺多的。现在第一版的代码差不多完成,今晚算是空闲。因此先记录一下一些这些天遇到的bug。
个人认为multiple是一个很完美的属性。在元素<input type="file">,配上multipe和accept属性。就这样一个限定类型的多文件上传接口就出来了。
<input type="file">
然而事情总是不是那么完美的。这次的主角是安卓。
事实上下面还有段语句解释。
Not supported on Android 4.x and below, presumably an OS limitation. Only seems to work in Android 5.x for the Chrome browser.
就是说只有安卓5.0以上的版本才支持这个特性。我们知道安卓5.0出来已经有一段时间了。但是因为安卓特殊的厂商分发机制。到现在大部分机子还是处于4.x的程度。
其实这个特性在安卓上是曾经生效过的。但是因为某一个版本的问题,直接被废弃了。无论你如何选择都是只能提交一张。而web页面暂时没有办法对此作出反抗。除非你用hybrid之类的自由度比较大的框架。
因此这里我们降级采用了微信JSSDK的上传接口。
花开两朵,各表一枝。既然安卓和iOS分成了两个派别,那我们先谈一下iOS的处理。(真对不起,我手头没有winphone,而且两个系统已经搞死我了。windows phone用户不要怪我。)
一般来说,我们会采用change事件来监听网页里的input值选择,在type="file"的情境下我们也照样处理。这里的逻辑是这样的。
type="file"
手机取出一个文件还是挺快的。但是,如果你选了很多个文件。这就很难说了。在性能比较差的手机或者系统里。他会把所有照片的路径和相关资料都打包好,再提交给页面。这就是图中红框所指的时间差。这个时间差甚至会长达十秒以上。
这个时候,如果手机性能不好的话。页面会表现为卡死。如果手机性能尚不至于十分差劲,页面会可以交互。
而红框这个时候,如果我们用事件交代,就是click事件后、change事件前。
这是我们遇到的第一个问题,我们“不知道”用户已经选择完毕了,就被推上了前台。
那既然我们什么都不知道,那就提前做好准备吧。在用户click的时候就作出我们已经在处理的现象,安抚一下用户吧。
因此我决定在click事件上就加上相关的页面交互表示。当我们web端被推向用户的时候,不至于手足无措。但是这就引来了下面这个问题。
万一用户按了取消事件呢?
这就是另一个坑了。一般在电脑上,有两种处理情况。
现在假设你在电脑上。
但是,现在我们在手机端,而且根据上文,我们为了客户体验。在click上作了处理。
这就让我在click后处于一种十分尴尬的状态了。
究竟用户是在选择呢?取消选择了呢?还是选择完了手机在处理用户盯着我干瞪眼呢?
这个问题,我暂时想不到比较好的办法。我个人建把议决定权交还给用户。我们给可以让用户关掉的一个提示框。 待议。
iOS上的上传基本就是用form-data和filereader进行处理就好了。这里问题不大。
下面我们说android。
微信JSsdk中,chooseImage的最多数目是九个。如果你设定大于9的限制。在android里会显示依旧只能选9个,但是在iPhone里,你的确可以选很多个,不过该接口会返回一个错误。
令人庆幸的是,微信这个接口success、fail、cacel的接口一应俱全。让人十分满意。
localId是微信给的一个地址,应该是一个代理让你找寻本地文件。但是除此之外,就找不到其他资料了。
这个localId只能用于img展示,将其绑定到<img>的src属性上,就可以显示该图片。
<img>
但是这个localId无法用于filereader进行处理。
在stackoverflow上面找到这个处理方法。用于将img转化为dataurl。
一个是用xhr进行文件下载处理。
function toDataUrl(url, callback){ var xhr = new XMLHttpRequest(); xhr.responseType = 'blob'; xhr.onload = function() { var reader = new FileReader(); reader.onloadend = function () { callback(reader.result); } reader.readAsDataURL(xhr.response); }; xhr.open('GET', url); xhr.send(); }
但是微信的localId不支持这种ajax请求。
另一个是用canvas渲染后再进行提取。
function toDataUrl(url, callback, outputFormat){ var img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = function(){ var canvas = document.createElement('CANVAS'); var ctx = canvas.getContext('2d'); var dataURL; canvas.height = this.height; canvas.width = this.width; ctx.drawImage(this, 0, 0); dataURL = canvas.toDataURL(outputFormat); callback(dataURL); canvas = null; }; img.src = url; }
这里注意下,必须要设置跨域。不然你无法调用canvas的toDataURL方法。
不过我试了下,生成的图片都是空图片,应该还是有些问题。
鉴于时间愿意,我也放弃了,选择了一种我较为熟悉的做法。。
前端把图片上传至微信服务器,获取微信服务器mediaId,再在我服务器利用该id进行拉取。这个以后我再谈谈具体做法。
uploadImage不支持多张上传,而且必须要传完一张,再传下一张。如果你同时提请求,或者在他没有处理好的情况下,提出请求。他会不报错,不报warning直接忽略掉。
因此,这个必须要设置递归上传了。因此,我写了个异步递归方法。
recursion:function(...args){ let me = this; return new Promise((resolve,reject)=>{ let arr = args[0]; let callback = args[1]; let other = args.slice(2); // 判断处理队列是否还有需要处理的数据。 if(Array.isArray(arr) && arr.length > 0){ let tmp = arr.shift(); let runArgs = [tmp].concat(other); let newArgs = [arr,callback].concat(other) // 执行需要我执行的函数,无论是否成功,执行结束后调用下一个函数进行执行。 callback.apply(this,runArgs).then(()=>{ me.recursion.apply(me,newArgs).then(()=>{ resolve(); }) },(...args)=>{ console.log("recursion got reject",args); me.recursion.apply(me,newArgs).then(()=>{ resolve(); }) }).catch((...args)=>{ console.log("recursion catach error",args); me.recursion.apply(me,newArgs).then(()=>{ resolve(); }) }) } else { resolve() } }); }
使用起来也十分简单。
recursion(localIds,(each,self)=>{ return self.uploadByWx(each,self) },self).then(success=>{ self.$emit("finished"); });
传入你需要的参数和调用的函数。然后监听结果就好。
那么这样子我们就基本完成了主需求了。下面谈一些其他方面的小问题。
现在十分流行下拉翻页等需求。因此,对于scorll效果,我们用的越来越多。鉴于本次项目需要的滚动不算特别复杂。因此我就直接自己编写了一个vue的指令。
;(function() { var vueScroll = {}; vueScroll.install = function(Vue) { Vue.directive('scroll', { isFn : true, acceptStatement : true, bind : function() { //bind callback }, update : function(fn) { var self = this; if(typeof fn !== 'function') { return console.error('The param of directive "v-scroll" must be a function!'); } let positon = $(window).scrollTop(); let direction = ""; let delta = 20; $(window).scroll(function(...args){ let now = $(window).scrollTop(); if(now == ($(document).height() - $(window).height())){ args.push("bottom") args.push($(self.el)); fn.apply(self,args); } if(direction != "down" && now-positon > delta){ direction = "down"; positon = now; args.push("down") args.push($(self.el)); fn.apply(self,args); } else if(direction != "up" && positon-now > delta){ direction = "up"; positon = now; args.push("up") args.push($(self.el)); fn.apply(self,args); } else if(Math.abs(now-positon)>delta){ positon = now; } }) }, unbind : function() {}, }); }; if (typeof exports == "object") { module.exports = vueScroll; } else if (typeof define == "function" && define.amd) { define([], function(){ return vueScroll }) } else if (window.Vue) { window.vueScroll = vueScroll; Vue.use(vueScroll); } })();
监听滚动到底部的方式还是比较简单,做一个位置的提醒就好了。
至于判断滑动方向,我想不是方向改变了的话,你当然不希望收到这么多通知啦。因此我这里做了个标志的缓存。如果方向边,只在第一次移动的时候进行提醒。
但是这里苹果做了个优化,直到最后滚动彻底停下来,苹果的浏览器才出发window的scroll函数。这里需要注意。因此你可以默认滚动到底部就等于往下翻等。这里自己需要稍加注意。
移动端五花八门,还是很多细节会有不一样。特别是腾讯自己开发的X5浏览器,很多行为都十分怪异,惨不忍睹。这些找时间总结一下。
另外这次还尝试了一下使用vuejs和众多微信的接口。这些找时间再谈。
最近这两周压力比较大,手上这个项目遇到的坑还是挺多的。现在第一版的代码差不多完成,今晚算是空闲。因此先记录一下一些这些天遇到的bug。
个人认为multiple是一个很完美的属性。在元素
<input type="file">
,配上multipe和accept属性。就这样一个限定类型的多文件上传接口就出来了。然而事情总是不是那么完美的。这次的主角是安卓。
事实上下面还有段语句解释。
就是说只有安卓5.0以上的版本才支持这个特性。我们知道安卓5.0出来已经有一段时间了。但是因为安卓特殊的厂商分发机制。到现在大部分机子还是处于4.x的程度。
其实这个特性在安卓上是曾经生效过的。但是因为某一个版本的问题,直接被废弃了。无论你如何选择都是只能提交一张。而web页面暂时没有办法对此作出反抗。除非你用hybrid之类的自由度比较大的框架。
因此这里我们降级采用了微信JSSDK的上传接口。
花开两朵,各表一枝。既然安卓和iOS分成了两个派别,那我们先谈一下iOS的处理。(真对不起,我手头没有winphone,而且两个系统已经搞死我了。windows phone用户不要怪我。)
一般来说,我们会采用change事件来监听网页里的input值选择,在
type="file"
的情境下我们也照样处理。这里的逻辑是这样的。手机取出一个文件还是挺快的。但是,如果你选了很多个文件。这就很难说了。在性能比较差的手机或者系统里。他会把所有照片的路径和相关资料都打包好,再提交给页面。这就是图中红框所指的时间差。这个时间差甚至会长达十秒以上。
这个时候,如果手机性能不好的话。页面会表现为卡死。如果手机性能尚不至于十分差劲,页面会可以交互。
而红框这个时候,如果我们用事件交代,就是click事件后、change事件前。
这是我们遇到的第一个问题,我们“不知道”用户已经选择完毕了,就被推上了前台。
那既然我们什么都不知道,那就提前做好准备吧。在用户click的时候就作出我们已经在处理的现象,安抚一下用户吧。
因此我决定在click事件上就加上相关的页面交互表示。当我们web端被推向用户的时候,不至于手足无措。但是这就引来了下面这个问题。
万一用户按了取消事件呢?
这就是另一个坑了。一般在电脑上,有两种处理情况。
现在假设你在电脑上。
但是,现在我们在手机端,而且根据上文,我们为了客户体验。在click上作了处理。
这就让我在click后处于一种十分尴尬的状态了。
究竟用户是在选择呢?取消选择了呢?还是选择完了手机在处理用户盯着我干瞪眼呢?
这个问题,我暂时想不到比较好的办法。我个人建把议决定权交还给用户。我们给可以让用户关掉的一个提示框。 待议。
iOS上的上传基本就是用form-data和filereader进行处理就好了。这里问题不大。
下面我们说android。
微信JSsdk中,chooseImage的最多数目是九个。如果你设定大于9的限制。在android里会显示依旧只能选9个,但是在iPhone里,你的确可以选很多个,不过该接口会返回一个错误。
令人庆幸的是,微信这个接口success、fail、cacel的接口一应俱全。让人十分满意。
localId是微信给的一个地址,应该是一个代理让你找寻本地文件。但是除此之外,就找不到其他资料了。
这个localId只能用于img展示,将其绑定到
<img>
的src属性上,就可以显示该图片。但是这个localId无法用于filereader进行处理。
在stackoverflow上面找到这个处理方法。用于将img转化为dataurl。
一个是用xhr进行文件下载处理。
但是微信的localId不支持这种ajax请求。
另一个是用canvas渲染后再进行提取。
这里注意下,必须要设置跨域。不然你无法调用canvas的toDataURL方法。
不过我试了下,生成的图片都是空图片,应该还是有些问题。
鉴于时间愿意,我也放弃了,选择了一种我较为熟悉的做法。。
前端把图片上传至微信服务器,获取微信服务器mediaId,再在我服务器利用该id进行拉取。这个以后我再谈谈具体做法。
uploadImage不支持多张上传,而且必须要传完一张,再传下一张。如果你同时提请求,或者在他没有处理好的情况下,提出请求。他会不报错,不报warning直接忽略掉。
因此,这个必须要设置递归上传了。因此,我写了个异步递归方法。
使用起来也十分简单。
传入你需要的参数和调用的函数。然后监听结果就好。
那么这样子我们就基本完成了主需求了。下面谈一些其他方面的小问题。
现在十分流行下拉翻页等需求。因此,对于scorll效果,我们用的越来越多。鉴于本次项目需要的滚动不算特别复杂。因此我就直接自己编写了一个vue的指令。
监听滚动到底部的方式还是比较简单,做一个位置的提醒就好了。
至于判断滑动方向,我想不是方向改变了的话,你当然不希望收到这么多通知啦。因此我这里做了个标志的缓存。如果方向边,只在第一次移动的时候进行提醒。
但是这里苹果做了个优化,直到最后滚动彻底停下来,苹果的浏览器才出发window的scroll函数。这里需要注意。因此你可以默认滚动到底部就等于往下翻等。这里自己需要稍加注意。
移动端五花八门,还是很多细节会有不一样。特别是腾讯自己开发的X5浏览器,很多行为都十分怪异,惨不忍睹。这些找时间总结一下。
另外这次还尝试了一下使用vuejs和众多微信的接口。这些找时间再谈。