You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

537 lines
16 KiB
Vue

1 year ago
<template>
<view class="d-block tm-input overflow"
:class="[
black_tmeme?(bgTheme?'grey-darken-5':''):bgTheme,
flat?'':`px-${padding[0]}`,
'round-'+ bgRound,
`shadow-${color}-${bgShadow}`
]"
>
<view
:class="(flat?'':` py-${padding[1]} `)+` ${borderBottom?black_tmeme?'border-grey-darken-4-b-1 ':'border-grey-lighten-4-b-1':''}`"
>
<view @click="onclickInput" :class="[vertical?'tm-input-col':'flex-between ']" :style="{
width: '100%',height: 'auto',
alignItems:inputType=='textarea'?'flex-start':'center'
}">
<!-- 左边内容 -->
<view v-if="leftIcon||title" class="tm-input-left flex-start flex-shrink" :class="[vertical?'pb-24':'']">
<!-- icon -->
<view v-if="leftIcon" class="pr-16 vertical-align-middle flex-center">
<tm-icons dense :name="leftIcon" :color="color_tmeme"></tm-icons>
</view>
<!-- 标题 -->
<view v-if="title" class="d-inline-block "
:style="{fontSize:title_size}"
:class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']">
<text v-if="_required" class="text-red">*</text>
<slot name="default" :title="title">
{{title}}
</slot>
</view>
</view>
<view class="flex-between " :class="[disabled?'opacity-6':'',]" style="width: 100%;">
<!-- input主体 -->
<view class="tm-input-center relative fulled" >
<view class="flex-start tm-input-center-wk"
:class="['round-'+round,showIndent?'px-16':'',
black_tmeme?(bgColor?'grey-darken-4 text-grey-lighten-3':'text-grey-lighten-3'):bgColor,
`text-${textColor}`,isFocus&&focusShow?(black_tmeme?`border-${color_tmeme}-a-1`:`${color_tmeme} outlined `):``,
`border-${black_tmeme?(borderColor?'grey-darken-4':''):borderColor}-a-1`,
]">
<view class="flex-shrink px-16 flex-center" v-if="prefixpIcon" style="line-height: 0;">
<tm-icons dense :name="prefixpIcon" :size="28" :color="(prefixpIconColor||color_tmeme)" ></tm-icons>
</view>
<view :style="{fontSize:font_size}" class="flex-shrink pr-24" :class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']" v-if="prefixpText">
{{prefixpText}}
</view>
<input always-embed v-if="inputType!='textarea'" @confirm="$emit('confirm',$event)" @input="input"
@keyboardheightchange="$emit('keyboardheightchange',$event)" @blur="blur"
@focus="focusFun" :focus="focus_fs" :maxlength="maxlength" :adjust-position="adjustPosition"
:auto-focus="autoFocus" :confirm-type="confirmType" :disabled="disabled"
:password="password" :type="inputType" :value="value" class="tm-input-center-input "
:class="['text-align-'+align,showError?'text-red':'',' py-5 ']" :placeholder="placeholder"
:placeholder-class="black_tmeme? 'text-grey-darken-1 ':' ' +` text-size-n ` + placeholderClass"
:style="{
fontSize:font_size,
height:height_rpx+'rpx'
}"
/>
<!-- uniapp的bug当输入框禁用时点击此处来获取新的焦点以让键盘收起 -->
<view v-if="disabled" class="absolute fulled t-0 r-0" :style="{
height:height_rpx+'rpx'
}"></view>
<textarea always-embed v-if="inputType=='textarea'" @confirm="$emit('confirm',$event)" @input="input"
@keyboardheightchange="$emit('keyboardheightchange',$event)" @blur="blur"
@focus="focusFun" :focus="focus_fs" :maxlength="maxlength" :adjust-position="adjustPosition"
:auto-focus="autoFocus" :confirm-type="confirmType" :disabled="disabled"
:value="value" class="tm-input-center-input " :style="{
height:height_rpx+'rpx',
fontSize:font_size,
}"
:class="[maxlength>0?'pb-46':'','text-align-'+align,showError?'text-red':'','pt-16 fulled']" :placeholder="placeholder"
:placeholder-class="black_tmeme? 'text-grey-darken-1 ':' text-grey-lighten-1 ' +` text-size-n `+ placeholderClass" >
</textarea>
<!-- 清除图标 -->
<view v-if="clear&&valdata.length!=''" class="flex-center pl-16">
<tm-icons @click.stop="clearVal" name="icon-times-circle-fill" :color="color_tmeme"></tm-icons>
</view>
<view v-if="suffixIcon" class="flex-center">
<tm-icons :size="26" :name="suffixIcon" :color="(suffixIconColor||color_tmeme)"></tm-icons>
</view>
</view>
<view v-if="maxlength>0&&inputType=='textarea'"
:style="{bottom:'16rpx',right:'16rpx'}"
class="tm-input-center-numXz text-align-right text-size-xxs pt-12 text-grey absolute fulled">{{valueLen}}/{{maxlength}}</view>
</view>
<!-- 右边 -->
<view class="tm-input-right flex-end flex-shrink">
<!-- 后缀文字比如单位 -->
<text v-if="suffix" class=" text-grey-darken-4 pl-10" :style="{fontSize:font_size}">{{suffix}}</text>
<!-- 后台图标 -->
<view v-if="rightIcon" class="pl-10" style="line-height: 0;">
<tm-icons dense :name="rightIcon" color="grey-lighten-1"></tm-icons>
</view>
<!-- 插入的按钮等内容 -->
<slot name="rightBtn"></slot>
</view>
</view>
</view>
<!-- detail出错成功等信息 -->
<view v-if="showError" class="text-size-xs text-red pt-12">{{errorText}}</view>
</view>
</view>
</template>
<script>
/**
* 输入框
* @property {Number} maxlength = [-1] 默认-1最大输入字符数
* @property {Boolean} black = [] 默认false暗黑模式
* @property {Function} verify = [] 默认 (val) => {check: val.length <= 0 ? false : true,text: "必填项不能为空。"}校验规则函数
* @property {String} title-class = [] 默认 text-grey-darken-4,自定左边标题或者上标题的类
* @property {Boolean} required = [] 默认 false, 是否是必填如果必填写将会触发基础的校验不能为空
* @property {Boolean} adjust-position = [] 默认 false, 是否上推键盘
* @property {Boolean} auto-focus = [] 默认 false, 自动获得焦点
* @property {String} confirm-type = [done|go|next|send|search] 默认 done, 键盘右下角确认按钮文字
* @property {Boolean} disabled = [] 默认 false, 禁用
* @property {Boolean} focus-show = [] 默认 false, 是否显示聚焦状态
* @property {Boolean} show-indent = [] 默认 false, 是滞使输入框内容两边缩进默认是
* @property {Boolean} password = [] 默认 false, 密码模式
* @property {String} input-type = [digit|text|number|password|idcard|textarea] 默认 text, 输入模式
* @property {String} value = [] 默认 "", 输入内容同v-model
* @property {String} right-icon = [] 默认 "", 后缀图标
* @property {String} left-icon = [] 默认 "", 外层前缀图标
* @property {String} prefixp-icon = [] 默认 "", 输入框内部前缀图标
* @property {String} prefixp-icon-color = [] 默认 "", 默认空使用主题color颜色
* @property {String} suffix = [] 默认 "", 后缀文字
* @property {String} suffix-icon = [] 默认 "", 输入框内后缀图标
* @property {String} suffix-icon-color = [] 默认 "", 默认使用主题图标
* @property {String} title = [] 默认 "", 左边标题
* @property {String} title-font-size = [xxs/xs/s/n/g/lg/xl] 默认 "n",同类的字号,xxs,xs,s,n,g,lg,xl
* @property {Number|String} font-size = [xxs/xs/s/n/g/lg/xl/任意数字] 默认 "n",同类的字号,xxs,xs,s,n,g,lg,xl也可以是数字单位rpx
* @property {String} align = [left|center|right] 默认 "", 输入框文字对齐方式left,center,right
* @property {Boolean} clear = [false|true] 默认 false, 显示清除图标
* @property {String} color = [] 默认 primary, 主题色名称
* @property {String} bg-color = [grey-lighten-5|white] 默认 grey-lighten-5, 输入框背景色
* @property {String} border-color = [] 默认 "", 输入框边框类型主题颜色名称
* @property {Boolean} border-bottom = [false|true] 默认 true, 是否显示下划线
* @property {String} text-color = [black|primary] 默认 black, 输入框文字颜色
* @property {String} placeholder = [] 默认 请输入, 占位文字
* @property {Boolean} vertical = [false|true] 默认 false, 是否上下排列
* @property {Number} round = [] 默认 2, 输入框圆角
* @property {Boolean} showIndent = [] 默认 true, 是否输入框内部两边缩进
* @property {Number} bg-round = [] 默认 0, 整体框圆角
* @property {Number} bg-shadow = [] 默认 0, 整体框投影
* @property {String} bg-theme = [] 默认white, 整体框背景
* @property {Boolean} flat = [] 默认 false, 是否去除所有边框
* @property {Number|String} height = [] 默认 68,
* @property {String} name = [] 默认''提交表单时的的字段名称标识
* @property {String} prefixp-text = [] 默认''输入框内前缀文字
* @property {String} placeholder-class = [] 默认''点位符的自定义类
* @property {Array} padding = [] 默认[32,12]左右上下内间距
* @property {Function} click 点击输入框时触发发的函数
* @property {Function} clear 清空时触发携带相关数据
* @property {Function} input 输入时触发携带相关数据
* @example <tm-input ></tm-input>
*
*/
import tmSheet from "@/tm-vuetify/components/tm-sheet/tm-sheet.vue"
import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
export default {
components:{tmSheet,tmIcons},
name:"tm-input",
props: {
//提交表单时的的字段名称
name:{
type:String,
default:''
},
prefixpText:{
type:String,
default:''
},
flat: {
type: Boolean,
default: false
},
//是否输入框内部两边缩进。默认是
showIndent:{
type:Boolean,
default:true
},
maxlength: {
type: Number,
default: -1
},
black: {
type:Boolean|String,
default:null
},
//是否显示聚焦状态
focusShow: {
type:Boolean|String,
default:false
},
titleFontSize:{
type:String,
default:'n',//同类的字号,xxs,xs,s,n,g,lg,xl
},
height:{
type:Number|String,
default:68
},
// 校验规则函数。
verify: {
type: Function,
default: ()=>{
return (val) => {
return {
check: val?.length <= 0 ? false : true,
text: "必填项不能为空。"
};
}
}
},
titleClass: {
type: String,
default: 'text-grey-darken-4'
},
// 是否是必填。如果必填写将会触发基础的校验,不能为空。
required: Boolean,
adjustPosition: Boolean,
autoFocus: Boolean,
confirmType: String,
disabled: Boolean,
password: Boolean,
inputType: {
type: String,
default: 'text'
},
value: {
type: String|Number,
default: ''
},
// 右边外层后缀图标。
rightIcon: {
type: String,
default: ''
},
// 输入框内部前缀图标。
prefixpIcon: {
type: String,
default: ''
},
prefixpIconColor: {
type: String,
default: ''
},
// 左边外层图标。
leftIcon: {
type: String,
default: ''
},
// 后缀文字
suffix: {
type: String,
default: ''
},
// 输入框后缀图标
suffixIcon: {
type: String,
default: ''
},
suffixIconColor:{
type: String,
default: ''
},
// 左边标题。
title: {
type: String,
default: ''
},
fontSize:{
type:Number|String,
default:'n'
},
// 输入框文字对齐方式。left,center,right
align: {
type: String,
default: 'left'
},
// 显示清除图标。
clear: Boolean,
// 主题色名称。
color: {
type: String,
default: 'primary'
},
//输入框背景色。grey-lighten-5
bgColor: {
type: String,
default: ''
},
// 输入框边框类型主题颜色名称。
borderColor: {
type: String,
default: ''
},
// 是否显示下划线
borderBottom: {
type: Boolean,
default: true
},
// text输入框文字颜色。
textColor: {
type: String,
default: 'black'
},
placeholder: {
type: String,
default: "请输入"
},
placeholderClass:{
type:String,
default:'text-grey-lighten-1'
},
// 是否上下排列输入框。
vertical: Boolean,
round:{
type:Number|String,
default:2
},
bgRound:{
type:Number|String,
default:0
},
bgShadow:{
type:Number|String,
default:0
},
bgTheme:{
type:String,
default:'white'
},
//获取焦点。
focus:{
type:Boolean,
default:false
},
padding:{
type:Array,
default:()=>{
return [32,12];
}
},
// 跟随主题色的改变而改变。
fllowTheme:{
type:Boolean|String,
default:true
}
},
data() {
return {
showError: false,
errorText: "请正确填写",
FOCUS_Auto:false,
isFocus:false,
};
},
computed: {
_required(){
return this.required
},
height_rpx:function(){
return this.height;
},
font_size:function () {
let font = {
'xxs':'20rpx',
'xs':'22rpx',
's':'24rpx',
'm':'26rpx',
'n':'28rpx',
'g':'32rpx',
'lg':'36rpx',
'xl':'40rpx'
}
if(typeof this.fontSize=='string') return font[this.fontSize];
return this.fontSize+'rpx';
},
title_size:function () {
let font = {
'xxs':'20rpx',
'xs':'22rpx',
's':'24rpx',
'm':'26rpx',
'n':'28rpx',
'g':'32rpx',
'lg':'36rpx',
'xl':'40rpx'
}
if(typeof this.titleFontSize=='string') return font[this.titleFontSize];
return this.titleFontSize+'rpx';
},
focus_fs:{
get:function(){
return this.FOCUS_Auto;
},
set:function(val){
this.FOCUS_Auto = val;
}
},
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme:function(){
if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
valueLen:function(){
// 为了兼容ios不能使用this.valdata.length.
let p = String(this.valdata);
return p?.split('').length||0 ;
},
valdata:{
get:function(){
return this.value;
},
set:function(val){
this.$emit('input', val)
this.$emit('update:value', val)
if (this._required) {
this.$nextTick(function(){
this.verifyInput();
})
}
}
}
},
mounten(){
this.FOCUS_Auto = this.focus;
},
methods: {
onclickInput(e){
this.$emit('click',e)
},
input(e) {
this.valdata = e.target.value;
},
// 校验是否通过。
verifyInput() {
let verify = this.verify.bind(this, this.valdata||'');
verify = verify.call(this,this.valdata||'')
if(typeof verify ==='function'){
verify = verify.call(this,this.valdata||'')
}
if (typeof verify !== 'object') verify = {};
this.showError = !(verify.check??true);
this.errorText = verify.text??"";
return verify.check??true;
},
//清除校验显示 的内容。
clearVerify() {
this.showError = false;
this.errorText = "";
},
blur(e) {
this.isFocus=false;
this.$emit('blur', e)
},
focusFun(e){
this.isFocus=true;
this.$emit('focus',e)
},
clearVal(e){
this.valdata ="";
this.$emit('clear', this.valdata)
}
},
}
</script>
<style lang="scss" scoped>
.tm-input {
.tm-input-center {
width: 100%;
.tm-input-center-wk{
transition: all 0.2s;
}
.tm-input-center-input {
border: none;
background: none;
box-shadow: 0;
width: 100%;
}
}
.tm-input-left {
flex-shrink: 0;
height: 100%;
min-width: 80rpx;
padding-right: 24rpx;
}
.tm-input-col {
.tm-input-left {
max-width: inherit;
padding-right: 0;
}
.tm-input-center {
.tm-input-center-input {
height: 76upx;
}
}
}
.tm-input-right {
height: 100%;
// width: 300upx;
}
}
</style>