之前用:
【已解决】ReactJS中如何整合已有的datetime选择框
已经可以利用:
lanjingling0510/react-mobile-datepicker: ? ? look a demo, Please imitate mobile environment.
实现基本的日期选择了。
但是之前有个问题就是:
之前的代码:
render () { return ( <input value={datetimeToStr(this.state.curDate, "请选择")} onClick={this.handleDateClick} class={style.ui_input}> <DatePicker value={this.state.curDate} isOpen={this.state.isOpen} theme={‘ios’} min={new Date(2010, 1, 1)} max={new Date(2050, 1, 1)} dateFormat={[‘YYYY年’, ‘MM月’, ‘DD日’]} onSelect={this.handleDateSelect} onCancel={this.handleDateCancel} /> </input> ); } |
即:picker属于input,而input允许输入,所以此时点击选择日期时,会同时出发输入法且可以输入:
然后就去给input加上了
readonly=“readonly"
结果就导致了:
iOS和android都的确不会有输入框了
且iOS端仍然可以很流畅的滚动选择日期
但是:android端,基本上没发滚动选择日期了
极其偶尔的才可以滚动一下 但是马上又没发滚动了。
以为是android的bug
后来搜:
react-mobile-datepicker input readonly can not select
参考:
javascript – Bootstrap datetimepicker don’t work with readonly or disabled – Stack Overflow
感觉是:
datetimepicker
这类控件,估计都是会受readonly的影响。。
现在先去试试,把input改为其他的,比如p
看看效果
实在不行,再去试试
readonly=“true”
readonly=“readonly”
readonly
disabled=“disabled"
disabled
之类的。
可以弹出日期选择:
但是value的属性就不起效果了。
想去找找其他input类似的控件
html 输入 控件
不用去试试disabled了
-》的确是其本意就是禁止
“被禁用的 input 元素既不可用,也不可点击。”
所以此处是不合适用disabled
适合用:readonly
试了试:
readonly=“true”
结果问题依旧,基本上没发滑动选择日期了。
试试:
readonly
问题依旧。
react datepicker input readonly can not select
react datepicker input not focus
待会试试:
(ReactJS中的)readOnly
问题依旧。
或者待会试试:
jquery – How to make bootstrap datepicker readonly? – Stack Overflow
中onClick时,禁止传递event
加上:
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
即代码:
handleDateClick(e) { console.log("handleDateClick"); console.log(`this.state.curDate=${this.state.curDate}`); console.log(`this.state.prevSelectedDate=${this.state.prevSelectedDate}`); e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); if (this.state.curDate === INVALID_DATE) { this.setState({ curDate: new Date(), prevSelectedDate : INVALID_DATE }); } this.setState({ isOpen : true }); } render () { return ( <input value={datetimeToStr(this.state.curDate, "请选择")} onClick={this.handleDateClick} readOnly class={style.ui_input}> <DatePicker value={this.state.curDate} isOpen={this.state.isOpen} theme={‘ios’} min={new Date(2010, 1, 1)} max={new Date(2050, 1, 1)} dateFormat={[‘YYYY年’, ‘MM月’, ‘DD日’]} onSelect={this.handleDateSelect} onCancel={this.handleDateCancel} /> </input> ); } |
看看效果:
问题和以前一样了:会出现输入框,并且可以输入了。。。
react-datepicker interferes with react select · Issue #730 · Hacker0x01/react-datepicker
以后可以考虑看看这个cancelFocusInput
react datepicker input readonly
react mobile datepicker input readonly
make disable or readonly input field · Issue #961 · Hacker0x01/react-datepicker
Blinking cursor in mobile · Issue #253 · airbnb/react-dates
To don’t allow DatePicker keyboard input – Date/Time Pickers – Kendo UI Forum
试试:
disabled=“disabled"
不用去手机端试了,Chrome中就无法点击了。。
需要去搞清楚:
readonly="true"和readonly=“readonly"的区别:
input readonly="true" readonly=“readonly"
html – What is the difference between readonly="true" & readonly="readonly"? – Stack Overflow
html – What is the correct readonly attribute syntax for input text elements? – Stack Overflow
readonly只要出现,而不论其是否有值,值是readonly还是true(还是false)
都是一样的效果:表示是只读。
readonly只要不出现,则表示可以输入。
Blinking cursor in mobile · Issue #253 · airbnb/react-dates
目前感觉是:
设置input为readonly了,android端有问题,无法滚动了
像是android中的chrome内核有bug?
现在的想法只有:
(1)看看是否能想办法规避这个bug
(2)是否可以禁止显示输入框?
android chrome input readonly datepicker
asp.net mvc – How to not show a mobile keyboard when using bootstrap-datepicker? – Stack Overflow
ignoreReadonly这只是Bootstrap的,此处没法用。
不过还是先去试试:
e.preventDefault(); e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); |
问题依旧。
【已解决】ReactJS的H5页面中如何去掉输入框获得焦点时出现的黄色边框
试试:
type=“button”
<input value={datetimeToStr(this.state.curDate, "请选择")} onClick={this.handleDateClick} type="button" class={style.ui_input}> <DatePicker value={this.state.curDate} isOpen={this.state.isOpen} theme={‘ios’} min={new Date(2010, 1, 1)} max={new Date(2050, 1, 1)} dateFormat={[‘YYYY年’, ‘MM月’, ‘DD日’]} onSelect={this.handleDateSelect} onCancel={this.handleDateCancel} /> </input> |
Mac中Chrome的效果还是可以的。
然后再去把width从100%改为auto,就好看多了:
再去试试移动端
结果是:
Android端还是有问题:
虽然无法输入了,还是很难滑动选择日期,而iOS端WKWebView就很流畅。
现在感觉可能是之前的另外的问题导致的Android端滑动有问题:
【已解决】ReactJS中如何禁止input控件获得输入的焦点以避免弹出键盘和输入
此处虽然可以禁止输入了,但是滑动滚动选择日期,又基本失效了。。。
所以算是问题依旧。
去看了看其源码,感觉主要是:
componentDidMount() { const viewport = this.viewport; viewport.addEventListener(‘touchstart’, this.handleContentTouch, false); viewport.addEventListener(‘touchmove’, this.handleContentTouch, false); viewport.addEventListener(‘touchend’, this.handleContentTouch, false); viewport.addEventListener(‘mousedown’, this.handleContentMouseDown, false); } |
去注册了滑动事件
其中关于capture参数,参考:
EventTarget.addEventListener() – Web API 接口 | MDN
addEventListener的第三個參數 : O3noBLOG
HTML DOM addEventListener() 方法 | 菜鸟教程
然后用:
/** * 滑动日期选择器触屏事件 * @param {Object} event 事件对象 * @return {undefined} */ handleContentTouch(event) { event.preventDefault(); if (this.animating) return; if (event.type === ‘touchstart’) { this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { this.handleEnd(event); } } |
去检测触摸滚动
所以问题感觉是:
使用了preventDefault,或者是input无法获得输入焦点了,readonly了等等
scroll滚动时间,触摸事件,就失效了?
或者就极其不流畅了?
react js preventDefault scroll not work
react js preventDefault touchstart not work
reactjs – React JS: onWheel bubbling stopPropagation not working – Stack Overflow
javascript – How to disable scrolling temporarily? – Stack Overflow
onWheel Stop bubbling is not happening. · Issue #5845 · facebook/react
Bar scroll. The default ‘touchmove’ is not prevented on Mobile Safari · Issue #654 · twbs/ratchet
javascript – ReactJS SyntheticEvent stopPropagation() only works with React events? – Stack Overflow
touchstart preventDefault() does not prevent click event. · Issue #9809 · facebook/react
还是无解。
参考实例代码,去给DatePicker上一级加上一个div试试
<input value={datetimeToStr(this.state.curDate, "请选择")} onClick={this.handleDateClick} class={style.ui_input}> <div> <DatePicker value={this.state.curDate} isOpen={this.state.isOpen} ignoreReadonly={true} theme={‘ios’} min={new Date(2010, 1, 1)} max={new Date(2050, 1, 1)} dateFormat={[‘YYYY年’, ‘MM月’, ‘DD日’]} onSelect={this.handleDateSelect} onCancel={this.handleDateCancel} /> </div> </input> |
结果问题依旧:
还是滚动基本上无效,或者反应很迟钝。
去把react-mobile-datepicker的源码中的
/** * 滑动日期选择器触屏事件 * @param {Object} event 事件对象 * @return {undefined} */ handleContentTouch(event) { // event.preventDefault(); if (this.animating) return; if (event.type === ‘touchstart’) { this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { this.handleEnd(event); } } |
// event.preventDefault();
看看效果。
问题依旧。
react js touchstart not work
[FlatButton] – onTouchTap event works instead of onTouchStart · Issue #4555 · callemall/material-ui
Touch events not firing:reactjs
看到提示说是CSS中要有:
cursor: pointer;
所以去看库的源码,倒是都有:
<div className="App"> <a className="select-btn" onClick={this.handleClick}> select time </a> <DatePicker value={this.state.time} isOpen={this.state.isOpen} onSelect={this.handleSelect} onCancel={this.handleCancel} /> </div> .select-btn { display: inline-block; border: 1px solid #ccc; padding: 1rem; margin: 1rem 0; cursor: pointer; background: #fff; &.sm { margin: .5rem .5rem; padding: .5rem; } } |
所以自己此处也去加上试试
不用去试了,只是鼠标的形状而已。。。
难道是库中代码的refs的写法
(之前解决过:
【已解决】[eslint] Using this.refs is deprecated. (react/no-string-refs)
)
导致此处滑动时不时不生效的问题?
Update nuances of ref callback calling by unel · Pull Request #8333 · facebook/react
那抽空把代码换成新的写法试试
但是不方便直接修改库的源码
所以去尝试把库的源码拷贝到项目中,然后去调试
然后出错:
【未解决】Preact中css代码出错:Error evaluating function `color`: keyword.toLowerCase is not a function
算了,放弃整合react-mobile-datepicker代码到此preact项目中了。
去加了调试代码,也没看出什么问题。
去把refs改为正常的引用:
/node_modules/react-mobile-datepicker/dist/react-mobile-datepicker.js
// ref: ‘scroll’, ref: function (scroll) { return _this3.scroll = scroll; }, // eslint-disable-line className: ‘datepicker-scroll’, DatePickerItem.prototype._moveTo = function _moveTo(obj, currentIndex) { //_this2._clearTransition(_this2.refs.scroll); _this2._clearTransition(_this2.scroll); DatePickerItem.prototype._moveToNext = function _moveToNext(direction) { //this._moveTo(this.refs.scroll, this.currentIndex); this._moveTo(this.scroll, this.currentIndex); |
感觉是:
或许是此处的refs有问题,导致了:
_moveTo
_moveToNext
中的滚动没有起到效果,或者是很难起效果。
但是直接修改了:
react-mobile-datepicker.js
导致一个问题:
【已解决】npm run build项目出错:npm ERR! code ELIFECYCLE errno 2
所以还是:
最好从项目react-mobile-datepicker的源码,修改后,自己去build出来对应的 dist中的.js和.min.js
所以去:
【已解决】如何从项目react-mobile-datepicker的js源码编译并发布js库
然后用修复了refs的库,结果android端还是问题依旧:
有时候是好的,可以正常滑动滚动选择日期,虽然不是特别流畅,但是大部分时间都是无法滚动的。
-》所以确定不是refs的问题,而是其他什么原因导致滚动问题的。
然后也去对比了:
类似的代码和逻辑的:
处理页面的滚动,就基本上是正常工作的(虽然也不是极度的流畅)
而此处的日期选择的滚动就基本不工作。。
继续研究代码:
【已解决】尝试看看是否是Android浏览器对transform和translateY支持不够好导致无法滚动选择日期
所以,问题方向要调整到,找到:
加了readonly,或者允许输入法弹出后,为何android端就可以正常滑动选择了。
android js input popup then datepicker work
突然想起来,把input和DatePicker分开,不要是父子,而是sibling:
<div> <input value={datetimeToStr(this.state.curDate, "请选择")} readonly onClick={this.handleDateClick} class={style.ui_input} /> <DatePicker value={this.state.curDate} isOpen={this.state.isOpen} ignoreReadonly={true} theme={‘default’} min={new Date(2010, 1, 1)} max={new Date(2050, 1, 1)} dateFormat={[‘YYYY年’, ‘MM月’, ‘DD日’]} onSelect={this.handleDateSelect} onCancel={this.handleDateCancel} /> </div> |
看看效果。
果然问题依旧。
不过突然想起来:
难道是Android端的日期选择控件,只有是input获取焦点之后,才能开始滑动???
android datepicker only scroll after get focus
android datepicker only scroll after input focus
jquery datetime picker problem. | Laravel.io
Input click breaks scrolling · Issue #1638 · ionic-team/ionic
现象和我这有点类似
fix(keyboard):don’t setKeyboardShow on date/time inputs · ionic-team/ionic@ad08b34
iOS 8.x modal scroll issue · Issue #14839 · twbs/bootstrap
jquery – Disable scrolling when changing focus form elements ipad web app – Stack Overflow
webchromeclient scroll not work not get focus
android – WebView doesn’t scroll when keyboard opened – Stack Overflow
java – Android webview scrolling doesn’t work – Stack Overflow
Android Froyo WebView doesn’t scroll vertically – Stack Overflow
android webview scroll not work if not get focus
然后去试了试:
使用:
<input value={datetimeToStr(this.state.curDate, "请选择")} type="date" onClick={this.handleDateClick} class={style.ui_input} /> |
原生的日期选择,其实倒是还是不错的:
只不过会和现在此处的日期选择器重叠:
Android端的效果:
iOS端的效果:
android webview input get focus
Why is Android WebView refusing user input? – Stack Overflow
Android WebView – Setting HTML Field focus using Javascript – Stack Overflow
感觉可能是:
onTouchStart
onTouchMove
onTouchEnd
的事件,对于Android的webview中,当没有获得focus时,就不太起效果了?
去把:
<div className="datepicker-col-1"> <div ref={viewport => this.viewport = viewport} // eslint-disable-line componentDidMount() { const viewport = this.viewport; viewport.addEventListener(‘touchstart’, this.handleContentTouch, false); viewport.addEventListener(‘touchmove’, this.handleContentTouch, false); viewport.addEventListener(‘touchend’, this.handleContentTouch, false); viewport.addEventListener(‘mousedown’, this.handleContentMouseDown, false); } componentWillUnmount() { // alert(`DatePickerItem componentWillUnmount`); const viewport = this.viewport; viewport.removeEventListener(‘touchstart’, this.handleContentTouch, false); viewport.removeEventListener(‘touchmove’, this.handleContentTouch, false); viewport.removeEventListener(‘touchend’, this.handleContentTouch, false); viewport.removeEventListener(‘mousedown’, this.handleContentMouseDown, false); } |
换成ReactJS的:
onTouchStart
onTouchMove
onTouchEnd
<div className="datepicker-col-1"> <div onTouchStart={this.handleContentTouch} onTouchMove={this.handleContentTouch} onTouchEnd={this.handleContentTouch} onMouseDown={this.handleContentMouseDown} |
结果发现:
/** * 滑动日期选择器触屏事件 * @param {Object} event 事件对象 * @return {undefined} */ handleContentTouch(event) { event.preventDefault(); if (this.animating) return; if (event.type === ‘touchstart’) { this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { this.handleEnd(event); } } |
也要去改掉,因为React的SyntheticEvent没有type
另外先去:
android webview javascript touchstart not work
touchstart and touchend events does not work on Webview in Android – Stack Overflow
javascript – touchend event doesn’t work on Android – Stack Overflow
javascript – Android browsers not handling touchmove events correctly – Stack Overflow
Android – JavaScript : touchstart event not fired until zoom or scroll the page – Stack Overflow
android webview react js touchstart not work
android webview react js touchstart sometime not work
后来的后来,
不去继续测试自己的Android手机:锤子M1L了 Android 6.0.1
换用:
别的安卓手机:小米6 Android 7.1.1系统,然后日期选择的滚动是很完美的运行的。
另外再去换用:
直接用自己的锤子里面的移动端浏览器去打开对应的页面:
锥子内置浏览器
QQ浏览器
都是可以正常滑动选择日期的:
【总结】
经过一堆的测试:
别的安卓手机(小米6 Android 7.1.1、小米4C Android 7.0),和别的移动端浏览器(QQ浏览器,锥子自带浏览器),都是正常可以滑动选择日期的。
就是我自己的锥子的M1L的Android 6.0.1 中,无法正常滑动选择日期。
算是我的手机的适配性有问题。不算是程序的bug。
【后记1】
然后让Android人员帮忙打包了一个,用WebViewClient(之前是用WebChromeClient)的浏览器内核,然后日期滑动选择问题,貌似有一点点改善?但是问题依旧。
【后记2】
【未解决】锤子M1L浏览器内核滑动选择日期时出现警告:chromium Ignored attempt to cancel a touchend event
但是,对于此处的react-mobile-datepicker库来说,其代码写的也是有待改进的,此处,专门去记录,改动后的代码,以备后查:
【记录】修改后的react-mobile-datepicker的源码
【整理】Android中的两种Webview:WebViewClient WebChromeClient
【整理】Android手机端浏览器内核:Crosswalk vs 腾讯X5
然后再去想办法,连接手机端的webview去调试:
【已解决】如何远程调试Android手机端的原生app内嵌的Chrome内核的浏览器的H5页面
结果chrome有bug,没法远程调试->后来发现是:手机特殊,没法调试,换个android就可以chrome调试了。
再去把:
event.preventDefault();
换成:
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
试试:
/** * 滑动日期选择器触屏事件 * @param {Object} event 事件对象 * @return {undefined} */ handleContentTouch(event) { // event.preventDefault(); if (this.animating) return; if (event.type === ‘touchstart’) { // event.preventDefault(); event.stopPropagation(); event.nativeEvent.stopImmediatePropagation(); this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { // event.preventDefault(); event.stopPropagation(); event.nativeEvent.stopImmediatePropagation(); this.handleEnd(event); } } |
结果:
还是没有更多的改进。
【总结】
此处,对于现象:
锥子M1L的(Android 6.0.1)手机中,app内嵌Webview中显示年月日的滚动条,基本上没发工作,用力滑动很多次,基本上很难滚动,偶尔巧了,能滚动几下,但是马上又无法滚动了。
最终的结论是:
主要还是自己的手机的哪里不兼容的问题,导致上述日期滑动的问题的。
初步判断,或许是Android手机内置的webview的版本太低?但是目前没发验证,不知道内嵌webview的版本是多少
而别的手机:
(1)小米4C Android 7.0
(2)小米6 Android 7.1.1
(3)锥子M1L的手机端其他浏览器:QQ浏览器,锥子内置浏览器
都是可以正常混动选择日期的。
且同样代码,iOS的iPhone端,始终都是可以顺畅的滚动的。
经过一番调试和优化,最终:
通过对于:
/node_modules/react-mobile-datepicker/lib/DatePickerItem.js
把:
handleContentTouch(event) { event.preventDefault(); if (this.animating) return; if (event.type === ‘touchstart’) { this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { this.handleEnd(event); } } |
改为:
handleContentTouch(event) { if (this.animating) return; if (event.type === ‘touchstart’) { event.preventDefault(); this.handleStart(event); } else if (event.type === ‘touchmove’) { this.handleMove(event); } else if (event.type === ‘touchend’) { event.preventDefault(); this.handleEnd(event); } } |
把锥子M1L中的日期滑动,从90%的不工作,优化到50%的不工作(开始几次用力滑动后,之后基本上就可以顺畅滑动了)
但是还是没有彻底解决问题,也没有找到根本原因。以后再说。
备注:
react-component/m-date-picker: React Mobile DatePicker(web & react-native)
看起来好像还可以,以后抽空可以去试试效果如何。
转载请注明:在路上 » 【部分解决】ReactJS中react-mobile-datepicker中input被设置readonly时无法滚动选择日期