index.jsx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import React,{Component} from 'react';
  2. import className from 'classnames';
  3. import {NumberPan,Notify} from '@commonComp';
  4. import style from './index.less';
  5. /***
  6. * author:zn@2018-11-19
  7. * 接收参数:
  8. * value: 默认选中的值
  9. * placeholder:灰显文字
  10. * handleSelect: 选中事件
  11. * show: 是否显示下拉
  12. * allClick:是否前后缀也可唤出数字键盘
  13. *
  14. * ***/
  15. class NumberDrop extends Component{
  16. constructor(props){
  17. super(props);
  18. this.state={
  19. /*editable:false, //标签是否可输入*/
  20. timer:null,
  21. sltTimer:null,
  22. blurTimer:null,
  23. hasSelect:false, //是否点过下拉键盘
  24. placeholder:props.placeholder
  25. };
  26. this.$span = React.createRef();
  27. this.numInpBlur = this.numInpBlur.bind(this);
  28. this.handleSpanInp = this.handleSpanInp.bind(this);
  29. this.handleNumClick = this.handleNumClick.bind(this);
  30. this.handleNumFocus = this.handleNumFocus.bind(this);
  31. this.handleKeyDowm = this.handleKeyDowm.bind(this);
  32. this.beyondArea = this.beyondArea.bind(this);
  33. }
  34. select(text){ //选中键盘上数字事件
  35. //placeholder修改后,第一次点击键盘触发blur后onClick不触发,原因未知,改为onMouseup可触发
  36. let timer = null;
  37. clearTimeout(this.state.sltTimer);
  38. clearTimeout(this.state.blurTimer);
  39. const {handleSelect,ikey,suffix,prefix,mainSaveText,min,max} = this.props;
  40. const needCompare=min!=undefined&&max!=undefined;
  41. if(!text){
  42. this.setState({
  43. placeholder:this.props.placeholder
  44. });
  45. }else{
  46. if(needCompare){
  47. const that = this;
  48. const isFine = this.validSymbols(text,min,max); //有~或/时是否合理
  49. const hasSymbol = /[\/|\~]/g.test(text); //是否有~或/
  50. const singleFine = !isNaN(+text)&&parseFloat(min)<=parseFloat(text)&&parseFloat(text)<=parseFloat(max); //无~或/时是否合理
  51. timer = setTimeout(function(){
  52. clearTimeout(that.state.sltTimer);
  53. if(text!=''&&(!hasSymbol&&!singleFine)||(hasSymbol&&!isFine)){
  54. that.beyondArea();
  55. return;
  56. }
  57. },1500);
  58. }
  59. this.setState({
  60. hasSelect:true,
  61. sltTimer:timer
  62. });
  63. }
  64. handleSelect&&handleSelect({ikey,text,suffix,prefix,mainSaveText});
  65. }
  66. beyondArea(){
  67. const {handleSelect,ikey,suffix,prefix,mainSaveText} = this.props;
  68. Notify.info("输入数值不符合规范,请重新输入!");
  69. handleSelect&&handleSelect({ikey,text:'',suffix,prefix,mainSaveText});
  70. this.setState({
  71. placeholder:this.props.placeholder,
  72. hasSelect:false
  73. });
  74. }
  75. handleNumFocus(e){ //数字框可编辑状态下聚集事件,处理是否显示下拉等
  76. const {placeholder} = this.state;
  77. const val = e.target.innerText.trim();
  78. //console.log(33,e.target.innerText,placeholder,e.target.innerText.trim() == placeholder)
  79. if(val!=''&&val == placeholder){
  80. this.setState({
  81. placeholder:''
  82. });
  83. }
  84. e.stopPropagation();
  85. }
  86. handleKeyDowm(e){
  87. if(e.keyCode==13){
  88. const {reFocus,num,handleHide} = this.props;
  89. reFocus&&reFocus(num);
  90. handleHide && handleHide();
  91. }
  92. }
  93. handleNumClick(e){ //数字框不可编辑的状态时点击事件,点击将数字框变为可输入且下拉不再显示直到失焦后再次聚集
  94. e.stopPropagation();
  95. const {show,handleShow,ikey,id,patId,handleHide,value} = this.props;
  96. if(show) {
  97. handleHide && handleHide();
  98. return;
  99. }else{
  100. this.$span.current.focus();
  101. this.setState({
  102. hasSelect:false
  103. });
  104. handleShow&&handleShow({ikey,id:patId||id});
  105. }
  106. }
  107. validSymbols(txt,min,max){
  108. //输入只有一个~或/时判断两边是否为合理数字,有多个为不合理
  109. const index1 = txt.indexOf('~');
  110. const index2 = txt.indexOf('/');
  111. const needCompare = min!=undefined&&max!=undefined;
  112. let arr1=[],arr2=[];
  113. if(index1!=-1&&index1==txt.lastIndexOf('~')&&index1!=txt.length-1){ //有且只有一个~,且不在最后
  114. arr1 = txt.split('~');
  115. //~的范围在合理范围内为合理值
  116. if(!isNaN(+arr1[0])&&!isNaN(+arr1[1])&&((!needCompare)||(needCompare&&parseFloat(min)<=parseFloat(arr1[0])&&parseFloat(arr1[0])<=parseFloat(max)&&parseFloat(min)<=parseFloat(arr1[1])&&parseFloat(arr1[1])<=parseFloat(max)))){
  117. return true
  118. }
  119. return false;
  120. }
  121. if(index2!=-1&&index2==txt.lastIndexOf('/')&&index2!=txt.length-1){ //有且只有一个~,且不在最后
  122. arr2 = txt.split('/');
  123. // /两边的数字分别在合理范围内为合理值
  124. if(!isNaN(+arr2[0])&&!isNaN(+arr2[1])&&((!needCompare)||(needCompare&&parseFloat(min)<=parseFloat(arr2[0])&&parseFloat(arr2[0])<=parseFloat(max)&&parseFloat(min)<=parseFloat(arr2[1])&&parseFloat(arr2[1])<=parseFloat(max)))){
  125. return true
  126. }
  127. return false;
  128. }
  129. return false;
  130. }
  131. numInpBlur(e){ //数字框失焦,保存值到store中
  132. e.stopPropagation();
  133. const {handleSelect,ikey,suffix,prefix,mainSaveText,min,max,show} = this.props;
  134. /*if(show){ //修改清空后第一次点击键盘不触发click事件bug--失焦placehoder消失,弃用
  135. return;
  136. }*/
  137. //输入超出合理范围或输入不是数字提示且清空
  138. const needCompare=min!=undefined&&max!=undefined;
  139. const txt = e.target.innerText.trim();
  140. const isFine = this.validSymbols(txt,min,max); //有~或/时是否合理
  141. const hasSymbol = /[\/|\~]/g.test(txt); //是否有~或/
  142. const singleFine = (!isNaN(+txt)&&!needCompare)||(!isNaN(+txt)&&needCompare&&parseFloat(min)<=parseFloat(txt)&&parseFloat(txt)<=parseFloat(max)); //无~或/时是否合理
  143. if(txt!=''&&(!hasSymbol&&!singleFine)||(hasSymbol&&!isFine)){
  144. this.beyondArea();
  145. return;
  146. }
  147. //输入为空时显示placeholder
  148. const timer = setTimeout(()=>{
  149. if(!e.target.innerText.trim()){
  150. this.setState({
  151. placeholder:this.props.placeholder
  152. });
  153. }
  154. },200);
  155. this.setState({
  156. blurTimer:timer
  157. });
  158. const val = e.target.innerText.trim();
  159. const {placeholder} = this.state;
  160. let text = val===placeholder?'':val;
  161. //e.target.innerText = ''; //避免出现重复输入值
  162. handleSelect&&handleSelect({ikey,text,suffix,prefix,mainSaveText});
  163. }
  164. handleSpanInp(e){ //数字框输入事件
  165. e.stopPropagation();
  166. const {handleHide} = this.props;
  167. handleHide&&handleHide();
  168. }
  169. getClasses(){ //整个标签是否有值的状态
  170. const {hideTag,placeholder,value,isImports} = this.props;
  171. const val = value;
  172. const isSelected = val&&val!=placeholder?style['selected']:style['container'];
  173. const orgBorder = isImports&&!(val&&val!=placeholder)?style['orange-border']:'';
  174. const noTag = hideTag?style['no-tag']:'';
  175. return className(isSelected,noTag,orgBorder);
  176. }
  177. getSpanClass(){ //将被替换的文字选中状态显示
  178. const cls = this.props.show?style['blued']:'';
  179. return cls;
  180. }
  181. stopBubble(e){
  182. e.stopPropagation();
  183. }
  184. componentDidMount(){
  185. //设置最小宽度避免输入后宽度跳动
  186. const spanWidth = window.getComputedStyle(this.$span.current).width;
  187. this.$span.current.style.minWidth=spanWidth;
  188. //保存输入框dom以便聚焦
  189. const that = this;
  190. setTimeout(function(){ //多个其他史/现病史bug修改
  191. const {saveDoms} = that.props;
  192. saveDoms&&saveDoms(that.$span);
  193. })
  194. }
  195. componentWillReceiveProps(nextProps){
  196. if((nextProps.placeholder == this.props.placeholder)&&(nextProps.value == this.props.value)){
  197. return
  198. }
  199. this.setState({
  200. placeholder:nextProps.placeholder
  201. })
  202. }
  203. render(){
  204. const {prefix,suffix,show,value,handleHide,allClick} = this.props;
  205. const {placeholder,hasSelect} = this.state;
  206. return <div className={this.getClasses()}
  207. style={{position:'relative'}}
  208. onClick={allClick?this.handleNumClick:null}>
  209. <span>{prefix}</span>
  210. <span onFocus={this.handleNumFocus}
  211. onClick={allClick?null:this.handleNumClick}
  212. contentEditable={true}
  213. style={{minWidth:'10px',display:'inline-block',textAlign:'center'}}
  214. ref = {this.$span}
  215. onKeyUp={this.handleKeyDowm}
  216. onBlur={this.numInpBlur}
  217. onInput={this.handleSpanInp}
  218. className={this.getSpanClass()}
  219. >&nbsp;{value||placeholder}</span>
  220. <span>{suffix}</span>
  221. <NumberPan handleSelect={this.select.bind(this)}
  222. onClose={handleHide}
  223. show={show}
  224. toClear={!hasSelect}/>
  225. </div>
  226. }
  227. }
  228. export default NumberDrop;