Browse Source

Input: add clearable (#8509)

* Added clearable to el-input.

* Added en-US example.

* Also fire change event on clear.

* Used clearable shorthand; added clearable to attribute list.

* Added styles.
Bogdan Luca 7 years ago
parent
commit
6e8f10a556

+ 25 - 0
examples/docs/en-US/input.md

@@ -16,6 +16,7 @@
         input7: '',
         input8: '',
         input9: '',
+        input10: '',
         textarea: '',
         textarea2: '',
         textarea3: '',
@@ -188,6 +189,29 @@ export default {
 ```
 :::
 
+### Clearable
+
+::: demo Make the Input clearable with the `clearable` attribute.
+
+```html
+<el-input
+  placeholder="Please input"
+  v-model="input10"
+  clearable>
+</el-input>
+
+<script>
+export default {
+  data() {
+    return {
+      input10: ''
+    }
+  }
+}
+</script>
+```
+:::
+
 ### Input with icon
 
 Add an icon to indicate input type.
@@ -639,6 +663,7 @@ Search data from server-side.
 |autofocus | same as `autofocus` in native input | boolean | — | false |
 |form | same as `form` in native input | string | — | — |
 | label | label text | string | — | — |
+| clearable | whether to show clear button | boolean | — | false |
 
 ### Input slots
 

+ 35 - 9
packages/input/src/input.vue

@@ -10,7 +10,10 @@
       'el-input--prefix': $slots.prefix || prefixIcon,
       'el-input--suffix': $slots.suffix || suffixIcon
     }
-  ]">
+    ]"
+    @mouseenter="hovering = true"
+    @mouseleave="hovering = false"
+  >
     <template v-if="type !== 'textarea'">
       <!-- 前置元素 -->
       <div class="el-input-group__prepend" v-if="$slots.prepend"  tabindex="0">
@@ -40,14 +43,20 @@
       <!-- 后置内容 -->
       <span
         class="el-input__suffix"
-        v-if="$slots.suffix || suffixIcon || validateState && needStatusIcon"
+        v-if="$slots.suffix || suffixIcon || showClear || validateState && needStatusIcon"
         :style="suffixOffset">
         <span class="el-input__suffix-inner">
-          <slot name="suffix"></slot>
-          <i class="el-input__icon"
-            v-if="suffixIcon"
-            :class="suffixIcon">
-          </i>
+          <template v-if="!showClear">
+            <slot name="suffix"></slot>
+            <i class="el-input__icon"
+              v-if="suffixIcon"
+              :class="suffixIcon">
+            </i>
+          </template>
+          <i v-else
+            class="el-input__icon el-icon-circle-close el-input__clear"
+            @click="clear"
+          ></i>
         </span>
         <i class="el-input__icon"
           v-if="validateState"
@@ -102,7 +111,9 @@
         currentValue: this.value,
         textareaCalcStyle: {},
         prefixOffset: null,
-        suffixOffset: null
+        suffixOffset: null,
+        hovering: false,
+        focused: false
       };
     },
 
@@ -144,7 +155,11 @@
       },
       suffixIcon: String,
       prefixIcon: String,
-      label: String
+      label: String,
+      clearable: {
+        type: Boolean,
+        default: false
+      }
     },
 
     computed: {
@@ -172,6 +187,9 @@
       },
       isGroup() {
         return this.$slots.prepend || this.$slots.append;
+      },
+      showClear() {
+        return this.clearable && this.currentValue !== '' && (this.focused || this.hovering);
       }
     },
 
@@ -197,6 +215,7 @@
         };
       },
       handleBlur(event) {
+        this.focused = false;
         this.$emit('blur', event);
         if (this.validateEvent) {
           this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);
@@ -221,6 +240,7 @@
         this.textareaCalcStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
       },
       handleFocus(event) {
+        this.focused = true;
         this.$emit('focus', event);
       },
       handleInput(event) {
@@ -252,6 +272,12 @@
         if (this.$slots[pendant]) {
           return { transform: `translateX(${place === 'suf' ? '-' : ''}${this.$el.querySelector(`.el-input-group__${pendant}`).offsetWidth}px)` };
         }
+      },
+      clear() {
+        this.$emit('input', '');
+        this.$emit('change', '');
+        this.setCurrentValue('');
+        this.focus();
       }
     },
 

+ 1 - 0
packages/theme-chalk/src/common/var.scss

@@ -329,6 +329,7 @@ $--input-placeholder-color: $--color-text-placeholder !default;
 $--input-max-width: 314px !default;
 
 $--input-hover-border: $--border-color-hover !default;
+$--input-clear-hover-color: $--color-text-secondary !default;
 
 $--input-focus-border: $--color-primary !default;
 $--input-focus-fill: $--color-white !default;

+ 12 - 0
packages/theme-chalk/src/input.scss

@@ -8,6 +8,18 @@
   width: 100%;
   @include scroll-bar;
 
+  & .el-input__clear {
+    color: $--input-icon-color;
+    font-size: $--input-font-size;
+    line-height: 16px;
+    cursor: pointer;
+    transition: $--color-transition-base;
+
+    &:hover {
+      color: $--input-clear-hover-color;
+    }
+  }
+
   @include e(inner) {
     -webkit-appearance: none;
     background-color: $--input-fill;