Browse Source

fix: input组件问题修复

lkjh3214 3 years ago
parent
commit
3e734da7d8

+ 3 - 21
src/packages/__VUE/input/demo.vue

@@ -61,11 +61,7 @@
       v-model="state.event"
       :placeholder="translate('event')"
       clearable
-      @update:model-value="change"
-      @focus="focus"
-      @blur="blur"
       @clear="clear"
-      @click="click"
       @click-input="clickInput"
     />
   </div>
@@ -74,7 +70,7 @@
 <script lang="ts">
 import { reactive } from 'vue';
 import { Close } from '@nutui/icons-vue';
-
+import { showToast } from '@/packages/nutui.vue';
 import { createComponent } from '@/packages/utils/create';
 const { createDemo, translate } = createComponent('input');
 import { useTranslate } from '@/sites/assets/util/useTranslate';
@@ -190,22 +186,12 @@ export default createDemo({
     setTimeout(function () {
       // state.val1 = '异步数据';
     }, 2000);
-    const change = (value: string) => {
-      console.log('change: ', value);
-    };
-    const focus = (event: Event) => {
-      console.log('focus:', event);
-    };
-    const blur = (event: Event) => {
-      console.log('blur:', event);
-    };
     const clear = (event: Event) => {
+      showToast.text('clear');
       console.log('clear:', event);
     };
-    const click = (event: Event) => {
-      console.log('click:', event);
-    };
     const clickInput = (event: Event) => {
+      showToast.text('clickInput');
       console.log('clickInput:', event);
     };
     const clearValue = () => {
@@ -214,11 +200,7 @@ export default createDemo({
     const formatter = (value: string) => value.replace(/\d/g, '');
     return {
       state,
-      change,
-      blur,
       clear,
-      focus,
-      click,
       clickInput,
       formatter,
       translate,

+ 26 - 23
src/packages/__VUE/input/doc.en-US.md

@@ -144,16 +144,36 @@ Display the clear icon during the input process by setting `clearable`.
     clearable
     clearSize="14" 
   />
+  <nut-input
+    v-model="state.clear2"
+    placeholder="Custom Clear Icon"
+    clearable
+    clearSize="14"
+    show-word-limit
+    max-length="50"
+  >
+    <template #clear>
+      <Close width="12" height="12" @click="clearValue"></Close>
+    </template>
+  </nut-input>
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
+  import { Close } from "@nutui/icons-vue"
   export default {
+    components:{
+      Close
+    },
     setup() {
       const state = reactive({
-        clear:''
+        clear:'',
+        clear2:''
       });
+      const clearValue = () => {
+        state.clear2 = '';
+      };
       return {
-        state
+        state, clearValue
       };
     }
   }
@@ -313,47 +333,30 @@ After setting the `maxlength` and `show-word-limit` attributes, word count will
     v-model="state.event"
     clearable
     placeholder="Event"
-    @update:model-value="change"
-    @focus="focus"
-    @blur="blur"
     @clear="clear"
-    @click="click"
     @click-input="clickInput"
   />
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
+  import { showToast } from '@nutui/nutui';
   export default {
     setup() {
       const state = reactive({
         event: ''
       });
-      const change = (value: string) => {
-        console.log('change: ', value);
-      };
-      const focus = (event: Event) => {
-        console.log('focus:', event);
-      };
-      const blur = (event: Event) => {
-        console.log('blur:', event);
-      };
       const clear = (event: Event) => {
+        showToast.text('clear');
         console.log('clear:', event);
       };
-      const click = (event: Event) => {
-        console.log('click:', event);
-      };
       const clickInput = (event: Event) => {
+        showToast.text('clickInput');
         console.log('clickInput:', event);
       };
 
       return {
         state,
-        change,
-        blur,
         clear,
-        focus,
-        click,
         clickInput,
       };
     }
@@ -382,7 +385,7 @@ After setting the `maxlength` and `show-word-limit` attributes, word count will
 | show-word-limit | Whether to show word limit, need to set the `max-length` prop | boolean | `false`  |
 | error         | Whether to mark the input content in red   | boolean | `false`  |
 | formatter      | Input value formatter    | `(val: string) => string` | - |
-| format-trigger | When to format value, eg `onChange`、`onBlur` | string | - |
+| format-trigger | When to format value, eg `onChange`、`onBlur` | string | `onChange` |
 | confirm-type | The text of the button in the lower right corner of the keyboard, only valid when `type='text'`, eg `send`, `search`, `next`, ` go`, `done` | string |   `done`   |
 
 ### Events

+ 20 - 34
src/packages/__VUE/input/doc.md

@@ -145,21 +145,21 @@ app.use(Input);
     clearSize="14" 
   />
   <nut-input
-      v-model="state.clear2"
-      :placeholder="translate('clear2')"
-      clearable
-      clearSize="14"
-      show-word-limit
-      max-length="50"
-    >
-      <template #clear>
-        <Close width="12" height="12" @click="clearValue"></Close>
-      </template>
-    </nut-input>
+    v-model="state.clear2"
+    placeholder="自定义清除图标"
+    clearable
+    clearSize="14"
+    show-word-limit
+    max-length="50"
+  >
+    <template #clear>
+      <Close width="12" height="12" @click="clearValue"></Close>
+    </template>
+  </nut-input>
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
-  import { Close } from 
+  import { Close } from "@nutui/icons-vue"
   export default {
     components:{
       Close
@@ -169,8 +169,11 @@ app.use(Input);
         clear:'',
         clear2:''
       });
+      const clearValue = () => {
+        state.clear2 = '';
+      };
       return {
-        state
+        state, clearValue
       };
     }
   }
@@ -333,47 +336,30 @@ app.use(Input);
     v-model="state.event"
     clearable
     placeholder="事件演示"
-    @update:model-value="change"
-    @focus="focus"
-    @blur="blur"
     @clear="clear"
-    @click="click"
     @click-input="clickInput"
   />
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
+  import { showToast } from '@nutui/nutui';
   export default {
     setup() {
       const state = reactive({
         event: ''
       });
-      const change = (value: string) => {
-        console.log('change: ', value);
-      };
-      const focus = (event: Event) => {
-        console.log('focus:', event);
-      };
-      const blur = (event: Event) => {
-        console.log('blur:', event);
-      };
       const clear = (event: Event) => {
+        showToast.text('clear');
         console.log('clear:', event);
       };
-      const click = (event: Event) => {
-        console.log('click:', event);
-      };
       const clickInput = (event: Event) => {
+        showToast.text('clickInput');
         console.log('clickInput:', event);
       };
 
       return {
         state,
-        change,
-        blur,
         clear,
-        focus,
-        click,
         clickInput,
       };
     }
@@ -401,7 +387,7 @@ app.use(Input);
 | show-word-limit | 是否显示限制最长输入字符,需要设置 `max-length` 属性 | boolean | `false`  |
 | error         | 是否标红                                | boolean | `false`  |
 | formatter      | 输入内容格式化函数    | `(val: string) => string` | - |
-| format-trigger | 格式化函数触发的时机,可选值为 `onChange`、`onBlur` | string | - |
+| format-trigger | 格式化函数触发的时机,可选值为 `onChange`、`onBlur` | string | `onChange` |
 | confirm-type | 键盘右下角按钮的文字,仅在`type='text'`时生效,可选值 `send`:发送、`search`:搜索、`next`:下一个、`go`:前往、`done`:完成 | string |   `done`   |
 
 ### Events

+ 42 - 27
src/packages/__VUE/input/doc.taro.md

@@ -144,16 +144,37 @@ app.use(Input);
     clearable
     clearSize="14" 
   />
+  <nut-input
+    v-model="state.clear2"
+    placeholder="自定义清除图标"
+    clearable
+    clearSize="14"
+    show-word-limit
+    max-length="50"
+  >
+    <template #clear>
+      <Close width="12" height="12" size="12" @click="clearValue"></Close>
+    </template>
+  </nut-input>
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
+  import { Close } from '@nutui/icons-vue-taro';
+
   export default {
+    components: {
+      Close,
+    },
     setup() {
       const state = reactive({
-        clear:''
+        clear:'',
+        clear2:''
       });
+      const clearValue = () => {
+        state.clear2 = '';
+      };
       return {
-        state
+        state, clearValue
       };
     }
   }
@@ -318,46 +339,40 @@ app.use(Input);
     v-model="state.event"
     clearable
     placeholder="事件演示"
-    @update:model-value="change"
-    @focus="focus"
-    @blur="blur"
     @clear="clear"
-    @click="click"
     @click-input="clickInput"
   />
+  <nut-toast :msg="state.msg" v-model:visible="state.show" type="text" />
 </template>
 <script lang="ts">
   import { reactive } from 'vue';
+  import { Toast } from '@nutui/nutui-taro';
   export default {
+    components: {
+      Toast
+    },
     setup() {
       const state = reactive({
-        event: ''
+        event: '',
+        show:false,
+        msg:''
       });
-      const change = (value: string) => {
-        console.log('change: ', value);
-      };
-      const focus = (event: Event) => {
-        console.log('focus:', event);
-      };
-      const blur = (event: Event) => {
-        console.log('blur:', event);
+      const clear = (value: string | number, event: Event) => {
+        console.log('clear:', value, event);
+        showToast('clear')
       };
-      const clear = (event: Event) => {
-        console.log('clear:', event);
+      const showToast = (msg: string) => {
+        state.show = true;
+        state.msg = msg;
       };
-      const click = (event: Event) => {
-        console.log('click:', event);
-      };
-      const clickInput = (event: Event) => {
-        console.log('clickInput:', event);
+      const clickInput = (value: string | number) => {
+        console.log('clickInput:', value);
+        showToast('clickInput')
+
       };
       return {
         state,
-        change,
-        blur,
         clear,
-        focus,
-        click,
         clickInput,
       };
     }
@@ -385,7 +400,7 @@ app.use(Input);
 | show-word-limit | 是否显示限制最长输入字符,需要设置 `max-length` 属性 | boolean | `false`  |
 | error         | 是否标红                                | boolean | `false`  |
 | formatter      | 输入内容格式化函数    | `(val: string) => string` | - |
-| format-trigger | 格式化函数触发的时机,可选值为 `onChange`、`onBlur` | string | - |
+| format-trigger | 格式化函数触发的时机,可选值为 `onChange`、`onBlur` | string | `onChange` |
 | confirm-type | 键盘右下角按钮的文字,仅在`type='text'`时生效,可选值 `send`:发送、`search`:搜索、`next`:下一个、`go`:前往、`done`:完成 | string |   `done`   |
 | adjust-position | 键盘弹起时,是否自动上推页面     | boolean | `true` |
 | always-system | 是否强制使用系统键盘和 Web-view 创建的 input 元素。为 true 时,`confirm-type`、`confirm-hold` 可能失效    | boolean | `false` |

+ 6 - 2
src/packages/__VUE/input/index.scss

@@ -28,7 +28,7 @@ textarea {
   width: 100%;
   padding: 10px 25px;
   display: flex;
-  line-height: 24px;
+  line-height: 20px;
   background: $white;
   font-size: $input-font-size;
   box-sizing: border-box;
@@ -53,7 +53,11 @@ textarea {
     resize: none;
     flex: 1;
   }
-
+  .input-text {
+    font-size: $input-font-size;
+    height: auto;
+    min-height: auto;
+  }
   &__label {
     width: 80px;
     overflow: hidden;

+ 46 - 24
src/packages/__VUE/input/index.taro.vue

@@ -8,7 +8,7 @@
             class="input-text"
             ref="inputRef"
             :style="styles"
-            :maxlength="maxLength"
+            :maxlength="maxLength ? maxLength : -1"
             :placeholder="placeholder"
             :disabled="disabled"
             :readonly="readonly"
@@ -20,6 +20,9 @@
             @focus="onFocus"
             @blur="onBlur"
             @click="onClickInput"
+            @change="endComposing"
+            @compositionend="endComposing"
+            @compositionstart="startComposing"
             :adjust-position="adjustPosition"
             :always-system="alwaysSystem"
           ></component>
@@ -31,19 +34,28 @@
         </view>
         <view class="nut-input-clear-box" v-if="clearable && !readonly" v-show="active && modelValue.length > 0">
           <slot name="clear">
-            <MaskClose class="nut-input-clear" v-bind="$attrs" :size="clearSize" @click="clear"> </MaskClose>
+            <MaskClose
+              class="nut-input-clear"
+              v-bind="$attrs"
+              :size="clearSize"
+              :width="clearSize"
+              :height="clearSize"
+              @click="clear"
+            >
+            </MaskClose>
           </slot>
         </view>
       </view>
     </view>
   </view>
 </template>
+<!-- eslint-disable @typescript-eslint/no-non-null-assertion -->
 <script lang="ts">
 import { PropType, ref, reactive, computed, onMounted, watch, ComputedRef, InputHTMLAttributes, h } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { formatNumber } from './util';
 import { MaskClose } from '@nutui/icons-vue-taro';
-
+import Taro from '@tarojs/taro';
 const { componentName, create } = createComponent('input');
 
 export type InputType = InputHTMLAttributes['type'];
@@ -55,13 +67,12 @@ export type InputRule = {
   required?: boolean;
 };
 export type ConfirmTextType = 'send' | 'search' | 'next' | 'go' | 'done';
+export interface InputTarget extends HTMLInputElement {
+  composing?: boolean;
+}
 
 export default create({
   props: {
-    ref: {
-      type: String,
-      default: ''
-    },
     type: {
       type: String as PropType<InputType>,
       default: 'text'
@@ -78,10 +89,6 @@ export default create({
       type: String,
       default: 'left'
     },
-    center: {
-      type: Boolean,
-      default: false
-    },
     required: {
       type: Boolean,
       default: false
@@ -100,7 +107,7 @@ export default create({
     },
     maxLength: {
       type: [String, Number],
-      default: '9999'
+      default: ''
     },
     clearable: {
       type: Boolean,
@@ -122,14 +129,6 @@ export default create({
       type: Function as PropType<(value: string) => string>,
       default: null
     },
-    rules: {
-      type: Array as PropType<InputRule>,
-      default: []
-    },
-    rows: {
-      type: [String, Number],
-      default: null
-    },
     showWordLimit: {
       type: Boolean,
       default: false
@@ -152,7 +151,7 @@ export default create({
     }
   },
   components: { MaskClose },
-  emits: ['update:modelValue', 'change', 'blur', 'focus', 'clear', 'keypress', 'click-input'],
+  emits: ['update:modelValue', 'blur', 'focus', 'clear', 'keypress', 'click-input'],
 
   setup(props, { emit, slots }) {
     const active = ref(false);
@@ -177,7 +176,6 @@ export default create({
       const prefixCls = componentName;
       return {
         [prefixCls]: true,
-        center: props.center,
         [`${prefixCls}--disabled`]: props.disabled,
         [`${prefixCls}--required`]: props.required,
         [`${prefixCls}--error`]: props.error,
@@ -202,6 +200,15 @@ export default create({
     };
 
     const onInput = (event: Event) => {
+      if (Taro.getEnv() === Taro.ENV_TYPE.WEB) {
+        if (!(event.target as InputTarget)!.composing) {
+          _onInput(event);
+        }
+      } else {
+        _onInput(event);
+      }
+    };
+    const _onInput = (event: Event) => {
       const input = event.target as HTMLInputElement;
       let value = input.value;
       if (props.maxLength && value.length > Number(props.maxLength)) {
@@ -228,7 +235,7 @@ export default create({
 
       if (value !== props.modelValue) {
         emit('update:modelValue', value);
-        emit('change', value);
+        // emit('change', value);
       }
     };
 
@@ -265,7 +272,7 @@ export default create({
       event.stopPropagation();
       if (props.disabled) return;
       emit('update:modelValue', '', event);
-      emit('change', '', event);
+      // emit('change', '', event);
       emit('clear', '', event);
     };
 
@@ -282,7 +289,20 @@ export default create({
       }
       emit('click-input', event);
     };
+    const startComposing = ({ target }: Event) => {
+      if (Taro.getEnv() === Taro.ENV_TYPE.WEB) {
+        (target as InputTarget)!.composing = true;
+      }
+    };
 
+    const endComposing = ({ target }: Event) => {
+      if (Taro.getEnv() === Taro.ENV_TYPE.WEB) {
+        if ((target as InputTarget)!.composing) {
+          (target as InputTarget)!.composing = false;
+          (target as InputTarget)!.dispatchEvent(new Event('input'));
+        }
+      }
+    };
     watch(
       () => props.modelValue,
       () => {
@@ -309,6 +329,8 @@ export default create({
       onFocus,
       onBlur,
       clear,
+      startComposing,
+      endComposing,
       onClickInput
     };
   }

+ 38 - 28
src/packages/__VUE/input/index.vue

@@ -20,6 +20,9 @@
             @focus="onFocus"
             @blur="onBlur"
             @click="onClickInput"
+            @change="endComposing"
+            @compositionend="endComposing"
+            @compositionstart="startComposing"
           ></component>
           <view v-if="showWordLimit && maxLength" class="nut-input-word-limit">
             <span class="nut-input-word-num">{{ modelValue ? modelValue.length : 0 }}</span
@@ -28,13 +31,22 @@
         </view>
         <view class="nut-input-clear-box" v-if="clearable && !readonly" v-show="active && modelValue.length > 0">
           <slot name="clear">
-            <MaskClose class="nut-input-clear" v-bind="$attrs" :size="clearSize" @click="clear"> </MaskClose>
+            <MaskClose
+              class="nut-input-clear"
+              v-bind="$attrs"
+              :size="clearSize"
+              :width="clearSize"
+              :height="clearSize"
+              @click="clear"
+            >
+            </MaskClose>
           </slot>
         </view>
       </view>
     </view>
   </view>
 </template>
+<!-- eslint-disable @typescript-eslint/no-non-null-assertion -->
 <script lang="ts">
 import { PropType, ref, reactive, computed, onMounted, watch, ComputedRef, InputHTMLAttributes, h } from 'vue';
 import { createComponent } from '@/packages/utils/create';
@@ -52,13 +64,11 @@ export type InputRule = {
   required?: boolean;
 };
 export type ConfirmTextType = 'send' | 'search' | 'next' | 'go' | 'done';
-
+export interface InputTarget extends HTMLInputElement {
+  composing: boolean;
+}
 export default create({
   props: {
-    ref: {
-      type: String,
-      default: ''
-    },
     type: {
       type: String as PropType<InputType>,
       default: 'text'
@@ -75,10 +85,6 @@ export default create({
       type: String,
       default: 'left'
     },
-    center: {
-      type: Boolean,
-      default: false
-    },
     required: {
       type: Boolean,
       default: false
@@ -93,7 +99,7 @@ export default create({
     },
     maxLength: {
       type: [String, Number],
-      default: '9999'
+      default: ''
     },
     clearable: {
       type: Boolean,
@@ -115,14 +121,6 @@ export default create({
       type: Function as PropType<(value: string) => string>,
       default: null
     },
-    rules: {
-      type: Array as PropType<InputRule>,
-      default: []
-    },
-    rows: {
-      type: [String, Number],
-      default: null
-    },
     showWordLimit: {
       type: Boolean,
       default: false
@@ -142,7 +140,7 @@ export default create({
   },
   components: { MaskClose },
 
-  emits: ['update:modelValue', 'change', 'blur', 'focus', 'clear', 'keypress', 'click-input'],
+  emits: ['update:modelValue', 'blur', 'focus', 'clear', 'keypress', 'click-input'],
 
   setup(props, { emit, slots }) {
     const active = ref(false);
@@ -166,7 +164,6 @@ export default create({
       const prefixCls = componentName;
       return {
         [prefixCls]: true,
-        center: props.center,
         [`${prefixCls}--disabled`]: props.disabled,
         [`${prefixCls}--required`]: props.required,
         [`${prefixCls}--error`]: props.error,
@@ -191,12 +188,14 @@ export default create({
     };
 
     const onInput = (event: Event) => {
-      const input = event.target as HTMLInputElement;
-      let value = input.value;
-      if (props.maxLength && value.length > Number(props.maxLength)) {
-        value = value.slice(0, Number(props.maxLength));
+      if (!(event.target as InputTarget)!.composing) {
+        const input = event.target as HTMLInputElement;
+        let value = input.value;
+        if (props.maxLength && value.length > Number(props.maxLength)) {
+          value = value.slice(0, Number(props.maxLength));
+        }
+        updateValue(value);
       }
-      updateValue(value);
     };
 
     const updateValue = (value: string, trigger: InputFormatTrigger = 'onChange') => {
@@ -217,7 +216,7 @@ export default create({
 
       if (value !== props.modelValue) {
         emit('update:modelValue', value);
-        emit('change', value);
+        // emit('change', value);
       }
     };
 
@@ -254,7 +253,7 @@ export default create({
       event.stopPropagation();
       if (props.disabled) return;
       emit('update:modelValue', '', event);
-      emit('change', '', event);
+      // emit('change', '', event);
       emit('clear', '', event);
     };
 
@@ -271,7 +270,16 @@ export default create({
       }
       emit('click-input', event);
     };
+    const startComposing = ({ target }: Event) => {
+      (target as InputTarget)!.composing = true;
+    };
 
+    const endComposing = ({ target }: Event) => {
+      if ((target as InputTarget)!.composing) {
+        (target as InputTarget)!.composing = false;
+        (target as InputTarget)!.dispatchEvent(new Event('input'));
+      }
+    };
     watch(
       () => props.modelValue,
       () => {
@@ -295,6 +303,8 @@ export default create({
       onFocus,
       onBlur,
       clear,
+      startComposing,
+      endComposing,
       onClickInput
     };
   }

+ 9 - 20
src/sites/mobile-taro/vue/src/dentry/pages/input/index.vue

@@ -65,13 +65,10 @@
       placeholder="事件演示"
       clearable
       :adjust-position="state.adjustPosition"
-      @update:model-value="change"
-      @focus="focus"
-      @blur="blur"
       @clear="clear"
-      @click="click"
       @click-input="clickInput"
     />
+    <nut-toast :msg="state.msg" v-model:visible="state.show" type="text" />
   </div>
 </template>
 
@@ -111,28 +108,24 @@ export default {
       event: '',
       clear: '',
       clear2: '',
-      adjustPosition: false
+      adjustPosition: false,
+      show: false,
+      msg: ''
     });
     setTimeout(function () {
       // state.val1 = '异步数据';
     }, 2000);
-    const change = (value: string | number) => {
-      console.log('change: ', value);
-    };
-    const focus = (value: string | number, event: Event) => {
-      console.log('focus:', value, event);
-    };
-    const blur = (value: string | number, event: Event) => {
-      console.log('blur:', value, event);
-    };
     const clear = (value: string | number, event: Event) => {
       console.log('clear:', value, event);
+      showToast('clear');
     };
-    const click = (value: string | number) => {
-      console.log('click:', value);
+    const showToast = (msg: string) => {
+      state.show = true;
+      state.msg = msg;
     };
     const clickInput = (value: string | number) => {
       console.log('clickInput:', value);
+      showToast('clickInput');
     };
     const formatter = (value: string) => value.replace(/\d/g, '');
     const clearValue = () => {
@@ -140,11 +133,7 @@ export default {
     };
     return {
       state,
-      change,
-      blur,
       clear,
-      focus,
-      click,
       clickInput,
       formatter,
       clearValue,