143 lines
3.1 KiB
React
143 lines
3.1 KiB
React
|
|
||
|
import omit from 'omit.js'
|
||
|
import inputProps from './inputProps'
|
||
|
import calculateNodeHeight from './calculateNodeHeight'
|
||
|
import hasProp from '../_util/props-util'
|
||
|
|
||
|
function onNextFrame (cb) {
|
||
|
if (window.requestAnimationFrame) {
|
||
|
return window.requestAnimationFrame(cb)
|
||
|
}
|
||
|
return window.setTimeout(cb, 1)
|
||
|
}
|
||
|
|
||
|
function clearNextFrameAction (nextFrameId) {
|
||
|
if (window.cancelAnimationFrame) {
|
||
|
window.cancelAnimationFrame(nextFrameId)
|
||
|
} else {
|
||
|
window.clearTimeout(nextFrameId)
|
||
|
}
|
||
|
}
|
||
|
function fixControlledValue (value) {
|
||
|
if (typeof value === 'undefined' || value === null) {
|
||
|
return ''
|
||
|
}
|
||
|
return value
|
||
|
}
|
||
|
|
||
|
export default {
|
||
|
name: 'TextArea',
|
||
|
props: {
|
||
|
...inputProps,
|
||
|
autosize: [Object, Boolean],
|
||
|
},
|
||
|
model: {
|
||
|
prop: 'value',
|
||
|
event: 'change.value',
|
||
|
},
|
||
|
data () {
|
||
|
const { value, defaultValue } = this.$props
|
||
|
return {
|
||
|
stateValue: fixControlledValue(!hasProp(this, 'value') ? defaultValue : value),
|
||
|
nextFrameActionId: undefined,
|
||
|
textareaStyles: {},
|
||
|
}
|
||
|
},
|
||
|
computed: {
|
||
|
},
|
||
|
watch: {
|
||
|
value (val) {
|
||
|
this.stateValue = fixControlledValue(val)
|
||
|
if (this.nextFrameActionId) {
|
||
|
clearNextFrameAction(this.nextFrameActionId)
|
||
|
}
|
||
|
this.nextFrameActionId = onNextFrame(this.resizeTextarea)
|
||
|
},
|
||
|
},
|
||
|
mounted () {
|
||
|
this.resizeTextarea()
|
||
|
},
|
||
|
methods: {
|
||
|
handleKeyDown (e) {
|
||
|
if (e.keyCode === 13) {
|
||
|
this.$emit('pressEnter', e)
|
||
|
}
|
||
|
this.$emit('keydown', e)
|
||
|
},
|
||
|
resizeTextarea () {
|
||
|
const { autosize } = this.$props
|
||
|
if (!autosize || !this.$refs.textArea) {
|
||
|
return
|
||
|
}
|
||
|
const minRows = autosize ? autosize.minRows : null
|
||
|
const maxRows = autosize ? autosize.maxRows : null
|
||
|
const textareaStyles = calculateNodeHeight(this.$refs.textArea, false, minRows, maxRows)
|
||
|
this.textareaStyles = textareaStyles
|
||
|
},
|
||
|
|
||
|
getTextAreaClassName () {
|
||
|
const { prefixCls, disabled } = this.$props
|
||
|
return {
|
||
|
[prefixCls]: true,
|
||
|
[`${prefixCls}-disabled`]: disabled,
|
||
|
}
|
||
|
},
|
||
|
|
||
|
handleTextareaChange (e) {
|
||
|
if (!hasProp(this, 'value')) {
|
||
|
this.stateValue = e.target.value
|
||
|
this.$nextTick(() => {
|
||
|
this.resizeTextarea()
|
||
|
})
|
||
|
} else {
|
||
|
this.$forceUpdate()
|
||
|
this.$emit('change.value', e.target.value)
|
||
|
this.$emit('change', e)
|
||
|
}
|
||
|
this.$emit('input', e)
|
||
|
},
|
||
|
|
||
|
focus () {
|
||
|
this.$refs.textArea.focus()
|
||
|
},
|
||
|
|
||
|
blur () {
|
||
|
this.$refs.textArea.blur()
|
||
|
},
|
||
|
|
||
|
},
|
||
|
render () {
|
||
|
const { stateValue,
|
||
|
getTextAreaClassName,
|
||
|
handleKeyDown,
|
||
|
handleTextareaChange,
|
||
|
textareaStyles,
|
||
|
$attrs,
|
||
|
$listeners,
|
||
|
} = this
|
||
|
const otherProps = omit(this.$props, [
|
||
|
'prefixCls',
|
||
|
'autosize',
|
||
|
'type',
|
||
|
])
|
||
|
const textareaProps = {
|
||
|
attrs: { ...otherProps, ...$attrs },
|
||
|
on: {
|
||
|
...$listeners,
|
||
|
keydown: handleKeyDown,
|
||
|
input: handleTextareaChange,
|
||
|
},
|
||
|
}
|
||
|
return (
|
||
|
<textarea
|
||
|
{...textareaProps}
|
||
|
value={stateValue}
|
||
|
class={getTextAreaClassName()}
|
||
|
style={textareaStyles}
|
||
|
ref='textArea'
|
||
|
/>
|
||
|
)
|
||
|
},
|
||
|
}
|
||
|
|