浏览代码

chore: textarea

richard1015 4 年之前
父节点
当前提交
f4e25005d4
共有 5 个文件被更改,包括 133 次插入202 次删除
  1. 17 29
      src/packages/textarea/demo.vue
  2. 30 23
      src/packages/textarea/doc.md
  3. 26 37
      src/packages/textarea/index.scss
  4. 52 113
      src/packages/textarea/index.vue
  5. 8 0
      src/styles/variables.scss

+ 17 - 29
src/packages/textarea/demo.vue

@@ -1,49 +1,37 @@
 <template>
 <template>
   <div class="demo full">
   <div class="demo full">
     <h2>基础用法</h2>
     <h2>基础用法</h2>
-    <nut-textarea
-      v-model="state.val0"
-      @change="change"
-      rows="10"
-      placeholder="高度可拉伸"
-      :autosize="true"
-      label="留言:"
-    />
+    <nut-textarea v-model="value" />
     <h2>显示字数统计</h2>
     <h2>显示字数统计</h2>
+    <nut-textarea v-model="value2" limit-show max-length="20" />
+    <h2>高度自定义,拉伸</h2>
+    <nut-textarea v-model="value3" rows="10" autosize />
+    <h2>只读</h2>
+    <nut-textarea readonly model-value="textarea直读状态" />
+    <h2>禁用</h2>
     <nut-textarea
     <nut-textarea
-      v-model="state.val1"
-      @change="change"
-      rows="5"
-      :limit-show="true"
+      disabled
+      model-value="textarea禁用状态"
+      limit-show
       max-length="20"
       max-length="20"
-      placeholder="设置输入五行"
-      label="留言:"
     />
     />
-    <h2>只读</h2>
-    <nut-textarea readonly="true" rows="5" placeholder="只读" label="留言:" />
   </div>
   </div>
 </template>
 </template>
 
 
 <script lang="ts">
 <script lang="ts">
-import { reactive } from 'vue';
+import { ref } from 'vue';
 import { createComponent } from '@/utils/create';
 import { createComponent } from '@/utils/create';
 const { createDemo } = createComponent('textarea');
 const { createDemo } = createComponent('textarea');
 export default createDemo({
 export default createDemo({
   setup() {
   setup() {
-    const state = reactive({
-      val0: '',
-      val1: '初始数据'
-    });
-    setTimeout(function() {
-      state.val1 = '异步测试数据,2秒';
-    }, 2000);
-    const change = (num: string | number) => {
-      console.log('change: ', num);
-    };
+    const value = ref('');
+    const value2 = ref('');
+    const value3 = ref('');
 
 
     return {
     return {
-      state,
-      change
+      value,
+      value2,
+      value3
     };
     };
   }
   }
 });
 });

+ 30 - 23
src/packages/textarea/doc.md

@@ -2,16 +2,16 @@
 
 
 ### 介绍
 ### 介绍
 
 
-支持多行文本
+文本框内输入或编辑文字,支持限制输入数量。
 
 
 ### 安装
 ### 安装
 
 
 ``` javascript
 ``` javascript
 import { createApp } from 'vue';
 import { createApp } from 'vue';
-import { Textarea } from '@nutui/nutui';
+import { TextArea } from '@nutui/nutui';
 
 
 const app = createApp();
 const app = createApp();
-app.use(Textarea);
+app.use(TextArea);
 
 
 ```
 ```
 ## 代码演示
 ## 代码演示
@@ -20,30 +20,38 @@ app.use(Textarea);
 
 
 
 
 ```html
 ```html
-<nut-textarea
-  v-model="state.val0"
-  @change="change"
-  rows="5"
-  placeholder="高度可拉伸"
-  :autosize="true"
-  label="留言:"
-/>
+<nut-textarea v-model="value" />
+```
+``` javascript
+import { ref } from 'vue';
+
+export default {
+  setup() {
+    const value = ref('');
+    return { value };
+  },
+};
 ```
 ```
 
 
 ### 显示字数统计
 ### 显示字数统计
 
 
 
 
 ```html
 ```html
- <nut-textarea
-  v-model="state.val1"
-  @change="change"
-  rows="5"
-  :limit-show="true"
-  max-length="20"
-  type="textarea"
-  placeholder="设置输入五行"
-  label="留言:"
-/>
+<nut-textarea v-model="value" limit-show max-length="20" />
+```
+
+### 高度自定义,拉伸
+
+
+```html
+<nut-textarea v-model="value" rows="10" autosize />
+```
+### 直读、禁用
+
+
+```html
+<nut-textarea readonly model-value="textarea直读状态" />
+<nut-textarea disabled model-value="textarea禁用状态" limit-show max-length="20" />
 ```
 ```
 
 
 
 
@@ -52,8 +60,7 @@ app.use(Textarea);
 | 参数        | 说明                                             | 类型           | 默认值         |
 | 参数        | 说明                                             | 类型           | 默认值         |
 |-------------|--------------------------------------------------|----------------|----------------|
 |-------------|--------------------------------------------------|----------------|----------------|
 | v-model     | 输入值,支持双向绑定                             | String         | -              |
 | v-model     | 输入值,支持双向绑定                             | String         | -              |
-| placeholder | 为空时占位符                                     | String         | `'请输入信息'` |
-| label       | 左侧文案                                         | String         | -              |
+| placeholder | 设置占位提示文字                                 | String         | `'请输入内容'` |
 | max-length  | 限制最长输入字符                                 | String、Number | -              |
 | max-length  | 限制最长输入字符                                 | String、Number | -              |
 | rows        | textarea的高度                                   | String、Number | `2`            |
 | rows        | textarea的高度                                   | String、Number | `2`            |
 | limit-show  | textarea是否展示输入字符。须配合`max-length`使用 | Boolean        | `false`        |
 | limit-show  | textarea是否展示输入字符。须配合`max-length`使用 | Boolean        | `false`        |

+ 26 - 37
src/packages/textarea/index.scss

@@ -1,49 +1,38 @@
 .nut-textarea {
 .nut-textarea {
   position: relative;
   position: relative;
   width: 100%;
   width: 100%;
-  padding: 10px 0px 10px 25px;
   display: flex;
   display: flex;
   background: $white;
   background: $white;
-  border-bottom: 1px solid $input-border-bottom;
-  font-size: 14px;
-  .nut-input-label {
-    width: 80px;
-    overflow: hidden;
-    display: inline-block;
-    text-align: left;
-    .label-string {
-      overflow: hidden;
-      white-space: nowrap;
-      text-overflow: ellipsis;
+  font-size: $textarea-font;
+  padding: 10px 25px;
+
+  &--disabled {
+    .nut-textarea__textarea,
+    .nut-textarea____limit {
+      cursor: not-allowed;
+      color: $textarea-disabled-color !important;
     }
     }
   }
   }
-  .nut-textinput-clear {
-    width: 16px;
-    height: 16px;
+  &__limit {
     position: absolute;
     position: absolute;
     right: 15px;
     right: 15px;
+    bottom: 12px;
+    font-size: $textarea-font;
+    color: $textarea-limit-color;
   }
   }
-  .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;
-    }
+  &__textarea {
+    min-height: $textarea-height;
+    outline: none;
+    display: block;
+    box-sizing: border-box;
+    width: 100%;
+    min-width: 0;
+    margin: 0;
+    padding: 0;
+    color: $textarea-text-color;
+    text-align: left;
+    background-color: transparent;
+    border: 0;
+    resize: none;
   }
   }
 }
 }

+ 52 - 113
src/packages/textarea/index.vue

@@ -1,43 +1,35 @@
 <template>
 <template>
   <view :class="classes">
   <view :class="classes">
-    <view class="nut-input-label">
-      <view v-if="label" class="label-string">{{ label }}</view>
-    </view>
-    <view class="nut-text">
-      <textarea
-        :style="styles"
-        :rows="rows"
-        @input="valueChange"
-        @focus="valueFocus"
-        @blur="valueBlur"
-        v-model="curretvalue"
-        class="nut-text-core"
-        :maxlength="maxLength"
-        :placeholder="placeholder"
-        :disabled="disabled"
-        :readonly="readonly"
-      >
-      </textarea>
-      <view class="nut-text-limit" v-if="limitShow">
-        <view :class="[{ 'nut-field-over': textNum > maxLength }]">{{
-          textNum
-        }}</view>
-        <view>/{{ maxLength }}</view>
-      </view>
-    </view>
+    <textarea
+      class="nut-textarea__textarea"
+      :style="styles"
+      :rows="rows"
+      :disabled="disabled"
+      :readonly="readonly"
+      :value="modelValue"
+      @input="change"
+      @blur="blur"
+      @focus="focus"
+      :maxlength="maxLength"
+      :placeholder="placeholder"
+    />
+    <view class="nut-textarea__limit" v-if="limitShow">
+      {{ modelValue.length }}/{{ maxLength }}</view
+    >
   </view>
   </view>
 </template>
 </template>
 <script lang="ts">
 <script lang="ts">
-import { toRefs, reactive, computed, watch } from 'vue';
+import { computed, watch } from 'vue';
 import { createComponent } from '@/utils/create';
 import { createComponent } from '@/utils/create';
 
 
 const { componentName, create } = createComponent('textarea');
 const { componentName, create } = createComponent('textarea');
-interface Events {
-  eventName: 'change' | 'focus' | 'blur' | 'update:value';
-  params: (string | number | Event)[];
-}
+
 export default create({
 export default create({
   props: {
   props: {
+    modelValue: {
+      type: [String, Number],
+      default: ''
+    },
     textAlign: {
     textAlign: {
       type: String,
       type: String,
       default: 'left'
       default: 'left'
@@ -47,20 +39,16 @@ export default create({
       default: false
       default: false
     },
     },
     maxLength: {
     maxLength: {
-      type: String,
+      type: [String, Number],
       default: ''
       default: ''
     },
     },
     rows: {
     rows: {
       type: [String, Number],
       type: [String, Number],
-      default: '2'
-    },
-    label: {
-      type: String,
       default: ''
       default: ''
     },
     },
     placeholder: {
     placeholder: {
       type: String,
       type: String,
-      default: '请输入信息'
+      default: '请输入内容'
     },
     },
     readonly: {
     readonly: {
       type: Boolean,
       type: Boolean,
@@ -73,25 +61,17 @@ export default create({
     autosize: {
     autosize: {
       type: Boolean,
       type: Boolean,
       default: false
       default: false
-    },
-    value: {
-      type: [String, Number],
-      default: ''
     }
     }
   },
   },
 
 
-  emits: ['change', 'update:value', 'blur', 'focus'],
+  emits: ['update:modelValue', 'change', 'blur', 'focus'],
 
 
   setup(props, { emit }) {
   setup(props, { emit }) {
-    const state = reactive({
-      curretvalue: props.value,
-      textNum: String(props.value).length
-    });
-
     const classes = computed(() => {
     const classes = computed(() => {
       const prefixCls = componentName;
       const prefixCls = componentName;
       return {
       return {
-        [prefixCls]: true
+        [prefixCls]: true,
+        [`${prefixCls}--disabled`]: props.disabled
       };
       };
     });
     });
 
 
@@ -102,83 +82,42 @@ export default create({
       };
       };
     });
     });
 
 
-    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 (props.maxLength && val.length > Number(props.maxLength)) {
-        val = val.slice(0, Number(props.maxLength));
+    const emitChange = (value: string, event: Event) => {
+      if (props.maxLength && value.length > Number(props.maxLength)) {
+        value = value.substring(0, Number(props.maxLength));
       }
       }
-      state.textNum = val.length;
-      emitChange([
-        {
-          eventName: 'update:value',
-          params: [val]
-        },
-        {
-          eventName: 'change',
-          params: [val]
-        }
-      ]);
+      emit('change', value, event);
+      emit('update:modelValue', value, event);
     };
     };
 
 
-    const valueFocus = (e: Event) => {
-      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 change = (event: Event) => {
+      const input = event.target as HTMLInputElement;
+      emitChange(input.value, event);
     };
     };
 
 
-    const valueBlur = (e: Event) => {
-      const input = e.target as HTMLInputElement;
-      emitChange([
-        {
-          eventName: 'update:value',
-          params: [String(input.value)]
-        },
-        {
-          eventName: 'blur',
-          params: [String(input.value)]
-        }
-      ]);
+    const focus = (event: Event) => {
+      if (props.disabled) return;
+      if (props.readonly) return;
+      emit('focus', event);
     };
     };
 
 
-    watch(
-      () => props.value,
-      val => {
-        state.curretvalue = val;
-        state.textNum = String(val).length;
-        emitChange([
-          {
-            eventName: 'update:value',
-            params: [String(val)]
-          }
-        ]);
-      }
-    );
+    const blur = (event: Event) => {
+      if (props.disabled) return;
+      if (props.readonly) return;
+      const input = event.target as HTMLInputElement;
+
+      let value = input.value;
+
+      emitChange(value, event);
+      emit('blur', event);
+    };
 
 
     return {
     return {
-      ...toRefs(state),
       classes,
       classes,
       styles,
       styles,
-      valueChange,
-      valueFocus,
-      valueBlur
+      change,
+      focus,
+      blur
     };
     };
   }
   }
 });
 });

+ 8 - 0
src/styles/variables.scss

@@ -117,6 +117,14 @@ $uploader-background: #f7f8fa;
 $input-border-bottom: #eaf0fb;
 $input-border-bottom: #eaf0fb;
 $input-disabled-color: #c8c9cc;
 $input-disabled-color: #c8c9cc;
 
 
+// textarea
+
+$textarea-font: $font-size-2;
+$textarea-height: 100px;
+$textarea-limit-color: $text-color;
+$textarea-text-color: $title-color;
+$textarea-disabled-color: $disable-color;
+
 // inputnumber
 // inputnumber
 
 
 $inputnumber-icon-color: $title-color;
 $inputnumber-icon-color: $title-color;