tm-input.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. <template>
  2. <view class="d-block tm-input overflow"
  3. :class="[
  4. black_tmeme?(bgTheme?'grey-darken-5':''):bgTheme,
  5. flat?'':`px-${padding[0]}`,
  6. 'round-'+ bgRound,
  7. `shadow-${color}-${bgShadow}`
  8. ]"
  9. >
  10. <view
  11. :class="(flat?'':` py-${padding[1]} `)+` ${borderBottom?black_tmeme?'border-grey-darken-4-b-1 ':'border-grey-lighten-4-b-1':''}`"
  12. >
  13. <view @click="onclickInput" :class="[vertical?'tm-input-col':'flex-between ']" :style="{
  14. width: '100%',height: 'auto',
  15. alignItems:inputType=='textarea'?'flex-start':'center'
  16. }">
  17. <!-- 左边内容。 -->
  18. <view v-if="leftIcon||title" class="tm-input-left flex-start flex-shrink" :class="[vertical?'pb-24':'']">
  19. <!-- icon -->
  20. <view v-if="leftIcon" class="pr-16 vertical-align-middle flex-center">
  21. <tm-icons dense :name="leftIcon" :color="color_tmeme"></tm-icons>
  22. </view>
  23. <!-- 标题 -->
  24. <view v-if="title" class="d-inline-block "
  25. :style="{fontSize:title_size}"
  26. :class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']">
  27. <text v-if="required" class="text-red">*</text>
  28. <slot name="default" :title="title">
  29. {{title}}
  30. </slot>
  31. </view>
  32. </view>
  33. <view class="flex-between " :class="[disabled?'opacity-6':'',]" style="width: 100%;">
  34. <!-- input主体 -->
  35. <view class="tm-input-center relative fulled" >
  36. <view class="flex-start tm-input-center-wk"
  37. :class="['round-'+round,showIndent?'px-16':'',
  38. black_tmeme?(bgColor?'grey-darken-4 text-grey-lighten-3':'text-grey-lighten-3'):bgColor,
  39. `text-${textColor}`,isFocus&&focusShow?(black_tmeme?`border-${color_tmeme}-a-1`:`${color_tmeme} outlined `):``,
  40. `border-${black_tmeme?(borderColor?'grey-darken-4':''):borderColor}-a-1`,
  41. ]">
  42. <view class="flex-shrink px-16 flex-center" v-if="prefixpIcon" style="line-height: 0;">
  43. <tm-icons dense :name="prefixpIcon" :size="28" :color="(prefixpIconColor||color_tmeme)" ></tm-icons>
  44. </view>
  45. <view :style="{fontSize:font_size}" class="flex-shrink pr-24" :class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']" v-if="prefixpText">
  46. {{prefixpText}}
  47. </view>
  48. <input always-embed v-if="inputType!='textarea'" @confirm="$emit('confirm',$event)" @input="input"
  49. @keyboardheightchange="$emit('keyboardheightchange',$event)" @blur="blur"
  50. @focus="focusFun" :focus="focus_fs" :maxlength="maxlength" :adjust-position="adjustPosition"
  51. :auto-focus="autoFocus" :confirm-type="confirmType" :disabled="disabled"
  52. :password="password" :type="inputType" :value="value" class="tm-input-center-input "
  53. :class="['text-align-'+align,showError?'text-red':'',' py-5 ']" :placeholder="placeholder"
  54. :placeholder-class="black_tmeme? 'text-grey-darken-1 ':' ' +` text-size-n ` + placeholderClass"
  55. :style="{
  56. fontSize:font_size,
  57. height:height_rpx+'rpx'
  58. }"
  59. />
  60. <!-- uniapp的bug,当输入框禁用时,点击此处来获取新的焦点,以让键盘收起。 -->
  61. <view v-if="disabled" class="absolute fulled t-0 r-0" :style="{
  62. height:height_rpx+'rpx'
  63. }"></view>
  64. <textarea always-embed v-if="inputType=='textarea'" @confirm="$emit('confirm',$event)" @input="input"
  65. @keyboardheightchange="$emit('keyboardheightchange',$event)" @blur="blur"
  66. @focus="focusFun" :focus="focus_fs" :maxlength="maxlength" :adjust-position="adjustPosition"
  67. :auto-focus="autoFocus" :confirm-type="confirmType" :disabled="disabled"
  68. :value="value" class="tm-input-center-input " :style="{
  69. height:height_rpx+'rpx',
  70. fontSize:font_size,
  71. }"
  72. :class="[maxlength>0?'pb-46':'','text-align-'+align,showError?'text-red':'','pt-16 fulled']" :placeholder="placeholder"
  73. :placeholder-class="black_tmeme? 'text-grey-darken-1 ':' text-grey-lighten-1 ' +` text-size-n `+ placeholderClass" >
  74. </textarea>
  75. <!-- 清除图标 -->
  76. <view v-if="clear&&valdata.length!=''" class="flex-center pl-16">
  77. <tm-icons @click.stop="clearVal" name="icon-times-circle-fill" :color="color_tmeme"></tm-icons>
  78. </view>
  79. <view v-if="suffixIcon" class="flex-center">
  80. <tm-icons :size="26" :name="suffixIcon" :color="(suffixIconColor||color_tmeme)"></tm-icons>
  81. </view>
  82. </view>
  83. <view v-if="maxlength>0&&inputType=='textarea'"
  84. :style="{bottom:'16rpx',right:'16rpx'}"
  85. class="tm-input-center-numXz text-align-right text-size-xxs pt-12 text-grey absolute fulled">{{valueLen}}/{{maxlength}}</view>
  86. </view>
  87. <!-- 右边。 -->
  88. <view class="tm-input-right flex-end flex-shrink">
  89. <!-- 后缀文字,比如单位,等 -->
  90. <text v-if="suffix" class=" text-grey-darken-4 pl-10" :style="{fontSize:font_size}">{{suffix}}</text>
  91. <!-- 后台图标。 -->
  92. <view v-if="rightIcon" class="pl-10" style="line-height: 0;">
  93. <tm-icons dense :name="rightIcon" color="grey-lighten-1"></tm-icons>
  94. </view>
  95. <!-- 插入的按钮等内容。 -->
  96. <slot name="rightBtn"></slot>
  97. </view>
  98. </view>
  99. </view>
  100. <!-- detail出错成功等信息。 -->
  101. <view v-if="showError" class="text-size-xs text-red pt-12">{{errorText}}</view>
  102. </view>
  103. </view>
  104. </template>
  105. <script>
  106. /**
  107. * 输入框
  108. * @property {Number} maxlength = [-1] 默认:-1,最大输入字符数。
  109. * @property {Boolean} black = [] 默认:false,暗黑模式。
  110. * @property {Function} verify = [] 默认: (val) => {check: val.length <= 0 ? false : true,text: "必填项不能为空。"},校验规则函数。
  111. * @property {String} title-class = [] 默认: text-grey-darken-4,自定左边标题或者上标题的类。
  112. * @property {Boolean} required = [] 默认: false, 是否是必填。如果必填写将会触发基础的校验,不能为空。
  113. * @property {Boolean} adjust-position = [] 默认: false, 是否上推键盘。
  114. * @property {Boolean} auto-focus = [] 默认: false, 自动获得焦点。
  115. * @property {String} confirm-type = [done|go|next|send|search] 默认: done, 键盘右下角确认按钮文字。
  116. * @property {Boolean} disabled = [] 默认: false, 禁用。
  117. * @property {Boolean} focus-show = [] 默认: false, 是否显示聚焦状态。
  118. * @property {Boolean} show-indent = [] 默认: false, 是滞使输入框内容两边缩进。默认是。
  119. * @property {Boolean} password = [] 默认: false, 密码模式
  120. * @property {String} input-type = [digit|text|number|password|idcard|textarea] 默认: text, 输入模式
  121. * @property {String} value = [] 默认: "", 输入内容,同v-model
  122. * @property {String} right-icon = [] 默认: "", 后缀图标
  123. * @property {String} left-icon = [] 默认: "", 外层前缀图标
  124. * @property {String} prefixp-icon = [] 默认: "", 输入框内部前缀图标
  125. * @property {String} prefixp-icon-color = [] 默认: "", 默认空,使用主题color颜色
  126. * @property {String} suffix = [] 默认: "", 后缀文字
  127. * @property {String} suffix-icon = [] 默认: "", 输入框内后缀图标
  128. * @property {String} suffix-icon-color = [] 默认: "", 默认使用主题图标
  129. * @property {String} title = [] 默认: "", 左边标题。
  130. * @property {String} title-font-size = [xxs/xs/s/n/g/lg/xl] 默认: "n",同类的字号,xxs,xs,s,n,g,lg,xl
  131. * @property {Number|String} font-size = [xxs/xs/s/n/g/lg/xl/任意数字] 默认: "n",同类的字号,xxs,xs,s,n,g,lg,xl,也可以是数字单位rpx
  132. * @property {String} align = [left|center|right] 默认: "", 输入框文字对齐方式。left,center,right
  133. * @property {Boolean} clear = [false|true] 默认: false, 显示清除图标。
  134. * @property {String} color = [] 默认: primary, 主题色名称
  135. * @property {String} bg-color = [grey-lighten-5|white] 默认: grey-lighten-5, 输入框背景色。
  136. * @property {String} border-color = [] 默认: "", 输入框边框类型主题颜色名称。
  137. * @property {Boolean} border-bottom = [false|true] 默认: true, 是否显示下划线
  138. * @property {String} text-color = [black|primary] 默认: black, 输入框文字颜色。
  139. * @property {String} placeholder = [] 默认: 请输入, 占位文字
  140. * @property {Boolean} vertical = [false|true] 默认: false, 是否上下排列
  141. * @property {Number} round = [] 默认: 2, 输入框圆角。
  142. * @property {Boolean} showIndent = [] 默认: true, 是否输入框内部两边缩进
  143. * @property {Number} bg-round = [] 默认: 0, 整体框圆角。
  144. * @property {Number} bg-shadow = [] 默认: 0, 整体框投影。
  145. * @property {String} bg-theme = [] 默认:white, 整体框背景
  146. * @property {Boolean} flat = [] 默认: false, 是否去除所有边框
  147. * @property {Number|String} height = [] 默认: 68,
  148. * @property {String} name = [] 默认:'',提交表单时的的字段名称标识
  149. * @property {String} prefixp-text = [] 默认:'',输入框内前缀文字
  150. * @property {String} placeholder-class = [] 默认:'',点位符的自定义类。
  151. * @property {Array} padding = [] 默认:[32,12],左右,上下内间距。
  152. * @property {Function} click 点击输入框时触发发的函数。
  153. * @property {Function} clear 清空时触发携带相关数据
  154. * @property {Function} input 输入时触发携带相关数据
  155. * @example <tm-input ></tm-input>
  156. *
  157. */
  158. import tmSheet from "@/tm-vuetify/components/tm-sheet/tm-sheet.vue"
  159. import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
  160. export default {
  161. components:{tmSheet,tmIcons},
  162. name:"tm-input",
  163. props: {
  164. //提交表单时的的字段名称
  165. name:{
  166. type:String,
  167. default:''
  168. },
  169. prefixpText:{
  170. type:String,
  171. default:''
  172. },
  173. flat: {
  174. type: Boolean,
  175. default: false
  176. },
  177. //是否输入框内部两边缩进。默认是
  178. showIndent:{
  179. type:Boolean,
  180. default:true
  181. },
  182. maxlength: {
  183. type: Number,
  184. default: -1
  185. },
  186. black: {
  187. type:Boolean|String,
  188. default:null
  189. },
  190. //是否显示聚焦状态
  191. focusShow: {
  192. type:Boolean|String,
  193. default:false
  194. },
  195. titleFontSize:{
  196. type:String,
  197. default:'n',//同类的字号,xxs,xs,s,n,g,lg,xl
  198. },
  199. height:{
  200. type:Number|String,
  201. default:68
  202. },
  203. // 校验规则函数。
  204. verify: {
  205. type: Function,
  206. default: ()=>{
  207. return (val) => {
  208. return {
  209. check: val?.length <= 0 ? false : true,
  210. text: "必填项不能为空。"
  211. };
  212. }
  213. }
  214. },
  215. titleClass: {
  216. type: String,
  217. default: 'text-grey-darken-4'
  218. },
  219. // 是否是必填。如果必填写将会触发基础的校验,不能为空。
  220. required: Boolean,
  221. adjustPosition: Boolean,
  222. autoFocus: Boolean,
  223. confirmType: String,
  224. disabled: Boolean,
  225. password: Boolean,
  226. inputType: {
  227. type: String,
  228. default: 'text'
  229. },
  230. value: {
  231. type: String|Number,
  232. default: ''
  233. },
  234. // 右边外层后缀图标。
  235. rightIcon: {
  236. type: String,
  237. default: ''
  238. },
  239. // 输入框内部前缀图标。
  240. prefixpIcon: {
  241. type: String,
  242. default: ''
  243. },
  244. prefixpIconColor: {
  245. type: String,
  246. default: ''
  247. },
  248. // 左边外层图标。
  249. leftIcon: {
  250. type: String,
  251. default: ''
  252. },
  253. // 后缀文字
  254. suffix: {
  255. type: String,
  256. default: ''
  257. },
  258. // 输入框后缀图标
  259. suffixIcon: {
  260. type: String,
  261. default: ''
  262. },
  263. suffixIconColor:{
  264. type: String,
  265. default: ''
  266. },
  267. // 左边标题。
  268. title: {
  269. type: String,
  270. default: ''
  271. },
  272. fontSize:{
  273. type:Number|String,
  274. default:'n'
  275. },
  276. // 输入框文字对齐方式。left,center,right
  277. align: {
  278. type: String,
  279. default: 'left'
  280. },
  281. // 显示清除图标。
  282. clear: Boolean,
  283. // 主题色名称。
  284. color: {
  285. type: String,
  286. default: 'primary'
  287. },
  288. //输入框背景色。grey-lighten-5
  289. bgColor: {
  290. type: String,
  291. default: ''
  292. },
  293. // 输入框边框类型主题颜色名称。
  294. borderColor: {
  295. type: String,
  296. default: ''
  297. },
  298. // 是否显示下划线
  299. borderBottom: {
  300. type: Boolean,
  301. default: true
  302. },
  303. // text输入框文字颜色。
  304. textColor: {
  305. type: String,
  306. default: 'black'
  307. },
  308. placeholder: {
  309. type: String,
  310. default: "请输入"
  311. },
  312. placeholderClass:{
  313. type:String,
  314. default:'text-grey-lighten-1'
  315. },
  316. // 是否上下排列输入框。
  317. vertical: Boolean,
  318. round:{
  319. type:Number|String,
  320. default:2
  321. },
  322. bgRound:{
  323. type:Number|String,
  324. default:0
  325. },
  326. bgShadow:{
  327. type:Number|String,
  328. default:0
  329. },
  330. bgTheme:{
  331. type:String,
  332. default:'white'
  333. },
  334. //获取焦点。
  335. focus:{
  336. type:Boolean,
  337. default:false
  338. },
  339. padding:{
  340. type:Array,
  341. default:()=>{
  342. return [32,12];
  343. }
  344. },
  345. // 跟随主题色的改变而改变。
  346. fllowTheme:{
  347. type:Boolean|String,
  348. default:true
  349. }
  350. },
  351. data() {
  352. return {
  353. showError: false,
  354. errorText: "请正确填写",
  355. FOCUS_Auto:false,
  356. isFocus:false,
  357. };
  358. },
  359. computed: {
  360. height_rpx:function(){
  361. return this.height;
  362. },
  363. font_size:function () {
  364. let font = {
  365. 'xxs':'20rpx',
  366. 'xs':'22rpx',
  367. 's':'24rpx',
  368. 'm':'26rpx',
  369. 'n':'28rpx',
  370. 'g':'32rpx',
  371. 'lg':'36rpx',
  372. 'xl':'40rpx'
  373. }
  374. if(typeof this.fontSize=='string') return font[this.fontSize];
  375. return this.fontSize+'rpx';
  376. },
  377. title_size:function () {
  378. let font = {
  379. 'xxs':'20rpx',
  380. 'xs':'22rpx',
  381. 's':'24rpx',
  382. 'm':'26rpx',
  383. 'n':'28rpx',
  384. 'g':'32rpx',
  385. 'lg':'36rpx',
  386. 'xl':'40rpx'
  387. }
  388. if(typeof this.titleFontSize=='string') return font[this.titleFontSize];
  389. return this.titleFontSize+'rpx';
  390. },
  391. focus_fs:{
  392. get:function(){
  393. return this.FOCUS_Auto;
  394. },
  395. set:function(val){
  396. this.FOCUS_Auto = val;
  397. }
  398. },
  399. black_tmeme: function() {
  400. if (this.black !== null) return this.black;
  401. return this.$tm.vx.state().tmVuetify.black;
  402. },
  403. color_tmeme:function(){
  404. if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
  405. return this.$tm.vx.state().tmVuetify.color;
  406. }
  407. return this.color;
  408. },
  409. valueLen:function(){
  410. // 为了兼容ios不能使用this.valdata.length.
  411. let p = String(this.valdata);
  412. return p?.split('').length||0 ;
  413. },
  414. valdata:{
  415. get:function(){
  416. return this.value;
  417. },
  418. set:function(val){
  419. this.$emit('input', val)
  420. this.$emit('update:value', val)
  421. if (this.required) {
  422. this.$nextTick(function(){
  423. this.verifyInput();
  424. })
  425. }
  426. }
  427. }
  428. },
  429. mounten(){
  430. this.FOCUS_Auto = this.focus;
  431. },
  432. methods: {
  433. onclickInput(e){
  434. this.$emit('click',e)
  435. },
  436. input(e) {
  437. this.valdata = e.target.value;
  438. },
  439. // 校验是否通过。
  440. verifyInput() {
  441. let verify = this.verify.bind(this, this.valdata||'');
  442. verify = verify.call(this,this.valdata||'')
  443. if(typeof verify ==='function'){
  444. verify = verify.call(this,this.valdata||'')
  445. }
  446. if (typeof verify !== 'object') verify = {};
  447. this.showError = !(verify.check??true);
  448. this.errorText = verify.text??"";
  449. return verify.check??true;
  450. },
  451. //清除校验显示 的内容。
  452. clearVerify() {
  453. this.showError = false;
  454. this.errorText = "";
  455. },
  456. blur(e) {
  457. this.isFocus=false;
  458. this.$emit('blur', e)
  459. },
  460. focusFun(e){
  461. this.isFocus=true;
  462. this.$emit('focus',e)
  463. },
  464. clearVal(e){
  465. this.valdata ="";
  466. this.$emit('clear', this.valdata)
  467. }
  468. },
  469. }
  470. </script>
  471. <style lang="scss" scoped>
  472. .tm-input {
  473. .tm-input-center {
  474. width: 100%;
  475. .tm-input-center-wk{
  476. transition: all 0.2s;
  477. }
  478. .tm-input-center-input {
  479. border: none;
  480. background: none;
  481. box-shadow: 0;
  482. width: 100%;
  483. }
  484. }
  485. .tm-input-left {
  486. flex-shrink: 0;
  487. height: 100%;
  488. min-width: 80rpx;
  489. padding-right: 24rpx;
  490. }
  491. .tm-input-col {
  492. .tm-input-left {
  493. max-width: inherit;
  494. padding-right: 0;
  495. }
  496. .tm-input-center {
  497. .tm-input-center-input {
  498. height: 76upx;
  499. }
  500. }
  501. }
  502. .tm-input-right {
  503. height: 100%;
  504. // width: 300upx;
  505. }
  506. }
  507. </style>