refactor(login): 使用自定义输入框组件替换原生输入框 refactor(index): 重构网格布局代码,使用动态渲染方式 style: 更新全局字体样式,移除默认字体设置 chore: 添加多个字体文件和图标资源 docs: 更新应用名称和版本号
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> |