| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import Icon from '../icon';
- import Cell from '../cell';
- import { cellProps } from '../cell/shared';
- import { use, isObj, isDef, isIOS } from '../utils';
- import { preventDefault } from '../utils/event';
- import { getRootScrollTop } from '../utils/scroll';
- import { isNumber } from '../utils/validate/number';
- const [sfc, bem] = use('field');
- export default sfc({
- inheritAttrs: false,
- props: {
- ...cellProps,
- error: Boolean,
- leftIcon: String,
- rightIcon: String,
- readonly: Boolean,
- clearable: Boolean,
- labelWidth: [String, Number],
- labelAlign: String,
- inputAlign: String,
- onIconClick: Function,
- autosize: [Boolean, Object],
- errorMessage: String,
- errorMessageAlign: String,
- type: {
- type: String,
- default: 'text'
- }
- },
- data() {
- return {
- focused: false
- };
- },
- watch: {
- value() {
- this.$nextTick(this.adjustSize);
- }
- },
- mounted() {
- this.format();
- this.$nextTick(this.adjustSize);
- },
- computed: {
- showClear() {
- return (
- this.clearable && this.focused && this.value !== '' && isDef(this.value) && !this.readonly
- );
- },
- listeners() {
- return {
- ...this.$listeners,
- input: this.onInput,
- keypress: this.onKeypress,
- focus: this.onFocus,
- blur: this.onBlur
- };
- },
- labelStyle() {
- const { labelWidth } = this;
- if (labelWidth) {
- const width = isNumber(String(labelWidth)) ? `${labelWidth}px` : labelWidth;
- return {
- maxWidth: width,
- minWidth: width
- };
- }
- }
- },
- methods: {
- focus() {
- this.$refs.input && this.$refs.input.focus();
- },
- blur() {
- this.$refs.input && this.$refs.input.blur();
- },
- // native maxlength not work when type = number
- format(target = this.$refs.input) {
- let { value } = target;
- const { maxlength } = this.$attrs;
- if (this.type === 'number' && isDef(maxlength) && value.length > maxlength) {
- value = value.slice(0, maxlength);
- target.value = value;
- }
- return value;
- },
- onInput(event) {
- this.$emit('input', this.format(event.target));
- },
- onFocus(event) {
- this.focused = true;
- this.$emit('focus', event);
- // hack for safari
- /* istanbul ignore if */
- if (this.readonly) {
- this.blur();
- }
- },
- onBlur(event) {
- this.focused = false;
- this.$emit('blur', event);
- // Hack for iOS12 page scroll
- // https://developers.weixin.qq.com/community/develop/doc/00044ae90742f8c82fb78fcae56800
- /* istanbul ignore next */
- if (isIOS()) {
- window.scrollTo(0, getRootScrollTop());
- }
- },
- onClickLeftIcon() {
- this.$emit('click-left-icon');
- },
- onClickRightIcon() {
- // compatible old version
- this.$emit('click-icon');
- this.$emit('click-right-icon');
- this.onIconClick && this.onIconClick();
- },
- onClear(event) {
- preventDefault(event);
- this.$emit('input', '');
- this.$emit('clear');
- },
- onKeypress(event) {
- if (this.type === 'number') {
- const { keyCode } = event;
- const allowPoint = String(this.value).indexOf('.') === -1;
- const isValidKey =
- (keyCode >= 48 && keyCode <= 57) || (keyCode === 46 && allowPoint) || keyCode === 45;
- if (!isValidKey) {
- preventDefault(event);
- }
- }
- // trigger blur after click keyboard search button
- /* istanbul ignore next */
- if (this.type === 'search' && event.keyCode === 13) {
- this.blur();
- }
- this.$emit('keypress', event);
- },
- adjustSize() {
- const { input } = this.$refs;
- if (!(this.type === 'textarea' && this.autosize) || !input) {
- return;
- }
- input.style.height = 'auto';
- let height = input.scrollHeight;
- if (isObj(this.autosize)) {
- const { maxHeight, minHeight } = this.autosize;
- if (maxHeight) {
- height = Math.min(height, maxHeight);
- }
- if (minHeight) {
- height = Math.max(height, minHeight);
- }
- }
- if (height) {
- input.style.height = height + 'px';
- }
- },
- renderInput() {
- const inputProps = {
- ref: 'input',
- class: bem('control', this.inputAlign),
- domProps: {
- value: this.value
- },
- attrs: {
- ...this.$attrs,
- readonly: this.readonly
- },
- on: this.listeners
- };
- if (this.type === 'textarea') {
- return <textarea {...inputProps} />;
- }
- return <input type={this.type} {...inputProps} />;
- },
- renderLeftIcon() {
- const showLeftIcon = this.slots('left-icon') || this.leftIcon;
- if (showLeftIcon) {
- return (
- <div class={bem('left-icon')} onClick={this.onClickLeftIcon}>
- {this.slots('left-icon') || <Icon name={this.leftIcon} />}
- </div>
- );
- }
- },
- renderRightIcon() {
- const { slots } = this;
- const showRightIcon = slots('right-icon') || slots('icon') || this.rightIcon || this.icon;
- if (showRightIcon) {
- return (
- <div class={bem('right-icon')} onClick={this.onClickRightIcon}>
- {slots('right-icon') || slots('icon') || <Icon name={this.rightIcon || this.icon} />}
- </div>
- );
- }
- }
- },
- render(h) {
- const { slots, labelAlign } = this;
- const scopedSlots = {
- icon: this.renderLeftIcon
- };
- if (slots('label')) {
- scopedSlots.title = () => slots('label');
- }
- return (
- <Cell
- icon={this.leftIcon}
- size={this.size}
- title={this.label}
- center={this.center}
- border={this.border}
- isLink={this.isLink}
- required={this.required}
- titleStyle={this.labelStyle}
- titleClass={bem('label', labelAlign)}
- class={bem({
- error: this.error,
- disabled: this.$attrs.disabled,
- [`label-${labelAlign}`]: labelAlign,
- 'min-height': this.type === 'textarea' && !this.autosize
- })}
- scopedSlots={scopedSlots}
- >
- <div class={bem('body')}>
- {this.renderInput()}
- {this.showClear && <Icon name="clear" class={bem('clear')} onTouchstart={this.onClear} />}
- {this.renderRightIcon()}
- {slots('button') && <div class={bem('button')}>{slots('button')}</div>}
- </div>
- {this.errorMessage && <div class={bem('error-message', this.errorMessageAlign)}>{this.errorMessage}</div>}
- </Cell>
- );
- }
- });
|