ソースを参照

Merge pull request #404 from guoxiao158/review-gx

fix: input组件拆分
love_forever 4 年 前
コミット
8a1b08dbb0

+ 10 - 0
src/config.json

@@ -482,6 +482,16 @@
           "sort": 6,
           "show": true,
           "author": "Drjingfubo"
+        },
+        {
+          "version": "3.0.0",
+          "name": "TextArea",
+          "type": "component",
+          "cName": "文本域",
+          "desc": "文本输入",
+          "sort": 7,
+          "show": true,
+          "author": "gx"
         }
       ]
     },

+ 1 - 28
src/packages/input/demo.vue

@@ -57,34 +57,6 @@
       placeholder="支持小数点的输入"
       label="数字:"
     />
-    <h2>文本域</h2>
-    <nut-input
-      v-model:value="state.val7"
-      @change="change"
-      :autosize="true"
-      type="textarea"
-      placeholder="文本域"
-      label="留言:"
-    />
-    <nut-input
-      v-model:value="state.val7"
-      @change="change"
-      rows="5"
-      type="textarea"
-      placeholder="设置输入五行"
-      label="留言:"
-    />
-    <h2>显示字数统计</h2>
-    <nut-input
-      v-model:value="state.val8"
-      @change="change"
-      rows="5"
-      :limitShow="true"
-      maxLength="20"
-      type="textarea"
-      placeholder="设置输入五行"
-      label="留言:"
-    />
   </div>
 </template>
 
@@ -120,6 +92,7 @@ export default createDemo({
     const clear = (num: string | number) => {
       console.log('clear:', num);
     };
+
     return {
       state,
       change,

+ 17 - 19
src/packages/input/doc.md

@@ -20,8 +20,20 @@ app.use(input);
 双向绑定
 
 ```html
-<nut-input v-model:value="state.val1" @change="change" label="标题:" />
-
+<nut-input
+      v-model:value="state.val1"
+      @change="change"
+      @focus="focus"
+      @blur="blur"
+      label="文本"
+    />
+<nut-input placeholder="请输入文本"
+      @change="change"
+      v-model:value="state.val0"
+      :requireShow="true"
+      label="文本"
+      @clear="clear"
+    />
 ```
 
 ### 禁用和只读
@@ -44,19 +56,7 @@ app.use(input);
 <nut-input v-model:value="state.val5" @change="change" type="digit" label="整数:" />
 <nut-input v-model:value="state.val6" @change="change" type="digit" placeholder="支持小数点的输入" label="数字:"/>
 ```
-### 文本域
-
-```html
- <nut-input v-model:value="state.val7" @change="change" autosize="true" type="textarea" placeholder="文本域" label="留言:"/>
-<nut-input v-model:value="state.val7" @change="change" rows="5" type="textarea" placeholder="设置输入五行"  label="留言:"/>
-
-```
-### 文本域字数统计
-
-```html
- <nut-input v-model:value="state.val8" @change="change" rows="5" limitShow="true" maxLength="20" type="textarea" placeholder="设置输入五行" label="留言:"/>
 
-```
 
 
 | 参数         | 说明                             | 类型   | 默认值           |
@@ -64,15 +64,13 @@ app.use(input);
 | type         | 类型,可选值为 `text` `textarea` `number`  等 | String |`text`         |
 | value      | 输入值,双向绑定 | String |  -     |
 | placeholder         | 为空时占位符 | String |       -       |
-| placeholder-style | placeholder 样式     | String | - |
 | label          | 	左侧文案                       | string | -             |
+| requireShow          |左侧*号是否展示                       | boolean | `false`           |
 | disabled          | 	是否禁用                       | boolean | `false`              |
 | readonly          | 是否只读                        | boolean | `false`               |
-| clear-btn       | 是否带清除按钮(icon)                        | boolean | `true`               |
-| required          | 是否带必填的*号,且blur事件做非空校验                       | boolean | `false`               |
 | maxlength          | 限制最长输入字符                   | string/number | -               |
-| rows          | textarea时高度                   | string/number | 2             |
-| limit-show          | textarea时是否展示输入字符。须设置maxlength                        | boolean | `false`               |
+| disableClear          | 禁止展示清除icon                   | boolean | false             |
+| textAlign          | 文本位置                   | string | `left`             |
 | change          | 输入内容时触发                        | function | -               |
 | focus          | 聚焦时触发                        | function | -               |
 | blur          | 失焦时触发                        | function | -               |

+ 0 - 23
src/packages/input/index.scss

@@ -28,29 +28,6 @@
     position: absolute;
     right: 15px;
   }
-  .nut-text {
-    flex: 1;
-    padding: 0 10px;
-    .nut-text-limit {
-      float: right;
-      color: rgba(153, 153, 153, 1);
-    }
-    .nut-text-core {
-      outline: none;
-      display: block;
-      box-sizing: border-box;
-      width: 100%;
-      min-width: 0;
-      margin: 0;
-      padding: 0;
-      color: #323233;
-      line-height: inherit;
-      text-align: left;
-      background-color: transparent;
-      border: 0;
-      resize: none;
-    }
-  }
 }
 .nut-input-disabled {
   color: #c8c9cc !important;

+ 28 - 78
src/packages/input/index.vue

@@ -1,32 +1,10 @@
 <template>
-  <view :class="['nut-input', { 'nut-input-disabled': disabled }]">
+  <view :class="classes">
     <view class="nut-input-label">
       <view class="nut-input-require" v-if="requireShow">*</view>
       <view v-if="label" class="label-string">{{ label }}</view>
     </view>
-
-    <view v-if="type === 'textarea'" class="nut-text">
-      <textarea
-        :style="styles"
-        :rows="rows"
-        @input="valueChange"
-        v-model="state.curretvalue"
-        class="nut-text-core"
-        :maxlength="maxLength"
-        :placeholder="placeholder"
-        :disabled="disabled"
-        :readonly="readonly"
-      >
-      </textarea>
-      <span class="nut-text-limit" v-if="limitShow">
-        <span :class="[{ 'nut-field-over': state.textNum > maxLength }]">{{
-          state.textNum
-        }}</span>
-        <span>/{{ maxLength }}</span>
-      </span>
-    </view>
     <input
-      v-else
       class="input-text"
       :style="styles"
       :type="type"
@@ -43,7 +21,7 @@
       @click="handleClear"
       class="nut-textinput-clear"
       v-if="!disableClear && !readonly"
-      v-show="type !== 'textarea' && active"
+      v-show="active && state.curretvalue.length > 0"
     >
       <nut-icon name="close-little" size="12px"></nut-icon>
     </view>
@@ -54,43 +32,30 @@ import { ref, toRefs, reactive, computed } from 'vue';
 import { createComponent } from '@/utils/create';
 import { formatNumber } from './util';
 
-const { create } = createComponent('input');
-
+const { componentName, create } = createComponent('input');
+interface Events {
+  eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:value';
+  params: (string | number | Event)[];
+}
 export default create({
   props: {
     type: {
       type: String,
       default: 'text'
     },
-    textAlign: {
-      type: String,
-      default: 'left'
-    },
-    limitShow: {
-      type: Boolean,
-      default: false
-    },
-    maxLength: {
-      type: String,
+    value: {
+      type: [String, Number],
       default: ''
     },
-    requireShow: {
-      type: Boolean,
-      default: false
-    },
-    rows: {
+    placeholder: {
       type: String,
-      default: ''
+      default: '请输入信息'
     },
     label: {
       type: String,
       default: ''
     },
-    placeholder: {
-      type: String,
-      default: '请输入信息'
-    },
-    readonly: {
+    requireShow: {
       type: Boolean,
       default: false
     },
@@ -98,12 +63,16 @@ export default create({
       type: Boolean,
       default: false
     },
-    autosize: {
+    readonly: {
       type: Boolean,
       default: false
     },
-    value: {
-      type: [String, Number],
+    textAlign: {
+      type: String,
+      default: 'left'
+    },
+    maxLength: {
+      type: String,
       default: ''
     },
     disableClear: {
@@ -115,25 +84,13 @@ export default create({
   emits: ['change', 'update:value', 'blur', 'focus', 'clear', 'error'],
 
   setup(props, { emit }) {
-    interface Events {
-      eventName:
-        | 'change'
-        | 'focus'
-        | 'blur'
-        | 'clear'
-        | 'update:value'
-        | 'error';
-      params: (string | number | Event)[];
-    }
-
     const {
       label,
       placeholder,
       disabled,
       readonly,
       requireShow,
-      maxLength,
-      rows
+      maxLength
     } = props;
     const { value } = toRefs(props);
     const active = ref(false);
@@ -141,14 +98,15 @@ export default create({
       curretvalue: value,
       textNum: String(value.value).length
     });
+    const classes = computed(() => {
+      return {
+        [componentName]: true,
+        'nut-input-disabled': disabled
+      };
+    });
     const styles = computed(() => {
-      const rize =
-        props.type == 'textarea'
-          ? `'resize':${props.autosize ? 'none' : 'horizontal'}`
-          : '';
       return {
-        'text-align': props.textAlign,
-        rize
+        'text-align': props.textAlign
       };
     });
     const emitChange = (envs: Array<Events>) => {
@@ -162,12 +120,6 @@ export default create({
 
       if (maxLength && val.length > Number(maxLength)) {
         val = val.slice(0, Number(maxLength));
-        emitChange([
-          {
-            eventName: 'error',
-            params: [val]
-          }
-        ]);
       }
       if (props.type == 'digit') {
         val = formatNumber(val, true);
@@ -176,8 +128,6 @@ export default create({
         val = formatNumber(val, false);
       }
       state.textNum = val.length;
-      // input.value = val;
-      //state.curretvalue = val;
       emitChange([
         {
           eventName: 'update:value',
@@ -243,7 +193,6 @@ export default create({
       placeholder,
       label,
       disabled,
-      rows,
       state,
       styles,
       active,
@@ -252,6 +201,7 @@ export default create({
       valueFocus,
       valueBlur,
       handleClear,
+      classes,
       emitChange
     };
   }

+ 78 - 0
src/packages/textarea/demo.vue

@@ -0,0 +1,78 @@
+<template>
+  <div class="demo-nopading">
+    <h2>基础用法</h2>
+    <nut-textarea
+      v-model:value="state.val0"
+      @change="change"
+      rows="5"
+      placeholder="高度可拉伸"
+      :autosize="true"
+      label="留言:"
+    />
+    <h2>显示字数统计</h2>
+    <nut-textarea
+      v-model:value="state.val1"
+      @change="change"
+      rows="5"
+      :limitShow="true"
+      maxLength="20"
+      type="textarea"
+      placeholder="设置输入五行"
+      label="留言:"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { reactive } from 'vue';
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('textarea');
+export default createDemo({
+  setup() {
+    const state = reactive({
+      val0: '',
+      val1: '初始数据'
+    });
+    setTimeout(function() {
+      state.val1 = '异步测试数据,2秒';
+    }, 2000);
+    const change = (num: string | number) => {
+      console.log('change: ', num);
+    };
+    const focus = (num: string | number) => {
+      console.log('focus:', num);
+    };
+    const blur = (num: string | number) => {
+      console.log('blur:', num);
+    };
+    const clear = (num: string | number) => {
+      console.log('clear:', num);
+    };
+
+    return {
+      state,
+      change,
+      blur,
+      clear,
+      focus
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.demo-nopading {
+  height: 100%;
+  background: #f7f8fa;
+  overflow-x: hidden;
+  overflow-y: auto;
+  padding: 0;
+  padding-top: 57px;
+  h2 {
+    padding-left: 25px;
+    margin-top: 25px;
+    margin-bottom: 10px;
+    color: #909ca4;
+  }
+}
+</style>

+ 69 - 0
src/packages/textarea/doc.md

@@ -0,0 +1,69 @@
+# Input 输入框组件
+
+### 介绍
+
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { input } from '@nutui/nutui';
+
+const app = createApp();
+app.use(input);
+
+```
+## 代码演示
+
+### 基础用法
+
+
+```html
+<nut-textarea
+      v-model:value="state.val0"
+      @change="change"
+      rows="5"
+       placeholder="高度可拉伸"
+      :autosize="true"
+      label="留言:"
+    />
+```
+
+### 显示字数统计
+
+
+```html
+ <nut-textarea
+       v-model:value="state.val1"
+      @change="change"
+      rows="5"
+      :limitShow="true"
+      maxLength="20"
+      type="textarea"
+      placeholder="设置输入五行"
+      label="留言:"
+    />
+```
+
+
+
+| 参数         | 说明                             | 类型   | 默认值           |
+|--------------|----------------------------------|--------|------------------|
+| value      | 输入值,双向绑定 | String |  -     |
+| placeholder         | 为空时占位符 | String |       -       |
+| label          | 	左侧文案                       | string | -             |
+| maxlength          | 限制最长输入字符                   | string/number | -               |
+| rows          | textarea时高度                   | string/number | 2             |
+| limit-show          | textarea时是否展示输入字符。须设置maxlength                        | boolean | `false`               |
+| change          | 输入内容时触发                        | function | -               |
+| focus          | 聚焦时触发                        | function | -               |
+| blur          | 失焦时触发                        | function | -               |
+| clear          | 点击清空时触发                        | function | -               |
+
+
+
+
+
+
+
+

+ 54 - 0
src/packages/textarea/index.scss

@@ -0,0 +1,54 @@
+.nut-textarea {
+  position: relative;
+  width: 100%;
+  padding: 10px 0px 10px 25px;
+  display: flex;
+  background: rgba(255, 255, 255, 1);
+  border-bottom: 1px solid rgba(234, 240, 251, 1);
+  font-size: 14px;
+  input {
+    width: 230px;
+    flex: 1;
+    padding: 0 10px;
+  }
+  .nut-input-label {
+    width: 80px;
+    overflow: hidden;
+    display: inline-block;
+    text-align: left;
+    .label-string {
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+    }
+  }
+  .nut-textinput-clear {
+    width: 16px;
+    height: 16px;
+    position: absolute;
+    right: 15px;
+  }
+  .nut-text {
+    flex: 1;
+    padding: 0 10px;
+    .nut-text-limit {
+      float: right;
+      color: rgba(153, 153, 153, 1);
+    }
+    .nut-text-core {
+      outline: none;
+      display: block;
+      box-sizing: border-box;
+      width: 100%;
+      min-width: 0;
+      margin: 0;
+      padding: 0;
+      color: #323233;
+      line-height: inherit;
+      text-align: left;
+      background-color: transparent;
+      border: 0;
+      resize: none;
+    }
+  }
+}

+ 192 - 0
src/packages/textarea/index.vue

@@ -0,0 +1,192 @@
+<template>
+  <view class="nut-textarea">
+    <view class="nut-input-label">
+      <view v-if="props.label" class="label-string">{{ props.label }}</view>
+    </view>
+    <view class="nut-text">
+      <textarea
+        :style="styles"
+        :rows="props.rows"
+        @input="valueChange"
+        v-model="state.curretvalue"
+        class="nut-text-core"
+        :maxlength="maxLength"
+        :placeholder="props.placeholder"
+        :disabled="props.disabled"
+        :readonly="props.readonly"
+      >
+      </textarea>
+      <view class="nut-text-limit" v-if="limitShow">
+        <view :class="[{ 'nut-field-over': state.textNum > maxLength }]">{{
+          state.textNum
+        }}</view>
+        <view>/{{ maxLength }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts">
+import { ref, toRefs, reactive, computed } from 'vue';
+import { createComponent } from '@/utils/create';
+
+const { componentName, create } = createComponent('textarea');
+interface Events {
+  eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:value';
+  params: (string | number | Event)[];
+}
+export default create({
+  props: {
+    textAlign: {
+      type: String,
+      default: 'left'
+    },
+    limitShow: {
+      type: Boolean,
+      default: false
+    },
+    maxLength: {
+      type: String,
+      default: ''
+    },
+    rows: {
+      type: String,
+      default: ''
+    },
+    label: {
+      type: String,
+      default: ''
+    },
+    placeholder: {
+      type: String,
+      default: '请输入信息'
+    },
+    readonly: {
+      type: Boolean,
+      default: false
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    autosize: {
+      type: Boolean,
+      default: false
+    },
+    value: {
+      type: [String, Number],
+      default: ''
+    }
+  },
+
+  emits: ['change', 'update:value', 'blur', 'focus', 'clear', 'error'],
+
+  setup(props, { emit }) {
+    const { maxLength } = props;
+    const { value } = toRefs(props);
+    const active = ref(false);
+    const state = reactive({
+      curretvalue: value,
+      textNum: String(value.value).length
+    });
+    const classes = computed(() => {
+      return {
+        [componentName]: true
+      };
+    });
+    const styles = computed(() => {
+      return {
+        'text-align': props.textAlign,
+        resize: props.autosize ? 'vertical' : 'none'
+      };
+    });
+    const emitChange = (envs: Array<Events>) => {
+      envs.forEach((item: Events) => {
+        return emit(item.eventName, ...item.params);
+      });
+    };
+    const valueChange = (e: Event) => {
+      const input = e.target as HTMLInputElement;
+      let val = input.value;
+
+      if (maxLength && val.length > Number(maxLength)) {
+        val = val.slice(0, Number(maxLength));
+      }
+      state.textNum = val.length;
+      emitChange([
+        {
+          eventName: 'update:value',
+          params: [val]
+        },
+        {
+          eventName: 'change',
+          params: [val]
+        }
+      ]);
+    };
+    const valueFocus = (e: Event) => {
+      active.value = true;
+      const input = e.target as HTMLInputElement;
+      let val = input.value;
+      val = String(val);
+      emitChange([
+        {
+          eventName: 'update:value',
+          params: [state.curretvalue]
+        },
+        {
+          eventName: 'focus',
+          params: [val]
+        }
+      ]);
+    };
+    const valueBlur = (e: Event) => {
+      setTimeout(() => {
+        active.value = false;
+      }, 400);
+      const input = e.target as HTMLInputElement;
+      let val = input.value;
+      val = String(val);
+      emitChange([
+        {
+          eventName: 'update:value',
+          params: [val]
+        },
+        {
+          eventName: 'blur',
+          params: [val]
+        }
+      ]);
+    };
+    const handleClear = () => {
+      const val = '';
+      emitChange([
+        {
+          eventName: 'update:value',
+          params: [val]
+        },
+        {
+          eventName: 'clear',
+          params: [val]
+        }
+      ]);
+    };
+    return {
+      props,
+      value,
+      state,
+      styles,
+      active,
+      maxLength,
+      valueChange,
+      valueFocus,
+      valueBlur,
+      handleClear,
+      emitChange
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>