input踩坑大集合,持续更新~
2017-07-13 15:36
423 查看
一、PC端
1、input type='file'需求:用户点击按钮弹出选择文件框框,可以多选,可以单选,然后将用户选择的文件缓存,需要在界面显示用户选择了哪些文件, 文件大小不能超过50M,不可以一次上传相同文件两次,上传之前可以逐一删除选择过的文件。
效果如下:
1、文件多选:给input加上 multiple="multiple"即可多选。
2、限制文件后缀:加上accept='.csv' accept的值就是你想控制的文件后缀名。
3、样式:input file的样式不可改变,将input透明,用div做一个按钮,将input覆盖上面即可。
4、上传文件:项目框架react,UI层用ant design,故第一次开发时候选用了Upload组件,该组件上传一个文件很方便,直接引入组件即可,但是组件有一个缺点,点击就会直接上传,与需求不符。想来想去决定用户选择文件即把文件传给后端,后端将该文件对应的路径返回给我,在用户点击导入的时候,将对应的用户信息和文件路径在给后端传过去。但是由于项目进展,后端共享服务器,用户每次上传的文件会散落在多台服务器上,所以两次上传pass,决定用原生来做。
第一个坑:只用input上传,后台收不到文件
<input onChange={this.changeFiles} multiple="multiple" type="file" accept=".csv" name="name" />
在changeFiles函数中 可以获取到e.target.files。它是一个数组,选择几个文件,数组就有几个元素。好问题解决了,找后台同学调一下。Fuck,后台啥都收不到,怎么传都不行,fetch,ajax,formData都试过了,后台就是收不到东西。
经过一下午的研究终于搞明白了,原来上传文件的input外层,必须要form包裹着,且form要有enctype属性,告诉浏览器我即将要上传的是数据流。
<form encType="multipart/form-data" name="form" id="uploadForm"> <Button type="dashed" width="900"> <div className="DivInButton"> <span style={{fontWeight: "500", color: "#49a9ee", fontSize: "40px"}} className="iconfont icon-upload"></span> <p style={{fontWeight: "500", fontSize: "16px"}}>选择文件</p> </div> </Button> <input onChange={this.changeFiles} multiple="multiple" type="file" accept=".csv" name="name" /> </form>
如此选择的文件会有FileList标识,只有将这个东西传给服务器,服务器才会收到文件。
第二个坑:如何一个参数对应多个文件。利用formData,循环添加所有文件到一个key上即可。selectFiles就是选择过的文件。
let formData=new FormData(); formData.append("platformType", this.state.platformType); formData.append("shopName", this.state.shopName); for (let i = 0;i < selectFiles.length;i++) { formData.append("files", selectFiles[i]); } fetch(env.host+"/order/manualImport", {method: 'POST', body: formData, credentials: "include", header: {'Cache-Control': 'no-cache'}}) .then((response) => {if(/login/.test(response.url)){browserHistory.push('/login');return;};return response.json()}) .then((data) => { if (data) { if (data.status === 0) { do something... } else { do something... } } else { do something... }
5、上传图片预览:利用HTML5的FileReader接口,它的readAsDataURL方法可以获取图片的二进制码,注意,需要将FileReader先加载才可以获取到二进制码。
var EvaluateFile={}; function EvaluateUpload(e) { EvaluateFile=e.target.files[0]; var reader = new FileReader(); reader.onload = function () { var _this=this; document.querySelector(".EvaluateImage").setAttribute("src",_this.result); document.querySelector(".Evaluate_no").style.display='none'; document.querySelector(".Evaluate_yes").style.display='block'; } reader.readAsDataURL(EvaluateFile); }
onload加载完成后,内部this.result就是该图片的二进制码,可以直接输出给img标签。注意上传图片不可以上传二进制码,有些手机拍的照片质量很大,转成二进制码特别特别长,传给后端,后端还需要解析,传输的时间和解析的时间都是性能消耗、浪费时间的。后端的作用就是保存一下嘛。上传图片用方法4即可。
二、移动端
1、input输入框:Android端弹出输入法页面炸裂。在移动端,大部分情况下页面都是单页式,即最外层容器的宽高都是100%。在ios微信中,用户唤醒输入法是没问题的。
在安卓微信端,页面的可是范围既是document.documentElement.clientHeight,input获取焦点之后,整体高度会变小,导致页面元素位置改变。
这种情况下,要再所有逻辑前边判断当前设备是安卓端还是ios端。如果是安卓端,重新设置一下容器高度为当前设备屏幕高度即可。
var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); if (isAndroid) {//安卓 document.getElementById("root").setAttribute("class","Wrap_android"); document.querySelector(".Wrap_android").style.height=document.documentElement.clientHeight+"px"; } else if (isiOS) {//iphone document.getElementById("root").setAttribute("class","Wrap_iphone"); } else { document.getElementById("root").setAttribute("class","Wrap_android"); }
2、fixed定位:ios端唤醒输入法之后再滑动页面,定位失效。(不仅限于input输入框,时间选择器、select选择框都有这个bug)
正常的html结构
<body class="layout-fixed"> <!-- fixed定位的头部 --> <header> </header> <!-- 可以滚动的区域 --> <main> <!-- 内容在这里... --> </main> <!-- fixed定位的底部 --> <footer> <input type="text" placeholder="Footer..."/> <button class="submit">提交</button> </footer> </body>
对应的css
header, footer, main { display: block; } header { position: fixed; height: 50px; left: 0; top: 0; } footer { position: fixed; height: 34px; left: 0; bottom: 0; } main { margin-top: 50px; margin-bottom: 34px; height: 2000px }
这样的结构当用户唤起输入法之后,footer和header的fixed会变成absolute,页面滑动超过一屏时,footer和header就会随之滚动。
这时只要将滚动元素与定位元素分离即可。
<body class="layout-scroll-fixed"> <!-- fixed定位的头部 --> <header> </header> <!-- 可以滚动的区域 --> <main> <div class="content"> <!-- 内容在这里... --> </div> </main> <!-- fixed定位的底部 --> <footer> <input type="text" placeholder="Footer..."/> 4000 <button class="submit">提交</button> </footer> </body>
对应的css
header, footer, main { display: block; } header { position: fixed; height: 50px; left: 0; top: 0; } footer { position: fixed; height: 34px; left: 0; bottom: 0; } main { /* main绝对定位,进行内部滚动 */ position: absolute; top: 50px; bottom: 34px; /* 使之可以滚动 */ overflow-y: scroll; /* 增加该属性,可以增加弹性 */ -webkit-overflow-scrolling: touch; } main .content { height: 2000px; }
注意:移动端使用overflow-y:scroll时,滚动元素内滚动非常不流畅,滑动的手指松开后,滚动立即停止,失去了原本的滚动流畅特性。需使用-webkit-overflow-scrolling:touch;使元素恢复弹性。
相关文章推荐
- UI设计另类,创意的网站和App 集合(持续更新)
- shell特殊用途小命令集合——持续更新。。。求跟帖,大家一起分享
- codeforces好题集合 (持续更新)
- android下ListView的奇异异常大集合(持续更新)
- [置顶] Android 自己收集的开源项目和文章集合(持续更新 2018.3.21)
- android编程中用到的小功能集合(持续更新)
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新
- 有关音视频文件解析和提取等一系列问题的帖子集合,持续更新
- Coolite/Ext.net1.0 VType自定义验证扩展集合(持续更新......)
- Shell 小脚本集合----持续更新
- JNI编程小技巧集合(持续更新)
- 肤色检测&人脸检测数据集等链接大集合(持续更新中...)
- 集合表示及其运算(持续更新)
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新
- 集合框架的一些问题(持续更新)
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新
- cocos2d-html5 游戏实战源代码大集合和下载(包括flappy,popstar等----持续更新中----)
- MySQL_常用操作集合(持续更新)
- ionic1.x开发优秀博客的集合(持续更新)
- JAVA集合Map(持续更新)