网站首页 > 技术文章 正文
[React组件封装][优化]文件选择按钮(解决安卓下type为file的input标签不触发onChange的问题)
详细文章请关注公众号:程序员波波。
或者点击文章最下方了解更多前往原文地址。
之前已经写过“[React组件封装][实例]文件选择按钮组件封装”这篇文章。目的是封装一个文件选择按钮。
但是在真正运用的时候发现,还是存在问题的。主要是安卓端的微信浏览器input标签不触发onChange函数。
在经过一些查阅后,发现可能原因是安卓端的WebView不支持input标签为file,不会触发onChange,而微信安卓端使用了WebView,所以会有这样的问题。
该如何解决呢?
好在微信提供了专门的图片选择接口,这样至少保证FileButton在安卓微信端能够实现图片的选择。
使用微信的jssdk可以在微信浏览器内实现图片选择功能。
使用接口前需要先加载jweixin-1.4.0.js这个文件,然后还需要到服务器端去签名。(服务端具体的签名规则在微信的官方文档中可以查阅到)
然后我这里封装了一个WeixinTools,来完成上面的步骤。
WeixinTools.js:
import Tools from "../Tools"; import Strings from "../StringUtil"; import { UserOperation } from "../UserUtil"; import Http from "../Http"; class WeixinTools { static configJsSdk() { let arg = { cmd: UserOperation.GET_JS_SDK_CONFIG, data: { url: window.location.href, } } Http.post(Tools.getUrl('/user-operation/'), arg, (data)=>{ console.log(data) if (data.result_id == 0) { let ans = data.message let js_sdk_config = ans.js_sdk_config WeixinTools.jssdk.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: Strings.APP_ID, // 必填,公众号的唯一标识 timestamp: js_sdk_config.timestamp, // 必填,生成签名的时间戳 nonceStr: js_sdk_config.noncestr, // 必填,生成签名的随机串 signature: js_sdk_config.signature,// 必填,签名 jsApiList: [ 'chooseImage', "previewImage", "uploadImage", "downloadImage", "getLocalImgData" ] // 必填,需要使用的JS接口列表 }) WeixinTools.jssdk.ready(function(){ console.log('wx js sdk ready') // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 }); WeixinTools.jssdk.error(function(res){ console.log('wx js sdk error') console.log(res) // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 }); } }) } } var _jssdkDependScripts = [ "/static/Weixin/jweixin-1.4.0.js", ] if (Tools.isWeiXin()) { Tools.asyncLoadScripts(_jssdkDependScripts, ()=>{ WeixinTools.jssdk = jWeixin }) } export default WeixinTools
调用 WeixinTools.configJsSdk()这个方法,就可以实现jssdk的初始化。
实际使用:
然后将之前FileButton组件中的代码进行改造,对应安卓微信端使用chooseImage这个接口来实现选择图片。
但是微信选择完图片后回调接口只会返回一个localIds,这个并不是实际的文件,而是一个文件的标识符一样的东西。
通过getLocalImgData这个接口可以使用localId来获取图片的base64数据,不过在安卓端需要手动加上'data:image/jpeg;base64,'前缀。然后通过Tools.jpegBase64ToBlob将base64转化成blob类型,就能统一成FileButton原来的接口了。
Tools.jpegBase64ToBlob方法:
function jpegBase64ToBlob(urlData) { try { var arr = urlData.split(',') var mime = arr[0].match(/:(.*?);/)[1] || 'image/jpeg'; // 去掉url的头,并转化为byte var bytes = window.atob(arr[1]); // 处理异常,将ascii码小于0的转换为大于0 var ab = new ArrayBuffer(bytes.length); // 生成视图(直接针对内存):8位无符号整数,长度1个字节 var ia = new Uint8Array(ab); for (var i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } return new Blob([ab], { type: mime, }); } catch (e) { var ab = new ArrayBuffer(0); return new Blob([ab], { type: 'image/jpeg', }); } }
最终版FileButton:
import React, { Component } from 'react'; import PropTypes from 'prop-types' import CSSModules from 'react-css-modules'; import Button from '@material-ui/core/Button'; import Tools from '../../../common_js/Tools' import styles from './FileButton.css' import WeixinTools from '../../../common_js/weixin/WeixinTools'; class FileButton extends Component { constructor(props) { super(props); this.button = React.createRef() this.getFiles = this.getFiles.bind(this) this.onChange = this.onChange.bind(this) this.onClick = this.onClick.bind(this) } click() { this.button.current.click() } onClick() { const { onChange } = this.props WeixinTools.jssdk.chooseImage({ count: 1, // 默认9 sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { let localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 WeixinTools.jssdk.getLocalImgData({ localId: localIds[0], success: function (res) { let localData = 'data:image/jpeg;base64,' + res.localData // let localData = 'data:image/jpeg;base64,' + res.localData.replace(/\r|\n/g, ''); if (onChange) { onChange([Tools.jpegBase64ToBlob(localData)]) } } }); } }); } getFiles() { let ans = [] let files = this.refs.fileLoader.files for (let i = 0; i < files.length; i++) { ans.push(files[i]) } return ans } onChange(e) { if (!Tools.isNone(this.props.onChange)) { this.props.onChange(this.getFiles()) } this.refs.fileLoader.value = '' } componentDidMount() { if (Tools.isWeiXin() && Tools.isAndroid()) { WeixinTools.configJsSdk() } } render() { let { accept, onChange, children, multiple, ...other } = this.props if (Tools.isNone(accept)) { accept = 'image/*' if (Tools.isChrome()) { accept = 'image/jpeg,image/gif,image/png,image/bmp' } } if (Tools.isWeiXin() && Tools.isAndroid()) { return ( ); } return ( ); } } FileButton.propTypes = { onChange: PropTypes.func, accept: PropTypes.string, } export default CSSModules(FileButton, styles);
猜你喜欢
- 2024-10-16 【验证码逆向专栏】百某网数字九宫格验证码逆向分析
- 2024-10-16 jquery-利用canvas让图片旋转角度
- 2024-10-16 一文带你搞懂JS实现压缩图片 js压缩上传图片
- 2024-10-16 前端性能优化之请求优化 前端性能优化问题
- 2024-10-16 Serverless 实战:如何为你的头像增加点装饰?
- 2024-10-16 谈谈图片上传及canvas压缩的流程 js 图片压缩后上传
- 2024-10-16 妹子委婉地和男友说没钱了,结果差点换来一张luo照?
- 2024-10-16 Blob-对象介绍 对象object
- 2024-10-16 《小白HTML5成长之路51》canvas压缩图片上传功能的原理
- 2024-10-16 Dom-to-image截图将html生成图片 html2canvas截图
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)