123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- import React,{Component} from 'react';
- import className from 'classnames';
- import {NumberPan,Notify} from '@commonComp';
- import style from './index.less';
- import $ from "jquery";
- import {handleEnter,getPageCoordinate} from '@utils/tools.js';
- /***
- * author:zn@2018-11-19
- * 接收参数:
- * value: 默认选中的值
- * placeholder:灰显文字
- * handleSelect: 选中事件
- * show: 是否显示下拉
- * allClick:是否前后缀也可唤出数字键盘
- *
- * ***/
- class NumberDrop extends Component{
- constructor(props){
- super(props);
- this.state={
- editable:false, //标签是否可输入
- timer:null,
- sltTimer:null,
- hasSelect:false, //是否点过下拉键盘
- boxLeft:0,
- boxTop:0,
- tmpTop:0,
- tmpScroll:0,
- placeholder:props.placeholder
- };
- this.$span = React.createRef();
- this.$pre = React.createRef();
- this.$suf = React.createRef();
- this.$cont = React.createRef();
- this.select = this.select.bind(this);
- this.numInpBlur = this.numInpBlur.bind(this);
- this.handleSpanInp = this.handleSpanInp.bind(this);
- this.handleNumClick = this.handleNumClick.bind(this);
- this.handleNumFocus = this.handleNumFocus.bind(this);
- this.handleBlur = this.handleBlur.bind(this);
- this.changeToEdit = this.changeToEdit.bind(this);
- this.handleKeyDowm = this.handleKeyDowm.bind(this);
- this.beyondArea = this.beyondArea.bind(this);
- }
- select(text){ //选中键盘上数字事件
- let timer = null;
- clearTimeout(this.state.sltTimer);
- const {handleSelect,ikey,suffix,prefix,mainSaveText,min,max} = this.props;
- const needCompare=min!=undefined&&max!=undefined;
- if(!text){
- this.setState({
- placeholder:this.props.placeholder
- });
- }else{
- //console.log(text,isNaN(+text),max<+text)
- if(needCompare){
- if(!isNaN(+text)&&max<+text){ //数值过大
- this.beyondArea();
- return;
- }
- const that = this;
- timer = setTimeout(function(){
- clearTimeout(that.state.sltTimer);
- if(!that.props.show&&!isNaN(+text)&&min>+text){
- that.beyondArea();
- return;
- }
- },1500);
- }
- this.setState({
- hasSelect:true,
- sltTimer:timer
- });
- }
- handleSelect&&handleSelect({ikey,text,suffix,prefix,mainSaveText});
- }
- beyondArea(){
- const {handleSelect,ikey,suffix,prefix,mainSaveText} = this.props;
- Notify.info("数值在正常值范围内,请重新输入");
- handleSelect&&handleSelect({ikey,text:'',suffix,prefix,mainSaveText});
- this.setState({
- placeholder:this.props.placeholder,
- hasSelect:false
- });
- }
- handleNumFocus(e){ //数字框可编辑状态下聚集事件,处理是否显示下拉等
- const {placeholder} = this.state;
- const val = e.target.innerText.trim();
- //console.log(33,e.target.innerText,placeholder,e.target.innerText.trim() == placeholder)
- if(val!=''&&val == placeholder){
- this.setState({
- placeholder:''
- });
- }
- e.stopPropagation();
- }
- handleNumClick(e){ //数字框不可编辑的状态时点击事件,点击将数字框变为可输入且下拉不再显示直到失焦后再次聚集
- const {show,handleShow,ikey,id,patId,handleHide,value} = this.props;
- this.$span.current.focus();
- if(show) {
- handleHide && handleHide();
- return;
- }else{
- const {editable} = this.state;
- if(editable){
- return;
- }
- const that = this;
- //双击时不显示下拉
- clearTimeout(that.state.timer);
- const timer = setTimeout(function(){
- //只有弹窗关闭则点击数字键盘会清空当前数据
- that.setState({
- hasSelect:false
- });
- handleShow&&handleShow({ikey,id:patId||id});
- },300);
- this.setState({
- timer,
- boxLeft:getPageCoordinate(e).boxLeft,
- boxTop:getPageCoordinate(e).boxTop,
- tmpScroll: $("#addScrollEvent")[0].scrollTop,
- tmpTop:getPageCoordinate(e).boxTop
- });
- $("#addScrollEvent").scroll(()=>{
- let scrollYs = $("#addScrollEvent")[0].scrollTop;
- this.setState({
- boxTop:this.state.tmpTop - scrollYs + this.state.tmpScroll
- })
- })
- }
- e.stopPropagation();
- }
- numInpBlur(e){ //数字框失焦,保存值到store中
- e.stopPropagation();
- const {handleSelect,ikey,suffix,prefix,mainSaveText,min,max,show} = this.props;
- if(show){ //修改清空后第一次点击键盘不触发click事件bug
- return;
- }
- const txt = e.target.innerText.replace(/^\s*/,'');
- if(max!=undefined&&!isNaN(+txt)&&(min>+txt||max<+txt)){
- this.beyondArea();
- return;
- }
- //输入为空时显示placeholder
- if(!e.target.innerText.trim()){
- this.setState({
- placeholder:this.props.placeholder
- });
- }
- /*this.setState({
- hasSelect:false
- });*/
- const val = e.target.innerText.replace(/^\s*/,'');
- const {placeholder} = this.state;
- let text = val===placeholder?'':val.replace(/[\u4e00-\u9fa5]/g,'');
- e.target.innerText = ''; //避免出现重复输入值
- handleSelect&&handleSelect({ikey,text,suffix,prefix,mainSaveText});
- }
- handleSpanInp(e){ //数字框输入事件
- e.stopPropagation();
- const {handleHide} = this.props;
- /*this.setState({ //再键盘点击数字要清空
- hasSelect:false
- });*/
- handleHide&&handleHide();
- }
- handleKeyDowm(e){
- handleEnter();
- //只能输入数字
- const key = e.key;
- const ctrlOn = e.ctrlKey;
- const isCopyPaste = ctrlOn&&(key=='v'||key=='c');
- if((!/[0-9|.|~|\/]/.test(key)&&key.length==1&&!isCopyPaste)){
- e.preventDefault();
- return false;
- }
- }
- getClasses(){ //整个标签是否有值的状态
- const {hideTag,placeholder,value} = this.props;
- const $span = this.$span.current;
- const val = value;//$span&&$span.innerText.trim()||value;
- const blueBorder = this.state.editable?style['blue-border']:'';
- const isSelected = val&&val!=placeholder?style['selected']:style['container'];
- const noTag = hideTag?style['no-tag']:'';
- return className(isSelected,noTag,blueBorder);
- }
- changeToEdit(e){ //整个标签双击编辑状态
- const {value,id,handleDbclick,patId,handleHide,show} = this.props;
- clearTimeout(this.state.timer);//取消延时的单击事件
- e.preventDefault();
- if(show){
- handleHide&&handleHide();
- }
- if(value&&value.trim()) {//有选中值的标签才能双击编辑
- this.setState({
- editable: true
- });
- setTimeout(()=>{
- this.$cont.current.focus();
- })
- //双击埋点记录
- handleDbclick && handleDbclick({id:patId||id});
- }
- }
- handleBlur(e){ //双击编辑blur
- const {handleLabelChange,ikey,boxMark,value} = this.props;
- //if(!this.state.editable) return;
- this.setState({
- editable: false
- });
- let totalVal = e.target.innerText;
- let changeVal = this.$span.current.innerText.replace(/^\s*/,'');//数字框值-修改后;去掉前空格避免多空格叠加
- let prefix = this.$pre.current.innerText.replace(/^\s*/,''); //前缀值-修改后
- let suffix = this.$suf.current.innerText.replace(/^\s*/,''); //后缀值-修改后
- //console.log('数字框:'+changeVal,";全部:"+totalVal,";前缀:"+prefix+";后缀:"+suffix);
- handleLabelChange && handleLabelChange({ikey,changeVal,type:boxMark,totalVal,prefix,suffix});
- }
- getSpanClass(){ //将被替换的文字选中状态显示
- //const {hasSelect} = this.state;
- const cls = this.props.show?style['blued']:'';
- return cls;
- }
- componentDidMount(){
- //设置最小宽度避免输入后宽度跳动
- const spanWidth = window.getComputedStyle(this.$span.current).width;
- this.$span.current.style.minWidth=spanWidth;
- }
- render(){
- const {prefix,suffix,show,value,handleHide,allClick} = this.props;
- const {numEditable,placeholder,editable,hasSelect,boxTop,boxLeft} = this.state;
- return <div className={this.getClasses()}
- ref={this.$cont}
- onDoubleClick={this.changeToEdit}
- onClick={allClick?this.handleNumClick:null}
- contentEditable={editable}
- onBlur={this.handleBlur}
- onkeydown={handleEnter}>
- <span ref = {this.$pre}> {prefix}</span>
- <span onFocus={this.handleNumFocus}
- onClick={allClick?null:this.handleNumClick}
- contentEditable={true}
- style={{minWidth:'10px',display:'inline-block',textAlign:'center'}}
- ref = {this.$span}
- onBlur={this.numInpBlur}
- onInput={this.handleSpanInp}
- className={this.getSpanClass()}
- onkeydown={this.handleKeyDowm}> {value||placeholder}</span>
- <span ref = {this.$suf}> {suffix}</span>
- <NumberPan handleSelect={(text)=>this.select(text)}
- onClose={handleHide}
- show={show}
- toClear={!hasSelect}
- left={boxLeft}
- top={boxTop}/>
- </div>
- }
- }
- export default NumberDrop;
|