253 lines
5.3 KiB
Vue
253 lines
5.3 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="custom-input" :class="inputClass" :style="[wrapperStyle]">
|
|||
|
|
<view class="custom-input__content">
|
|||
|
|
<view class="custom-input__content__prefix-icon" v-if="prefixIcon">
|
|||
|
|
<u-icon
|
|||
|
|
:name="prefixIcon"
|
|||
|
|
:width="iconSize"
|
|||
|
|
:height="iconSize"
|
|||
|
|
:customStyle="prefixIconStyle"
|
|||
|
|
></u-icon>
|
|||
|
|
</view>
|
|||
|
|
<view class="custom-input__content__field-wrapper" @tap="clickHandler">
|
|||
|
|
<input
|
|||
|
|
class="custom-input__content__field-wrapper__field"
|
|||
|
|
:style="[inputStyle]"
|
|||
|
|
:type="type"
|
|||
|
|
:focus="focus"
|
|||
|
|
:value="value"
|
|||
|
|
:disabled="disabled"
|
|||
|
|
:maxlength="maxlength"
|
|||
|
|
:placeholder="placeholder"
|
|||
|
|
:password="password || type === 'password' || false"
|
|||
|
|
@input="onInput"
|
|||
|
|
@blur="onBlur"
|
|||
|
|
@focus="onFocus"
|
|||
|
|
@confirm="onConfirm"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
<view
|
|||
|
|
class="custom-input__content__suffix-icon"
|
|||
|
|
v-if="$slots.suffix"
|
|||
|
|
>
|
|||
|
|
<slot name="suffix"></slot>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
export default {
|
|||
|
|
name: 'CustomInput',
|
|||
|
|
props: {
|
|||
|
|
// 输入框的值
|
|||
|
|
value: {
|
|||
|
|
type: [String, Number],
|
|||
|
|
default: ''
|
|||
|
|
},
|
|||
|
|
// 输入框类型
|
|||
|
|
type: {
|
|||
|
|
type: String,
|
|||
|
|
default: 'text'
|
|||
|
|
},
|
|||
|
|
// 是否禁用输入框
|
|||
|
|
disabled: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 最大输入长度
|
|||
|
|
maxlength: {
|
|||
|
|
type: [String, Number],
|
|||
|
|
default: -1
|
|||
|
|
},
|
|||
|
|
// 占位符
|
|||
|
|
placeholder: {
|
|||
|
|
type: String,
|
|||
|
|
default: ''
|
|||
|
|
},
|
|||
|
|
// 是否密码类型
|
|||
|
|
password: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
},
|
|||
|
|
// 前置图标
|
|||
|
|
prefixIcon: {
|
|||
|
|
type: String,
|
|||
|
|
default: ''
|
|||
|
|
},
|
|||
|
|
// 前置图标样式
|
|||
|
|
prefixIconStyle: {
|
|||
|
|
type: [String, Object],
|
|||
|
|
default: () => ({})
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 图标大小
|
|||
|
|
iconSize: {
|
|||
|
|
type: [String, Number],
|
|||
|
|
default: 32
|
|||
|
|
},
|
|||
|
|
// 输入框字体大小
|
|||
|
|
fontSize: {
|
|||
|
|
type: [String, Number],
|
|||
|
|
default: '14px'
|
|||
|
|
},
|
|||
|
|
// 输入框字体颜色
|
|||
|
|
color: {
|
|||
|
|
type: String,
|
|||
|
|
default: '#333'
|
|||
|
|
},
|
|||
|
|
// 是否自动获取焦点
|
|||
|
|
focus: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
},
|
|||
|
|
// 边框类型
|
|||
|
|
border: {
|
|||
|
|
type: String,
|
|||
|
|
default: 'bottom' // none, bottom, surround
|
|||
|
|
},
|
|||
|
|
// 自定义样式
|
|||
|
|
customStyle: {
|
|||
|
|
type: Object,
|
|||
|
|
default: () => ({})
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
// 输入框的值
|
|||
|
|
innerValue: this.value
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
watch: {
|
|||
|
|
value(newVal) {
|
|||
|
|
this.innerValue = newVal;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
// 组件的类名
|
|||
|
|
inputClass() {
|
|||
|
|
let classes = [];
|
|||
|
|
const { border } = this;
|
|||
|
|
|
|||
|
|
if (border === 'surround') {
|
|||
|
|
classes = classes.concat(['custom-border', 'custom-input--radius']);
|
|||
|
|
} else if (border === 'bottom') {
|
|||
|
|
classes = classes.concat(['custom-border-bottom', 'custom-input--no-radius']);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return classes.join(' ');
|
|||
|
|
},
|
|||
|
|
// 组件的样式
|
|||
|
|
wrapperStyle() {
|
|||
|
|
const style = {};
|
|||
|
|
|
|||
|
|
// 无边框时,去除内边距
|
|||
|
|
if (this.border === 'none') {
|
|||
|
|
style.padding = '0';
|
|||
|
|
} else {
|
|||
|
|
// 由于uni-app的iOS开发者能力有限,导致需要分开写才有效
|
|||
|
|
style.paddingTop = '6px';
|
|||
|
|
style.paddingBottom = '6px';
|
|||
|
|
style.paddingLeft = '9px';
|
|||
|
|
style.paddingRight = '9px';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return Object.assign(style, this.customStyle);
|
|||
|
|
},
|
|||
|
|
// 输入框的样式
|
|||
|
|
inputStyle() {
|
|||
|
|
const style = {
|
|||
|
|
color: this.color,
|
|||
|
|
fontSize: this.fontSize,
|
|||
|
|
flex: 1
|
|||
|
|
};
|
|||
|
|
return style;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
// 当键盘输入时,触发input事件
|
|||
|
|
onInput(e) {
|
|||
|
|
const { value = '' } = e.detail || {};
|
|||
|
|
this.innerValue = value;
|
|||
|
|
this.$emit('input', value);
|
|||
|
|
// 为了支持v-model,需要同时触发update:value事件
|
|||
|
|
this.$emit('update:value', value);
|
|||
|
|
this.$emit('change', value);
|
|||
|
|
},
|
|||
|
|
// 输入框失去焦点时触发
|
|||
|
|
onBlur(event) {
|
|||
|
|
this.$emit('blur', event.detail.value);
|
|||
|
|
},
|
|||
|
|
// 输入框聚焦时触发
|
|||
|
|
onFocus(event) {
|
|||
|
|
this.$emit('focus');
|
|||
|
|
},
|
|||
|
|
// 点击完成按钮时触发
|
|||
|
|
onConfirm(event) {
|
|||
|
|
this.$emit('confirm', this.innerValue);
|
|||
|
|
},
|
|||
|
|
// 点击事件
|
|||
|
|
clickHandler() {
|
|||
|
|
this.$emit('click');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.custom-input {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: row;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
flex: 1;
|
|||
|
|
|
|||
|
|
&--radius {
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&--no-radius {
|
|||
|
|
border-radius: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.custom-border {
|
|||
|
|
border: 1px solid #dcdfe6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.custom-border-bottom {
|
|||
|
|
border-bottom: 1px solid #dcdfe6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__content {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: row;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
flex: 1;
|
|||
|
|
|
|||
|
|
&__prefix-icon {
|
|||
|
|
margin-right: 5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__field-wrapper {
|
|||
|
|
flex: 1;
|
|||
|
|
|
|||
|
|
&__field {
|
|||
|
|
width: 100%;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #333;
|
|||
|
|
|
|||
|
|
// 去除input的默认样式
|
|||
|
|
outline: none;
|
|||
|
|
border: none;
|
|||
|
|
background: none;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__suffix-icon {
|
|||
|
|
margin-left: 5px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|