nuke-input
Advanced tools
Comparing version 0.1.8 to 0.1.9
@@ -13,3 +13,3 @@ # 类型 | ||
import {createElement, Component} from 'weex-rx'; | ||
import { View, Text} from 'nuke-components'; | ||
import { View, Text, ScrollView} from 'nuke-components'; | ||
import Input from 'nuke-input'; | ||
@@ -24,6 +24,10 @@ import {mount} from 'nuke-mounter'; | ||
this.state = { | ||
inputVal:'', | ||
d1:'', | ||
d2:'', | ||
d3:'', | ||
textVal:'', | ||
valid1:'', | ||
valid2:'', | ||
data1:'', | ||
data2:'' | ||
} | ||
@@ -39,9 +43,23 @@ | ||
change=(e)=>{ | ||
console.log(e) | ||
c1=(e)=>{ | ||
console.log('onChange======>',e) | ||
this.setState({ | ||
d1: e | ||
}) | ||
} | ||
c2=(e)=>{ | ||
let value=e.value || e.target.value || ''; | ||
console.log('c2 onInput==>',value) | ||
this.setState({ | ||
inputVal: value | ||
d2 : value | ||
}) | ||
} | ||
c3=(e)=>{ | ||
console.log('c3 onChange======>',e) | ||
this.setState({ | ||
d3: e | ||
}) | ||
} | ||
textChange=(e)=>{ | ||
@@ -54,20 +72,60 @@ console.log(e) | ||
} | ||
d1change=(e)=>{ | ||
console.log(e) | ||
let value=e.value || e.target.value || ''; | ||
this.setState({ | ||
d1: value | ||
}) | ||
} | ||
d2change=(e)=>{ | ||
console.log(e) | ||
let value=e.value || e.target.value || ''; | ||
this.setState({ | ||
d2: value | ||
}) | ||
} | ||
render() { | ||
return ( | ||
<View style={{paddingTop:'30rem'}}> | ||
<View style={styles.st}><Text style={styles.stText}>单行</Text></View> | ||
<Input ref="myinput" placeholder="搜一搜..." value={this.state.inputVal} onChange={this.change.bind(this)} /> | ||
<ScrollView style={{paddingTop:'30rem'}}> | ||
<View style={styles.st}><Text style={styles.stText}>input inset 使用 onChange 事件</Text></View> | ||
<View style={[styles.row,{paddingLeft:0,paddingRight:0}]}><Input placeholder="搜一搜..." type="inset" value={this.state.d1} onChange={this.c1.bind(this)} style={{backgroundColor:'#f3f3f3'}} /></View> | ||
<Text>输入的是:{this.state.d1}</Text> | ||
<View style={styles.st}><Text style={styles.stText}>input onInput 实时获取</Text></View> | ||
<View style={styles.row}><Input placeholder="搜一搜..." defaultValue="羊绒大衣" onInput={this.c2.bind(this)} /></View> | ||
<Text>实时获取:{this.state.d2}</Text> | ||
<View style={styles.st}><Text style={styles.stText}>自定义样式</Text></View> | ||
<View style={styles.row}><Input style={{borderWidth:0,backgroundColor:'#3089dc',color:'#ffffff'}} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>带clear按钮</Text></View> | ||
<View style={styles.row}><Input hasClear={true} placeholder="搜一搜..." value={this.state.d3} onChange={this.c3.bind(this)} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>输入校验success反馈</Text></View> | ||
<Input hasFeedback="true" onChange={this.validate.bind(this,'success','valid1')} state={this.state.valid1} /> | ||
<View style={styles.row}><Input hasFeedback="true" onChange={this.validate.bind(this,'success','valid1')} state={this.state.valid1} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>输入校验error反馈</Text></View> | ||
<Input hasFeedback="true" placeholder="请输入..." onChange={this.validate.bind(this,'error','valid2')} state={this.state.valid2} /> | ||
<View style={styles.row}><Input hasFeedback="true" placeholder="请输入..." onChange={this.validate.bind(this,'error','valid2')} state={this.state.valid2} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>textarea</Text></View> | ||
<Input style={{height:'300rem'}} multiple={true} ref="xxx" placeholder="写一句自我介绍" onInput={this.textChange} value={this.state.textVal} onFocus={(e) => console.log('onFocus',e)} onBlur={(e) => console.log('onBlur',e)}/> | ||
<View style={styles.row}><Input style={{height:'300rem',marginBottom:'20rem'}} multiple={true} placeholder="设置高度300rem" onFocus={(e) => console.log('onFocus',e)} onBlur={(e) => console.log('onBlur',e)}/></View> | ||
<View style={styles.row}><Input multiple={true} placeholder="介绍一下" value="大家好我是xxxx" | ||
/></View> | ||
</View> | ||
<View style={styles.st}><Text style={styles.stText}>read only</Text></View> | ||
<View style={[styles.row,{marginBottom:'10rem'}]}><Input readOnly placeholder="输入姓名" defaultValue="只读"/></View> | ||
<View style={styles.row}><Input style={{height:'400rem',marginBottom:'10rem'}} readOnly multiple={true} placeholder="输入简介..." defaultValue="只读textarea"/></View> | ||
<View style={styles.st}><Text style={styles.stText}>disabled</Text></View> | ||
<View style={[styles.row,{marginBottom:'10rem'}]}><Input disabled placeholder="输入姓名" defaultValue="不可用"/></View> | ||
<View style={styles.row}><Input style={{height:'400rem',marginBottom:'10rem'}} disabled multiple={true} ref="d2" placeholder="输入简介..." defaultValue="不可用textarea"/></View> | ||
</ScrollView> | ||
); | ||
@@ -77,2 +135,7 @@ } | ||
const styles={ | ||
row:{ | ||
paddingLeft:'30rem', | ||
paddingRight:'30rem', | ||
}, | ||
st:{ | ||
@@ -79,0 +142,0 @@ marginBottom:'30rem', |
# Changelog | ||
## 0.1.9 / 2016-12-19 | ||
* [[be5c171](http://gitlab.alibaba-inc.com/nuke/input/commit/be5c171dadcad54c06a1cc5cc80f8e5bf6cd4b97)] - `feat` 重构input | ||
* [[c503b16](http://gitlab.alibaba-inc.com/nuke/input/commit/c503b16326db3e6856896f509cf15581bcb26c0a)] - `docs` update docs | ||
## 0.1.7 / 2016-11-30 | ||
@@ -5,0 +10,0 @@ |
475
lib/index.js
@@ -27,2 +27,6 @@ /** @jsx createElement */ | ||
var _nukeButton = require('nuke-button'); | ||
var _nukeButton2 = _interopRequireDefault(_nukeButton); | ||
var _nukeEnv = require('nuke-env'); | ||
@@ -36,2 +40,4 @@ | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
@@ -61,2 +67,15 @@ | ||
/** | ||
* 构造函数 | ||
*/ | ||
/** | ||
* 设置默认状态 | ||
*/ | ||
/** | ||
* 声明属性类型 | ||
*/ | ||
function Input(props) { | ||
@@ -67,2 +86,8 @@ _classCallCheck(this, Input); | ||
_this.state = { | ||
focus: false, | ||
value: _this.getPropValue('value') || '' | ||
}; | ||
_this.changeHandler = _this.changeHandler.bind(_this); | ||
@@ -72,23 +97,222 @@ _this.focusHandler = _this.focusHandler.bind(_this); | ||
_this.clearHandler = _this.clearHandler.bind(_this); | ||
_this.state = { | ||
focus: false, | ||
clearButton: true, | ||
state: '', | ||
value: _this.props.value || '' | ||
}; | ||
_this.timer = null; | ||
return _this; | ||
} | ||
/** | ||
* 设置默认属性 | ||
*/ | ||
_createClass(Input, [{ | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(newProps) {} | ||
value: function componentWillReceiveProps(newProps) { | ||
this.updateStateFromProps(newProps, ['type', 'value']); | ||
} | ||
/** | ||
* 渲染: 当state发生改变时立即执行 | ||
*/ | ||
}, { | ||
key: 'renderClear', | ||
value: function renderClear() { | ||
//如果已经设置了feedback, 则不出现clear | ||
key: 'render', | ||
value: function render() { | ||
var _props = this.props, | ||
hasFeedback = _props.hasFeedback, | ||
hasClear = _props.hasClear, | ||
_props$prefix = _props.prefix, | ||
prefix = _props$prefix === undefined ? this.defaultPrefix : _props$prefix, | ||
className = _props.className, | ||
state = _props.state, | ||
defaultValue = _props.defaultValue, | ||
value = _props.value, | ||
onChange = _props.onChange, | ||
onFocus = _props.onFocus, | ||
onBlur = _props.onBlur, | ||
readOnly = _props.readOnly, | ||
size = _props.size, | ||
disabled = _props.disabled, | ||
_props$style = _props.style, | ||
style = _props$style === undefined ? {} : _props$style, | ||
addonBefore = _props.addonBefore, | ||
addonAfter = _props.addonAfter, | ||
multiple = _props.multiple, | ||
readOnly = _props.readOnly, | ||
hasFeedback = _props.hasFeedback; | ||
_props$type = _props.type, | ||
type = _props$type === undefined ? 'enclosed' : _props$type, | ||
others = _objectWithoutProperties(_props, ['hasFeedback', 'hasClear', 'prefix', 'className', 'state', 'defaultValue', 'value', 'onChange', 'onFocus', 'onBlur', 'readOnly', 'size', 'disabled', 'style', 'addonBefore', 'addonAfter', 'multiple', 'type']); | ||
// style.textAlign = this.getValueFromContextAndProp('align') || 'left'; | ||
// const type = this.getValueFromContextAndProp('type') || 'enclosed'; | ||
//如果当前的没有设置, 则取上下文的state | ||
if (state === undefined) state = this.context.state; | ||
var baseClass = 'input'; | ||
var newStyle = Object.assign({}, _index2.default['input'], _index2.default[size], _index2.default['' + type], _index2.default['' + (multiple ? 'multiple' : 'single')], _index2.default[type + '-' + (multiple ? 'multiple' : 'single')], this.state.focus ? _index2.default['focus'] : {}, readOnly ? _index2.default[(multiple ? 'multiple' : 'single') + '-readonly'] : {}, disabled ? _index2.default[type + '-' + (multiple ? 'multiple' : 'single') + '-disabled'] : {}, _index2.default[type + '-' + (multiple ? 'multiple' : 'single') + '-' + state], style | ||
// { | ||
// [state]: state | ||
); | ||
var attrs = { | ||
// style: style, | ||
onChange: this.changeHandler, | ||
onFocus: this.focusHandler, | ||
onBlur: this.blurHandler, | ||
disabled: disabled, | ||
readOnly: readOnly, | ||
value: this.state.value, | ||
defaultValue: defaultValue | ||
}; | ||
// 防止重复定义带来的warning | ||
if ('value' in attrs) { | ||
delete attrs.defaultValue; | ||
} | ||
// 绕过h5下 readOnly 默认值问题 | ||
if ('readOnly' in attrs && !attrs.readOnly) { | ||
delete attrs.readOnly; | ||
} | ||
var inputElement = void 0; | ||
var flexVal = 'flex-' + (10 - (addonBefore ? 1 : 0) - (addonAfter ? 1 : 0)); | ||
var isAddonMode = (addonBefore || addonAfter) && !multiple; | ||
var customStyleFilter = {}; | ||
['color', 'fontSize', 'fontStyle', 'fontWeight', 'lineHeight', 'textAlign', 'textDecoration'].forEach(function (item) { | ||
if (style[item]) { | ||
// debugger; | ||
customStyleFilter[item] = style[item]; | ||
} | ||
}); | ||
var inputStyle = Object.assign({}, _index2.default['input-inner'], _index2.default[size], _index2.default[type + '-' + (multiple ? 'multiple' : 'single') + '-input'], _index2.default[(multiple ? 'multiple' : 'single') + '-input'], hasFeedback ? _index2.default['has-feedback-input'] : {}, hasClear && this.state.focus ? _index2.default['has-clear-input'] : {}, this.state.focus ? _index2.default['focus-input'] : {}, readOnly ? _index2.default[(multiple ? 'multiple' : 'single') + '-readonly-input'] : {}, disabled ? _index2.default[type + '-' + (multiple ? 'multiple' : 'single') + '-disabled-input'] : {}, customStyleFilter); | ||
if (multiple) { | ||
if (_nukeEnv.isWeb) { | ||
inputElement = (0, _weexRx.createElement)( | ||
'textarea', | ||
_extends({ style: inputStyle }, attrs, this.pickAttrs(others)), | ||
attrs.value | ||
); | ||
} else { | ||
inputElement = (0, _weexRx.createElement)('textarea', _extends({ style: inputStyle }, attrs, this.pickAttrs(others))); | ||
} | ||
} else { | ||
inputElement = (0, _weexRx.createElement)('input', _extends({}, attrs, this.pickAttrs(others), { | ||
type: this.props.htmlType, | ||
style: inputStyle | ||
})); | ||
} | ||
return (0, _weexRx.createElement)( | ||
_nukeComponents.View, | ||
{ style: newStyle }, | ||
(0, _weexRx.createElement)( | ||
_nukeComponents.View, | ||
{ x: 'innner-flex', style: _index2.default['inner-flex'] }, | ||
this.renderAddonBefore(baseClass, isAddonMode), | ||
(0, _weexRx.createElement)( | ||
_nukeComponents.View, | ||
{ x: 'innner-input-box', style: [_index2.default['inner-input-box'], _index2.default[flexVal]] }, | ||
inputElement, | ||
this.renderClear(baseClass), | ||
this.renderFeedback(baseClass), | ||
this.renderCounter(baseClass) | ||
), | ||
this.renderAddonAfter(baseClass, isAddonMode) | ||
) | ||
); | ||
} | ||
}, { | ||
key: 'getPropValue', | ||
value: function getPropValue(key) { | ||
var capitalKey = key.charAt(0).toUpperCase() + key.slice(1); | ||
var name = this.props[key] !== undefined ? key : 'default' + capitalKey; | ||
return this.props[name]; | ||
} | ||
}, { | ||
key: 'getValueFromContextAndProp', | ||
value: function getValueFromContextAndProp(key) { | ||
var value = this.context[key]; | ||
if (this.props.hasOwnProperty(key)) { | ||
value = this.props[key]; | ||
} | ||
return value; | ||
} | ||
}, { | ||
key: 'renderAddonBefore', | ||
value: function renderAddonBefore(baseClass, isAddonMode) { | ||
if (this.props.addonBefore && isAddonMode) { | ||
return (0, _weexRx.createElement)( | ||
'div', | ||
{ style: [_index2.default[baseClass + '-addon'], _index2.default[baseClass + '-addon-before']] }, | ||
this.props.addonBefore | ||
); | ||
} | ||
} | ||
}, { | ||
key: 'renderAddonAfter', | ||
value: function renderAddonAfter(baseClass, isAddonMode) { | ||
if (this.props.addonAfter && isAddonMode) { | ||
return (0, _weexRx.createElement)( | ||
'div', | ||
{ style: [_index2.default[baseClass + '-addon'], _index2.default[baseClass + '-addon-after']] }, | ||
this.props.addonAfter | ||
); | ||
} | ||
} | ||
}, { | ||
key: 'pickAttrs', | ||
value: function pickAttrs(props) { | ||
var attributes = 'accept acceptCharset accessKey action allowFullScreen allowTransparency\nalt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge\ncharSet checked classID className colSpan cols content contentEditable contextMenu\ncontrols coords crossOrigin data dateTime default defer dir disabled download draggable\nencType form formAction formEncType formMethod formNoValidate formTarget frameBorder\nheaders height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity\nis keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media\nmediaGroup method min minLength multiple muted name noValidate nonce open\noptimum pattern placeholder poster preload radioGroup readOnly rel required\nreversed role rowSpan rows sandbox scope scoped scrolling seamless selected\nshape size sizes span spellCheck src srcDoc srcLang srcSet start step style\nsummary tabIndex target title type useMap value width wmode wrap'.replace(/\s+/g, ' ').replace(/\t|\n|\r/g, '').split(' '), | ||
eventsName = 'onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown\n onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick\n onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown\n onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel\n onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough\n onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata\n onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError'.replace(/\s+/g, ' ').replace(/\t|\n|\r/g, '').split(' '), | ||
attrsPrefix = ['data-', 'aria-']; | ||
var attrs = {}; | ||
for (var key in props) { | ||
if (attributes.indexOf(key) > -1 || eventsName.indexOf(key) > -1) { | ||
attrs[key] = props[key]; | ||
} else if (attrsPrefix.map(function (prefix) { | ||
return new RegExp('^' + prefix); | ||
}).some(function (reg) { | ||
return key.replace(reg, '') != key; | ||
})) { | ||
attrs[key] = props[key]; | ||
} | ||
} | ||
return attrs; | ||
} | ||
//计数器 | ||
}, { | ||
key: 'renderCounter', | ||
value: function renderCounter(baseClass) { | ||
var _props2 = this.props, | ||
multiple = _props2.multiple, | ||
maxLength = _props2.maxLength, | ||
hasLimitHint = _props2.hasLimitHint; | ||
if (!(multiple && maxLength && hasLimitHint)) return; | ||
return (0, _weexRx.createElement)( | ||
'div', | ||
{ className: baseClass + '-counter' }, | ||
this.state.value.length, | ||
'/', | ||
maxLength | ||
); | ||
} | ||
}, { | ||
key: 'renderClear', | ||
value: function renderClear(baseClass) { | ||
//如果已经设置了feedback, 则不出现clear | ||
var _props3 = this.props, | ||
hasClear = _props3.hasClear, | ||
multiple = _props3.multiple, | ||
inMatrix = _props3.inMatrix, | ||
readOnly = _props3.readOnly, | ||
hasFeedback = _props3.hasFeedback, | ||
htmlType = _props3.htmlType, | ||
_props3$type = _props3.type, | ||
type = _props3$type === undefined ? 'enclosed' : _props3$type; | ||
var _state = this.state, | ||
@@ -98,8 +322,20 @@ focus = _state.focus, | ||
//hasClear与hasFeedback互斥 | ||
if (typeof hasFeedback === 'boolean' && hasFeedback === true) { | ||
hasClear = false; | ||
} | ||
if (!hasClear || multiple || !value || readOnly || hasFeedback) return null; | ||
return (0, _weexRx.createElement)(_nukeIcon2.default, { | ||
onPress: this.clearHandler, | ||
src: '//img.alicdn.com/tfs/TB1LKb1LXXXXXXnXpXXXXXXXXXX-40-40.jpg' }); | ||
//不在配置平台或者focus的情况下, 不处理 | ||
// if(!(inMatrix || focus)) return null; | ||
// 这里的button是一个清空按钮 | ||
// 如果input在表单里需要处理回车事件 | ||
// 但是这里又没有指定htmlType为button | ||
// 则会直接触发清空操作 | ||
var clearStyle = Object.assign({}, _index2.default['clear'], _index2.default['single-clear'], _index2.default[type + '-single-clear']); | ||
// console.log('clearstyle',clearStyle) | ||
return (0, _weexRx.createElement)(_nukeIcon2.default, { x: 'clear-icon', onPress: this.clearHandler, size: 'medium', name: 'deleteFilling', style: clearStyle }); | ||
} | ||
@@ -109,25 +345,30 @@ }, { | ||
value: function renderFeedback() { | ||
var _props4 = this.props, | ||
_props4$type = _props4.type, | ||
type = _props4$type === undefined ? 'enclosed' : _props4$type, | ||
multiple = _props4.multiple, | ||
hasFeedback = _props4.hasFeedback; | ||
//多行不出现反馈 | ||
if (this.props.multiple || !this.props.hasFeedback) return null; | ||
var src = ''; | ||
if (multiple || !hasFeedback) return null; | ||
var iconType = ''; | ||
var state = this.props.state; | ||
switch (state) { | ||
case 'success': | ||
src = '//img.alicdn.com/tfs/TB1SpzcLpXXXXcIXVXXXXXXXXXX-64-64.png'; | ||
break; | ||
case 'error': | ||
src = '//img.alicdn.com/tfs/TB1wlDmLpXXXXajXFXXXXXXXXXX-64-64.png'; | ||
break; | ||
} | ||
if (src) { | ||
return (0, _weexRx.createElement)(_nukeIcon2.default, { src: src }); | ||
} else { | ||
return null; | ||
} | ||
//如果没有设置state, 则从context中取state | ||
if (state === undefined) state = this.context.state; | ||
// switch(state){ | ||
// case 'success': | ||
// iconType = 'success-filling'; | ||
// break; | ||
// case 'error': | ||
// iconType = 'error-filling'; | ||
// break; | ||
// } | ||
// debugger; | ||
// console.log('type',type); | ||
// console.log('styles[`${type}-single-feedback`]',styles[`${type}-single-feedback`]); | ||
var feedbackStyle = Object.assign({}, _index2.default['feedback'], _index2.default['single-feedback'], _index2.default[type + '-single-feedback'], _index2.default['single-' + state + '-feedback']); | ||
return (0, _weexRx.createElement)(_nukeIcon2.default, { x: 'feedback-icon', name: state + 'Filling', size: 'medium', style: feedbackStyle }); | ||
} | ||
//发生变更 | ||
}, { | ||
@@ -137,20 +378,50 @@ key: 'changeHandler', | ||
var value = e.target.value; | ||
var clearButton = !!value; | ||
var maxLength = this.props.maxLength; | ||
this.trigger('onChange', value, e); | ||
this.setUnControlledState('value', value); | ||
// 不管有没有到达maxLength | ||
// !!!必须优先确保trigger onChange,让state与value同步 | ||
// 解决中文输入时由于value不同步被打断的问题 | ||
if (maxLength && value.length > maxLength) return; | ||
} | ||
}, { | ||
key: 'updateStateFromProps', | ||
value: function updateStateFromProps(props, keys, callback) { | ||
if (!keys) { | ||
keys = this.state && Object.keys(this.state) || []; | ||
} else if (typeof keys === 'string') { | ||
keys = [keys]; | ||
} | ||
var newState = { | ||
clearButton: clearButton | ||
}; | ||
//没有任何可更新的keys | ||
if (!keys.length) return; | ||
if (!this.props.hasOwnProperty('value')) { | ||
newState.value = value; | ||
var newState = {}; | ||
keys.map(function (key) { | ||
if (props.hasOwnProperty(key) && props[key] !== undefined) { | ||
newState[key] = props[key]; | ||
}; | ||
}); | ||
//如果用户提供了回调函数, 则由回调函数 | ||
if (callback) { | ||
callback(newState); | ||
} else { | ||
this.setState(newState); | ||
} | ||
} | ||
}, { | ||
key: 'trigger', | ||
value: function trigger(fn) { | ||
if (typeof fn === 'string') fn = this.props[fn]; | ||
if (!(typeof fn === 'function')) return; | ||
this.setState(newState); | ||
// debugger; | ||
this.props.onChange && this.props.onChange(e); | ||
// this.trigger('onChange', value, e); | ||
for (var _len = arguments.length, attrs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
attrs[_key - 1] = arguments[_key]; | ||
} | ||
return fn.apply(this, attrs); | ||
} | ||
@@ -164,4 +435,3 @@ }, { | ||
this.props.onFocus && this.props.onFocus(e); | ||
// this.trigger('onFocus', e); | ||
this.trigger('onFocus', e); | ||
} | ||
@@ -171,13 +441,14 @@ }, { | ||
value: function blurHandler(e) { | ||
var _this2 = this; | ||
//避免focus为false后, clear的button被隐藏的这种情况发生 | ||
//input的blur会在clear的click事件前触发 | ||
clearTimeout(this.timer); | ||
var that = this; | ||
this.timer = setTimeout(function () { | ||
that.setState({ | ||
_this2.setState({ | ||
focus: false | ||
}); | ||
// that.trigger('onBlur', e); | ||
_this2.trigger('onBlur', e); | ||
}, 10); | ||
@@ -188,79 +459,11 @@ } | ||
value: function clearHandler(e) { | ||
this.setState({ 'value': '' }); | ||
this.props.onClear && this.props.onClear(e); | ||
this.setUnControlledState('value', ''); | ||
this.trigger('onChange', '', e); | ||
} | ||
}, { | ||
key: 'pickAttrs', | ||
value: function pickAttrs(props) { | ||
return props; | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var self = this; | ||
key: 'setUnControlledState', | ||
value: function setUnControlledState(key, value) { | ||
if (this.props[key] !== undefined) return; | ||
var _props2 = this.props, | ||
hasFeedback = _props2.hasFeedback, | ||
hasClear = _props2.hasClear, | ||
_props2$prefix = _props2.prefix, | ||
prefix = _props2$prefix === undefined ? this.defaultPrefix : _props2$prefix, | ||
state = _props2.state, | ||
onChange = _props2.onChange, | ||
onFocus = _props2.onFocus, | ||
onBlur = _props2.onBlur, | ||
defaultValue = _props2.defaultValue, | ||
readOnly = _props2.readOnly, | ||
disabled = _props2.disabled, | ||
_props2$style = _props2.style, | ||
style = _props2$style === undefined ? {} : _props2$style, | ||
_props2$contentStyle = _props2.contentStyle, | ||
contentStyle = _props2$contentStyle === undefined ? {} : _props2$contentStyle, | ||
multiple = _props2.multiple, | ||
others = _objectWithoutProperties(_props2, ['hasFeedback', 'hasClear', 'prefix', 'state', 'onChange', 'onFocus', 'onBlur', 'defaultValue', 'readOnly', 'disabled', 'style', 'contentStyle', 'multiple']); | ||
//hasClear与hasFeedback互斥 | ||
if (hasFeedback) hasClear = false; | ||
// style.textAlign ='left'; | ||
var type = 'enclosed'; | ||
var disabledStyle = this.props.disabled ? INPUT_TYPES['disabled'] : {}; | ||
var errorStyle = this.props.state === 'error' ? INPUT_TYPES['error'] : {}; | ||
var errorTextStyle = this.props.state === 'error' ? INPUT_TYPES['errorText'] : {}; | ||
var wrapStyle = Object.assign({}, _index2.default[INPUT_TYPES['input']], _index2.default[disabledStyle], _index2.default[errorStyle], style); | ||
var inputStyle = {}; | ||
TextAttrArr.forEach(function (item) { | ||
if (wrapStyle[item]) { | ||
inputStyle[item] = wrapStyle[item]; | ||
} | ||
}); | ||
var attrs = { | ||
style: style, | ||
value: this.state.value, | ||
onChange: this.changeHandler, | ||
onFocus: this.focusHandler, | ||
onBlur: this.blurHandler, | ||
disabled: disabled, | ||
readOnly: readOnly | ||
}; | ||
var inputElement = void 0; | ||
if (multiple) { | ||
inputElement = (0, _weexRx.createElement)('textarea', _extends({}, attrs, { style: [_index2.default['nukeInputInput'], inputStyle, _index2.default[errorTextStyle]] }, this.pickAttrs(others))); | ||
} else { | ||
inputElement = (0, _weexRx.createElement)('input', _extends({}, attrs, this.pickAttrs(others), { | ||
type: this.props.htmlType, | ||
style: [_index2.default['nukeInputInput'], inputStyle, _index2.default[errorTextStyle]] | ||
})); | ||
} | ||
return (0, _weexRx.createElement)( | ||
_nukeComponents.View, | ||
{ style: wrapStyle }, | ||
inputElement, | ||
self.renderClear(), | ||
self.renderFeedback() | ||
); | ||
this.setState(_defineProperty({}, key, value)); | ||
} | ||
@@ -279,5 +482,7 @@ }]); | ||
hasClear: _weexRx.PropTypes.bool, | ||
type: _weexRx.PropTypes.oneOf(['enclosed', 'inset']), | ||
state: _weexRx.PropTypes.oneOf(['', 'success', 'error', 'warning']), | ||
value: _weexRx.PropTypes.string, | ||
defaultValue: _weexRx.PropTypes.string, | ||
value: _weexRx.PropTypes.any, | ||
defaultValue: _weexRx.PropTypes.any, | ||
size: _weexRx.PropTypes.oneOf(['small', 'large', 'medium']), | ||
disabled: _weexRx.PropTypes.bool, | ||
@@ -289,19 +494,25 @@ onClick: _weexRx.PropTypes.func, | ||
// 文本域前后附加内容 | ||
addonBefore: _weexRx.PropTypes.string, | ||
addonAfter: _weexRx.PropTypes.string, | ||
// 增加htmlType枚举检查 | ||
// mext-input用于文本输入型场景 | ||
// search type跟目前的hasClear有冲突 | ||
htmlType: _weexRx.PropTypes.oneOf(['text', 'tel', 'email', 'url', 'password']) | ||
htmlType: _weexRx.PropTypes.oneOf(['search', 'text', 'tel', 'email', 'url', 'password', 'number']) | ||
}; | ||
/** | ||
* 设置默认属性 | ||
*/ | ||
Input.defaultProps = { | ||
hasClear: true, | ||
hasClear: false, | ||
hasFeedback: false, | ||
multiple: false, | ||
size: 'medium', | ||
htmlType: 'text', | ||
hasLimitHint: false | ||
}; | ||
Input.contextTypes = { | ||
align: _weexRx.PropTypes.string, | ||
type: _weexRx.PropTypes.string, | ||
form: _weexRx.PropTypes.object, | ||
state: _weexRx.PropTypes.string | ||
}; | ||
exports.default = Input; | ||
module.exports = exports['default']; |
{ | ||
"name": "nuke-input", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"description": "输入框", | ||
@@ -38,3 +38,4 @@ "main": "lib/index", | ||
"nuke-env": "0.x.x", | ||
"nuke-icon": "0.x.x" | ||
"nuke-icon": "0.x.x", | ||
"nuke-button": "0.x.x" | ||
}, | ||
@@ -41,0 +42,0 @@ "devDependencies": {}, |
524
src/index.js
@@ -14,4 +14,6 @@ /** @jsx createElement */ | ||
import Icon from 'nuke-icon'; | ||
import Button from 'nuke-button'; | ||
import { isWeex , isWeb } from 'nuke-env'; | ||
import InputStyles from './index.rxscss'; | ||
import styles from './index.rxscss'; | ||
const INPUT_TYPES = { | ||
@@ -29,6 +31,78 @@ 'input': 'nukeInput', | ||
const TextAttrArr=['color','fontSize','fontStyle','fontWeight','lineHeight','textAlign','textDecoration','textDecoration']; | ||
class Input extends Component { | ||
constructor(props) { | ||
/** | ||
* 声明属性类型 | ||
*/ | ||
static propTypes = { | ||
readOnly: PropTypes.bool, | ||
inMatrix: PropTypes.bool, | ||
align: PropTypes.oneOf(['left', 'right', 'center']), | ||
multiple: PropTypes.bool, | ||
hasFeedback: PropTypes.bool, | ||
hasClear: PropTypes.bool, | ||
type: PropTypes.oneOf(['enclosed', 'inset']), | ||
state: PropTypes.oneOf(['', 'success', 'error', 'warning']), | ||
value: PropTypes.any, | ||
defaultValue: PropTypes.any, | ||
size: PropTypes.oneOf(['small', 'large', 'medium']), | ||
disabled: PropTypes.bool, | ||
onClick: PropTypes.func, | ||
maxLength: PropTypes.number, | ||
//是否显示限制长度的提示 | ||
hasLimitHint: PropTypes.bool, | ||
// 文本域前后附加内容 | ||
addonBefore: PropTypes.string, | ||
addonAfter: PropTypes.string, | ||
// 增加htmlType枚举检查 | ||
// mext-input用于文本输入型场景 | ||
htmlType: PropTypes.oneOf( | ||
[ | ||
'search', | ||
'text', | ||
'tel', | ||
'email', | ||
'url', | ||
'password', | ||
'number' | ||
] | ||
) | ||
}; | ||
/** | ||
* 设置默认属性 | ||
*/ | ||
static defaultProps = { | ||
hasClear: false, | ||
hasFeedback: false, | ||
multiple: false, | ||
size: 'medium', | ||
htmlType: 'text', | ||
hasLimitHint: false | ||
}; | ||
/** | ||
* 设置默认状态 | ||
*/ | ||
state = { | ||
focus: false, | ||
value: this.getPropValue('value') || '', | ||
}; | ||
static contextTypes = { | ||
align: PropTypes.string, | ||
type: PropTypes.string, | ||
form: PropTypes.object, | ||
state: PropTypes.string | ||
}; | ||
/** | ||
* 构造函数 | ||
*/ | ||
constructor(props){ | ||
super(props); | ||
this.changeHandler = this.changeHandler.bind(this); | ||
@@ -38,70 +112,310 @@ this.focusHandler = this.focusHandler.bind(this); | ||
this.clearHandler = this.clearHandler.bind(this); | ||
this.state={ | ||
focus: false, | ||
clearButton: true, | ||
state: '', | ||
value: this.props.value || '' | ||
} | ||
this.timer = null; | ||
} | ||
componentWillReceiveProps (newProps){ | ||
this.updateStateFromProps(newProps, ['type', 'value']); | ||
} | ||
renderClear(){ | ||
/** | ||
* 渲染: 当state发生改变时立即执行 | ||
*/ | ||
render() { | ||
let { | ||
hasFeedback, | ||
hasClear, | ||
prefix = this.defaultPrefix, | ||
className, | ||
state, | ||
defaultValue, | ||
value, | ||
onChange, | ||
onFocus, | ||
onBlur, | ||
readOnly, | ||
size, | ||
disabled, | ||
style = {}, | ||
addonBefore, | ||
addonAfter, | ||
multiple, | ||
type = 'enclosed', | ||
...others } = this.props; | ||
// style.textAlign = this.getValueFromContextAndProp('align') || 'left'; | ||
// const type = this.getValueFromContextAndProp('type') || 'enclosed'; | ||
//如果当前的没有设置, 则取上下文的state | ||
if(state === undefined) state = this.context.state; | ||
const baseClass = `input`; | ||
const newStyle = Object.assign({},styles['input'], | ||
styles[size], | ||
styles[`${type}`], | ||
styles[`${multiple ? 'multiple' : 'single'}`], | ||
styles[`${type}-${multiple ? 'multiple' : 'single'}`], | ||
this.state.focus ? styles['focus']:{}, | ||
readOnly ? styles[`${multiple ? 'multiple' : 'single'}-readonly`]:{}, | ||
disabled ? styles[`${type}-${multiple ? 'multiple' : 'single'}-disabled`]:{}, | ||
styles[`${type}-${multiple ? 'multiple' : 'single'}-${state}`], | ||
style | ||
// { | ||
// [state]: state | ||
); | ||
const attrs = { | ||
// style: style, | ||
onChange: this.changeHandler, | ||
onFocus: this.focusHandler, | ||
onBlur: this.blurHandler, | ||
disabled: disabled, | ||
readOnly: readOnly, | ||
value: this.state.value, | ||
defaultValue | ||
}; | ||
// 防止重复定义带来的warning | ||
if('value' in attrs) { | ||
delete attrs.defaultValue; | ||
} | ||
// 绕过h5下 readOnly 默认值问题 | ||
if('readOnly' in attrs && !attrs.readOnly) { | ||
delete attrs.readOnly; | ||
} | ||
let inputElement; | ||
let flexVal = `flex-${10 - (addonBefore ? 1 : 0) - (addonAfter ? 1 : 0)}`; | ||
let isAddonMode = (addonBefore || addonAfter) && (!multiple); | ||
let customStyleFilter={}; | ||
['color','fontSize','fontStyle','fontWeight','lineHeight','textAlign','textDecoration'].forEach((item)=>{ | ||
if(style[item]){ | ||
// debugger; | ||
customStyleFilter[item]=style[item]; | ||
} | ||
}) | ||
const inputStyle = Object.assign({},styles[`input-inner`], | ||
styles[size], | ||
styles[`${type}-${multiple ? 'multiple' : 'single'}-input`], | ||
styles[`${multiple ? 'multiple' : 'single'}-input`], | ||
hasFeedback ? styles[`has-feedback-input`]:{}, | ||
hasClear && this.state.focus ? styles['has-clear-input']:{}, | ||
this.state.focus ? styles['focus-input']:{}, | ||
readOnly ? styles[`${multiple ? 'multiple' : 'single'}-readonly-input`]:{}, | ||
disabled ? styles[`${type}-${multiple ? 'multiple' : 'single'}-disabled-input`]:{}, | ||
customStyleFilter | ||
); | ||
if(multiple){ | ||
if(isWeb){ | ||
inputElement = <textarea style={inputStyle} {...attrs} {...this.pickAttrs(others)}>{attrs.value}</textarea> | ||
}else{ | ||
inputElement = <textarea style={inputStyle} {...attrs} {...this.pickAttrs(others)} /> | ||
} | ||
}else{ | ||
inputElement = <input | ||
{...attrs} | ||
{...this.pickAttrs(others)} | ||
type={this.props.htmlType} | ||
style={inputStyle} | ||
/> | ||
} | ||
return ( | ||
<View style={newStyle}> | ||
<View x="innner-flex" style={styles['inner-flex']}> | ||
{this.renderAddonBefore(baseClass, isAddonMode)} | ||
<View x="innner-input-box" style={[styles[`inner-input-box`],styles[flexVal]]}> | ||
{inputElement} | ||
{this.renderClear(baseClass)} | ||
{this.renderFeedback(baseClass)} | ||
{this.renderCounter(baseClass)} | ||
</View> | ||
{this.renderAddonAfter(baseClass, isAddonMode)} | ||
</View> | ||
</View> | ||
); | ||
} | ||
getPropValue(key){ | ||
const capitalKey = key.charAt(0).toUpperCase() + key.slice(1); | ||
const name = this.props[key] !== undefined ? key : `default${capitalKey}`; | ||
return this.props[name]; | ||
} | ||
getValueFromContextAndProp(key){ | ||
let value = this.context[key]; | ||
if(this.props.hasOwnProperty(key)){ | ||
value = this.props[key]; | ||
} | ||
return value; | ||
} | ||
renderAddonBefore(baseClass, isAddonMode) { | ||
if(this.props.addonBefore && isAddonMode) { | ||
return ( | ||
<div style={[styles[`${baseClass}-addon`],styles[`${baseClass}-addon-before`]]}> | ||
{this.props.addonBefore} | ||
</div> | ||
); | ||
} | ||
} | ||
renderAddonAfter(baseClass, isAddonMode) { | ||
if(this.props.addonAfter && isAddonMode) { | ||
return ( | ||
<div style={[styles[`${baseClass}-addon`],styles[`${baseClass}-addon-after`]]}> | ||
{this.props.addonAfter} | ||
</div> | ||
); | ||
} | ||
} | ||
pickAttrs(props){ | ||
const attributes = `accept acceptCharset accessKey action allowFullScreen allowTransparency | ||
alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge | ||
charSet checked classID className colSpan cols content contentEditable contextMenu | ||
controls coords crossOrigin data dateTime default defer dir disabled download draggable | ||
encType form formAction formEncType formMethod formNoValidate formTarget frameBorder | ||
headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity | ||
is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media | ||
mediaGroup method min minLength multiple muted name noValidate nonce open | ||
optimum pattern placeholder poster preload radioGroup readOnly rel required | ||
reversed role rowSpan rows sandbox scope scoped scrolling seamless selected | ||
shape size sizes span spellCheck src srcDoc srcLang srcSet start step style | ||
summary tabIndex target title type useMap value width wmode wrap`.replace(/\s+/g,' ').replace(/\t|\n|\r/g, '').split(' '), | ||
eventsName = `onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown | ||
onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick | ||
onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown | ||
onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel | ||
onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough | ||
onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata | ||
onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError` | ||
.replace(/\s+/g,' ').replace(/\t|\n|\r/g, '').split(' '), | ||
attrsPrefix = ['data-', 'aria-']; | ||
var attrs = {}; | ||
for (var key in props) { | ||
if (attributes.indexOf(key) > -1 || eventsName.indexOf(key) > -1) { | ||
attrs[key] = props[key]; | ||
} | ||
else if (attrsPrefix.map(function (prefix) { | ||
return new RegExp('^' + prefix) | ||
}).some(function (reg) { | ||
return key.replace(reg, '') != key; | ||
})) { | ||
attrs[key] = props[key]; | ||
} | ||
} | ||
return attrs; | ||
} | ||
//计数器 | ||
renderCounter(baseClass){ | ||
const {multiple, maxLength, hasLimitHint} = this.props; | ||
if(!(multiple && maxLength && hasLimitHint)) return; | ||
return ( | ||
<div className={`${baseClass}-counter`}> | ||
{this.state.value.length}/{maxLength} | ||
</div> | ||
); | ||
} | ||
renderClear(baseClass){ | ||
//如果已经设置了feedback, 则不出现clear | ||
const {hasClear, multiple, readOnly, hasFeedback} = this.props; | ||
let {hasClear, multiple, inMatrix, readOnly, hasFeedback, htmlType , type = 'enclosed'} = this.props; | ||
const {focus, value} = this.state; | ||
//hasClear与hasFeedback互斥 | ||
if(typeof hasFeedback === 'boolean' && hasFeedback === true) { | ||
hasClear = false; | ||
} | ||
if(!hasClear || multiple || !value || readOnly || hasFeedback) return null; | ||
return (<Icon | ||
onPress={this.clearHandler} | ||
src="//img.alicdn.com/tfs/TB1LKb1LXXXXXXnXpXXXXXXXXXX-40-40.jpg"/>); | ||
//不在配置平台或者focus的情况下, 不处理 | ||
// if(!(inMatrix || focus)) return null; | ||
// 这里的button是一个清空按钮 | ||
// 如果input在表单里需要处理回车事件 | ||
// 但是这里又没有指定htmlType为button | ||
// 则会直接触发清空操作 | ||
const clearStyle = Object.assign({}, styles['clear'], | ||
styles['single-clear'], | ||
styles[`${type}-single-clear`] | ||
) | ||
// console.log('clearstyle',clearStyle) | ||
return ( | ||
<Icon x="clear-icon" onPress={this.clearHandler} size="medium" name="deleteFilling" style={clearStyle} /> | ||
); | ||
} | ||
renderFeedback(){ | ||
const { type = 'enclosed', multiple, hasFeedback } = this.props; | ||
//多行不出现反馈 | ||
if(this.props.multiple || !this.props.hasFeedback) return null; | ||
if(multiple || !hasFeedback) return null; | ||
let src = ''; | ||
let iconType = ''; | ||
let state = this.props.state; | ||
switch(state){ | ||
case 'success': | ||
src = '//img.alicdn.com/tfs/TB1SpzcLpXXXXcIXVXXXXXXXXXX-64-64.png'; | ||
break; | ||
case 'error': | ||
src = '//img.alicdn.com/tfs/TB1wlDmLpXXXXajXFXXXXXXXXXX-64-64.png'; | ||
break; | ||
} | ||
if(src){ | ||
return (<Icon src={src}/>); | ||
}else{ | ||
return null; | ||
} | ||
//如果没有设置state, 则从context中取state | ||
if(state === undefined) state = this.context.state; | ||
// switch(state){ | ||
// case 'success': | ||
// iconType = 'success-filling'; | ||
// break; | ||
// case 'error': | ||
// iconType = 'error-filling'; | ||
// break; | ||
// } | ||
// debugger; | ||
// console.log('type',type); | ||
// console.log('styles[`${type}-single-feedback`]',styles[`${type}-single-feedback`]); | ||
const feedbackStyle = Object.assign({}, styles['feedback'], | ||
styles['single-feedback'], | ||
styles[`${type}-single-feedback`], | ||
styles[`single-${state}-feedback`] | ||
) | ||
return <Icon x="feedback-icon" name={`${state}Filling`} size="medium" style={feedbackStyle} />; | ||
} | ||
//发生变更 | ||
changeHandler(e){ | ||
const value = e.target.value; | ||
const clearButton = !!value; | ||
const {maxLength} = this.props; | ||
this.trigger('onChange', value, e); | ||
this.setUnControlledState('value', value); | ||
// 不管有没有到达maxLength | ||
// !!!必须优先确保trigger onChange,让state与value同步 | ||
// 解决中文输入时由于value不同步被打断的问题 | ||
if(maxLength && value.length > maxLength) return; | ||
} | ||
updateStateFromProps(props, keys, callback){ | ||
if(!keys){ | ||
keys = (this.state && Object.keys(this.state)) || []; | ||
}else if(typeof(keys) === 'string'){ | ||
keys = [keys]; | ||
} | ||
let newState = { | ||
clearButton: clearButton | ||
} | ||
//没有任何可更新的keys | ||
if(!keys.length) return; | ||
let newState = {}; | ||
keys.map((key)=>{ | ||
if(props.hasOwnProperty(key) && props[key] !== undefined){ | ||
newState[key] = props[key]; | ||
}; | ||
}); | ||
if(!this.props.hasOwnProperty('value')){ | ||
newState.value = value; | ||
//如果用户提供了回调函数, 则由回调函数 | ||
if(callback){ | ||
callback(newState); | ||
}else{ | ||
this.setState(newState); | ||
} | ||
} | ||
trigger(fn, ...attrs){ | ||
if(typeof fn === 'string') fn = this.props[fn]; | ||
if(!(typeof fn === 'function')) return; | ||
this.setState(newState); | ||
// debugger; | ||
this.props.onChange && this.props.onChange(e); | ||
// this.trigger('onChange', value, e); | ||
} | ||
return fn.apply(this, attrs); | ||
} | ||
focusHandler(e){ | ||
@@ -112,4 +426,3 @@ this.setState({ | ||
this.props.onFocus && this.props.onFocus(e); | ||
// this.trigger('onFocus', e); | ||
this.trigger('onFocus', e); | ||
} | ||
@@ -121,10 +434,9 @@ | ||
clearTimeout(this.timer); | ||
const that = this; | ||
this.timer = setTimeout(function(){ | ||
that.setState({ | ||
this.timer = setTimeout(() => { | ||
this.setState({ | ||
focus: false | ||
}); | ||
// that.trigger('onBlur', e); | ||
this.trigger('onBlur', e); | ||
}, 10); | ||
@@ -134,115 +446,19 @@ } | ||
clearHandler(e){ | ||
this.setState({'value': ''}); | ||
this.props.onClear && this.props.onClear(e); | ||
this.setUnControlledState('value', ''); | ||
this.trigger('onChange', '', e); | ||
} | ||
pickAttrs(props){ | ||
return props; | ||
} | ||
render(){ | ||
var self=this; | ||
let { | ||
hasFeedback, | ||
hasClear, | ||
prefix = this.defaultPrefix, | ||
state, | ||
onChange, | ||
onFocus, | ||
onBlur, | ||
defaultValue, | ||
readOnly, | ||
disabled, | ||
style = {}, | ||
contentStyle={}, | ||
multiple, | ||
...others | ||
} = this.props; | ||
setUnControlledState(key, value){ | ||
if(this.props[key] !== undefined) return; | ||
//hasClear与hasFeedback互斥 | ||
if(hasFeedback) hasClear = false; | ||
// style.textAlign ='left'; | ||
const type = 'enclosed'; | ||
const disabledStyle = this.props.disabled?INPUT_TYPES['disabled'] :{}; | ||
const errorStyle = this.props.state==='error'?INPUT_TYPES['error'] :{}; | ||
const errorTextStyle = this.props.state==='error'?INPUT_TYPES['errorText'] :{}; | ||
const wrapStyle = Object.assign({},InputStyles[INPUT_TYPES['input']],InputStyles[disabledStyle],InputStyles[errorStyle], style); | ||
let inputStyle ={}; | ||
TextAttrArr.forEach((item)=>{ | ||
if(wrapStyle[item]){ | ||
inputStyle[item]=wrapStyle[item]; | ||
} | ||
}) | ||
const attrs = { | ||
style: style, | ||
value: this.state.value, | ||
onChange: this.changeHandler, | ||
onFocus: this.focusHandler, | ||
onBlur: this.blurHandler, | ||
disabled: disabled, | ||
readOnly: readOnly | ||
}; | ||
let inputElement; | ||
if(multiple){ | ||
inputElement = <textarea {...attrs} style={[InputStyles['nukeInputInput'],inputStyle,InputStyles[errorTextStyle]]} {...this.pickAttrs(others)} /> | ||
}else{ | ||
inputElement = <input | ||
{...attrs} | ||
{...this.pickAttrs(others)} | ||
type={this.props.htmlType} | ||
style={[InputStyles['nukeInputInput'],inputStyle,InputStyles[errorTextStyle]]} | ||
/> | ||
} | ||
return ( | ||
<View style={wrapStyle}> | ||
{inputElement} | ||
{self.renderClear()} | ||
{self.renderFeedback()} | ||
</View> | ||
); | ||
} | ||
this.setState({ | ||
[key]: value | ||
}) | ||
} | ||
} | ||
Input.propTypes = { | ||
readOnly: PropTypes.bool, | ||
inMatrix: PropTypes.bool, | ||
align: PropTypes.oneOf(['left', 'right', 'center']), | ||
multiple: PropTypes.bool, | ||
hasFeedback: PropTypes.bool, | ||
hasClear: PropTypes.bool, | ||
state: PropTypes.oneOf(['', 'success', 'error', 'warning']), | ||
value: PropTypes.string, | ||
defaultValue: PropTypes.string, | ||
disabled: PropTypes.bool, | ||
onClick: PropTypes.func, | ||
maxLength: PropTypes.number, | ||
//是否显示限制长度的提示 | ||
hasLimitHint: PropTypes.bool, | ||
// 增加htmlType枚举检查 | ||
// mext-input用于文本输入型场景 | ||
// search type跟目前的hasClear有冲突 | ||
htmlType: PropTypes.oneOf(['text', 'tel', 'email', 'url', 'password']) | ||
}; | ||
/** | ||
* 设置默认属性 | ||
*/ | ||
Input.defaultProps = { | ||
hasClear: true, | ||
hasFeedback: false, | ||
multiple: false, | ||
htmlType: 'text', | ||
hasLimitHint: false | ||
}; | ||
export default Input; | ||
/** @jsx createElement */ | ||
import {createElement, Component} from 'weex-rx'; | ||
import { View, Text} from 'nuke-components'; | ||
import { View, Text,ScrollView} from 'nuke-components'; | ||
import Input from 'nuke-input'; | ||
@@ -13,6 +13,10 @@ import {mount} from 'nuke-mounter'; | ||
this.state = { | ||
inputVal:'', | ||
d1:'', | ||
d2:'', | ||
d3:'', | ||
textVal:'', | ||
valid1:'', | ||
valid2:'', | ||
data1:'', | ||
data2:'' | ||
} | ||
@@ -28,9 +32,23 @@ | ||
change=(e)=>{ | ||
console.log(e) | ||
c1=(e)=>{ | ||
console.log('onChange======>',e) | ||
this.setState({ | ||
d1: e | ||
}) | ||
} | ||
c2=(e)=>{ | ||
let value=e.value || e.target.value || ''; | ||
console.log('c2 onInput==>',value) | ||
this.setState({ | ||
inputVal: value | ||
d2 : value | ||
}) | ||
} | ||
c3=(e)=>{ | ||
console.log('c3 onChange======>',e) | ||
this.setState({ | ||
d3: e | ||
}) | ||
} | ||
textChange=(e)=>{ | ||
@@ -43,20 +61,60 @@ console.log(e) | ||
} | ||
d1change=(e)=>{ | ||
console.log(e) | ||
let value=e.value || e.target.value || ''; | ||
this.setState({ | ||
d1: value | ||
}) | ||
} | ||
d2change=(e)=>{ | ||
console.log(e) | ||
let value=e.value || e.target.value || ''; | ||
this.setState({ | ||
d2: value | ||
}) | ||
} | ||
render() { | ||
return ( | ||
<View style={{paddingTop:'30rem'}}> | ||
<View style={styles.st}><Text style={styles.stText}>单行</Text></View> | ||
<Input ref="myinput" placeholder="搜一搜..." value={this.state.inputVal} onChange={this.change.bind(this)} /> | ||
<ScrollView style={{paddingTop:'30rem'}}> | ||
<View style={styles.st}><Text style={styles.stText}>input inset 使用 onChange 事件</Text></View> | ||
<View style={[styles.row,{paddingLeft:0,paddingRight:0}]}><Input placeholder="搜一搜..." type="inset" value={this.state.d1} onChange={this.c1.bind(this)} style={{backgroundColor:'#f3f3f3'}} /></View> | ||
<Text>输入的是:{this.state.d1}</Text> | ||
<View style={styles.st}><Text style={styles.stText}>input onInput 实时获取</Text></View> | ||
<View style={styles.row}><Input placeholder="搜一搜..." defaultValue="羊绒大衣" onInput={this.c2.bind(this)} /></View> | ||
<Text>实时获取:{this.state.d2}</Text> | ||
<View style={styles.st}><Text style={styles.stText}>自定义样式</Text></View> | ||
<View style={styles.row}><Input style={{borderWidth:0,backgroundColor:'#3089dc',color:'#ffffff'}} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>带clear按钮</Text></View> | ||
<View style={styles.row}><Input hasClear={true} placeholder="搜一搜..." value={this.state.d3} onChange={this.c3.bind(this)} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>输入校验success反馈</Text></View> | ||
<Input hasFeedback="true" onChange={this.validate.bind(this,'success','valid1')} state={this.state.valid1} /> | ||
<View style={styles.row}><Input hasFeedback="true" onChange={this.validate.bind(this,'success','valid1')} state={this.state.valid1} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>输入校验error反馈</Text></View> | ||
<Input hasFeedback="true" placeholder="请输入..." onChange={this.validate.bind(this,'error','valid2')} state={this.state.valid2} /> | ||
<View style={styles.row}><Input hasFeedback="true" placeholder="请输入..." onChange={this.validate.bind(this,'error','valid2')} state={this.state.valid2} /></View> | ||
<View style={styles.st}><Text style={styles.stText}>textarea</Text></View> | ||
<Input style={{height:'300rem'}} multiple={true} ref="xxx" placeholder="写一句自我介绍" onInput={this.textChange} value={this.state.textVal} onFocus={(e) => console.log('onFocus',e)} onBlur={(e) => console.log('onBlur',e)}/> | ||
<View style={styles.row}><Input style={{height:'300rem',marginBottom:'20rem'}} multiple={true} placeholder="设置高度300rem" onFocus={(e) => console.log('onFocus',e)} onBlur={(e) => console.log('onBlur',e)}/></View> | ||
<View style={styles.row}><Input multiple={true} placeholder="介绍一下" value="大家好我是xxxx" | ||
/></View> | ||
</View> | ||
<View style={styles.st}><Text style={styles.stText}>read only</Text></View> | ||
<View style={[styles.row,{marginBottom:'10rem'}]}><Input readOnly placeholder="输入姓名" defaultValue="只读"/></View> | ||
<View style={styles.row}><Input style={{height:'400rem',marginBottom:'10rem'}} readOnly multiple={true} placeholder="输入简介..." defaultValue="只读textarea"/></View> | ||
<View style={styles.st}><Text style={styles.stText}>disabled</Text></View> | ||
<View style={[styles.row,{marginBottom:'10rem'}]}><Input disabled placeholder="输入姓名" defaultValue="不可用"/></View> | ||
<View style={styles.row}><Input style={{height:'400rem',marginBottom:'10rem'}} disabled multiple={true} ref="d2" placeholder="输入简介..." defaultValue="不可用textarea"/></View> | ||
</ScrollView> | ||
); | ||
@@ -66,2 +124,7 @@ } | ||
const styles={ | ||
row:{ | ||
paddingLeft:'30rem', | ||
paddingRight:'30rem', | ||
}, | ||
st:{ | ||
@@ -68,0 +131,0 @@ marginBottom:'30rem', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
86220
967
5
1
+ Addednuke-button@0.x.x
+ Addednuke-button@0.3.19(transitive)