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

274 lines
7.5 KiB

5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
  1. <template>
  2. <div class="material-input__component" :class="computedClasses">
  3. <div :class="{iconClass:icon}">
  4. <i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i>
  5. <input v-if="type === 'email'" type="email" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  6. :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
  7. @blur="handleMdBlur" @input="handleModelInput">
  8. <input v-if="type === 'url'" type="url" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  9. :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
  10. @blur="handleMdBlur" @input="handleModelInput">
  11. <input v-if="type === 'number'" type="number" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  12. :step="step" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :minlength="minlength"
  13. :maxlength="maxlength" :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
  14. <input v-if="type === 'password'" type="password" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  15. :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :required="required" @focus="handleMdFocus"
  16. @blur="handleMdBlur" @input="handleModelInput">
  17. <input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  18. :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
  19. @blur="handleMdBlur" @input="handleModelInput">
  20. <input v-if="type === 'text'" type="text" class="material-input" :name="name" :placeholder="placeholder" v-model="currentValue"
  21. :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" :maxlength="maxlength"
  22. :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
  23. <span class="material-input-bar"></span>
  24. <label class="material-label">
  25. <slot></slot>
  26. </label>
  27. </div>
  28. </div>
  29. </template>
  30. <script>
  31. // source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
  32. export default {
  33. name: 'md-input',
  34. props: {
  35. icon: String,
  36. name: String,
  37. type: {
  38. type: String,
  39. default: 'text'
  40. },
  41. value: [String, Number],
  42. placeholder: String,
  43. readonly: Boolean,
  44. disabled: Boolean,
  45. min: String,
  46. max: String,
  47. step: String,
  48. minlength: Number,
  49. maxlength: Number,
  50. required: {
  51. type: Boolean,
  52. default: true
  53. },
  54. autoComplete: {
  55. type: String,
  56. default: 'off'
  57. },
  58. validateEvent: {
  59. type: Boolean,
  60. default: true
  61. }
  62. },
  63. computed: {
  64. computedClasses() {
  65. return {
  66. 'material--active': this.focus,
  67. 'material--disabled': this.disabled,
  68. 'material--raised': Boolean(this.focus || this.currentValue) // has value
  69. }
  70. }
  71. },
  72. watch: {
  73. value(newValue) {
  74. this.currentValue = newValue
  75. }
  76. },
  77. data() {
  78. return {
  79. currentValue: this.value,
  80. focus: false,
  81. }
  82. },
  83. methods: {
  84. handleModelInput(event) {
  85. const value = event.target.value
  86. this.$emit('input', value)
  87. if (this.$parent.$options.componentName === 'ElFormItem') {
  88. if (this.validateEvent) {
  89. this.$parent.$emit('el.form.change', [value])
  90. }
  91. }
  92. this.$emit('change', value)
  93. },
  94. handleMdFocus(event) {
  95. this.focus = true
  96. this.$emit('focus', event)
  97. if (this.placeholder && this.placeholder !== '') {
  98. }
  99. },
  100. handleMdBlur(event) {
  101. this.focus = false
  102. this.$emit('blur', event)
  103. if (this.$parent.$options.componentName === 'ElFormItem') {
  104. if (this.validateEvent) {
  105. this.$parent.$emit('el.form.blur', [this.currentValue])
  106. }
  107. }
  108. }
  109. }
  110. }
  111. </script>
  112. <style rel="stylesheet/scss" lang="scss" scoped>
  113. // Fonts:
  114. $font-size-base: 16px;
  115. $font-size-small: 18px;
  116. $font-size-smallest: 12px;
  117. $font-weight-normal: normal;
  118. $font-weight-bold: bold;
  119. $apixel: 1px;
  120. // Utils
  121. $spacer: 12px;
  122. $transition: 0.2s ease all;
  123. $index: 0px;
  124. $index-has-icon: 30px;
  125. // Theme:
  126. $color-white: white;
  127. $color-grey: #9E9E9E;
  128. $color-grey-light: #E0E0E0;
  129. $color-blue: #2196F3;
  130. $color-red: #F44336;
  131. $color-black: black;
  132. // Base clases:
  133. %base-bar-pseudo {
  134. content: '';
  135. height: 1px;
  136. width: 0;
  137. bottom: 0;
  138. position: absolute;
  139. transition: $transition;
  140. }
  141. // Mixins:
  142. @mixin slided-top() {
  143. top: - ($font-size-base + $spacer);
  144. left: 0;
  145. font-size: $font-size-base;
  146. font-weight: $font-weight-bold;
  147. }
  148. // Component:
  149. .material-input__component {
  150. position: relative;
  151. * {
  152. box-sizing: border-box;
  153. }
  154. .iconClass {
  155. .material-input__icon {
  156. position: absolute;
  157. left: 0;
  158. line-height: $font-size-base;
  159. color: $color-blue;
  160. top: $spacer;
  161. width: $index-has-icon;
  162. height: $font-size-base;
  163. font-size: $font-size-base;
  164. font-weight: $font-weight-normal;
  165. pointer-events: none;
  166. }
  167. .material-label {
  168. left: $index-has-icon;
  169. }
  170. .material-input {
  171. text-indent: $index-has-icon;
  172. }
  173. }
  174. .material-input {
  175. font-size: $font-size-base;
  176. padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2;
  177. display: block;
  178. width: 100%;
  179. border: none;
  180. line-height: 1;
  181. border-radius: 0;
  182. &:focus {
  183. outline: none;
  184. border: none;
  185. border-bottom: 1px solid transparent; // fixes the height issue
  186. }
  187. }
  188. .material-label {
  189. font-weight: $font-weight-normal;
  190. position: absolute;
  191. pointer-events: none;
  192. left: $index;
  193. top: 0;
  194. transition: $transition;
  195. font-size: $font-size-small;
  196. }
  197. .material-input-bar {
  198. position: relative;
  199. display: block;
  200. width: 100%;
  201. &:before {
  202. @extend %base-bar-pseudo;
  203. left: 50%;
  204. }
  205. &:after {
  206. @extend %base-bar-pseudo;
  207. right: 50%;
  208. }
  209. }
  210. // Disabled state:
  211. &.material--disabled {
  212. .material-input {
  213. border-bottom-style: dashed;
  214. }
  215. }
  216. // Raised state:
  217. &.material--raised {
  218. .material-label {
  219. @include slided-top();
  220. }
  221. }
  222. // Active state:
  223. &.material--active {
  224. .material-input-bar {
  225. &:before,
  226. &:after {
  227. width: 50%;
  228. }
  229. }
  230. }
  231. }
  232. .material-input__component {
  233. background: $color-white;
  234. .material-input {
  235. background: none;
  236. color: $color-black;
  237. text-indent: $index;
  238. border-bottom: 1px solid $color-grey-light;
  239. }
  240. .material-label {
  241. color: $color-grey;
  242. }
  243. .material-input-bar {
  244. &:before,
  245. &:after {
  246. background: $color-blue;
  247. }
  248. }
  249. // Active state:
  250. &.material--active {
  251. .material-label {
  252. color: $color-blue;
  253. }
  254. }
  255. // Errors:
  256. &.material--has-errors {
  257. &.material--active .material-label {
  258. color: $color-red;
  259. }
  260. .material-input-bar {
  261. &:before,
  262. &:after {
  263. background: transparent;
  264. }
  265. }
  266. }
  267. }
  268. </style>