Browse Source

Merge branch 'next' of https://github.com/jdf2e/nutui into next

ninidesign 5 years ago
parent
commit
0bce5e68ba
4 changed files with 368 additions and 42 deletions
  1. 111 8
      src/packages/input/demo.vue
  2. 54 1
      src/packages/input/index.scss
  3. 168 33
      src/packages/input/index.vue
  4. 35 0
      src/packages/input/util.ts

+ 111 - 8
src/packages/input/demo.vue

@@ -1,25 +1,128 @@
 <template>
-  <div class="demo">
+  <div class="demo-nopading">
     <h2>基础用法</h2>
-    <nut-cell>
-      <nut-temp name="wifi"></nut-temp>
-      <nut-temp name="mail" txt="test txt"></nut-temp>
-    </nut-cell>
+    <nut-input v-model:value="state.val1" @change="change" label="标题:" />
+
+    <nut-input
+      placeholder="请输入文本"
+      @change="change"
+      v-model:value="state.val0"
+      requireShow="true"
+      label="标题:"
+    />
+    <h2>禁用输入框</h2>
+    <nut-input
+      v-model:value="state.val2"
+      @change="change"
+      disabled="true"
+      label="标题:"
+    />
+    <nut-input
+      v-model:value="state.val3"
+      @change="change"
+      readonly="true"
+      label="标题:"
+    />
+    <h2>限制输入长度</h2>
+    <nut-input
+      v-model:value="state.val4"
+      @change="change"
+      maxLength="7"
+      label="限制7:"
+    />
+    <h2>其他类型</h2>
+    <nut-input
+      v-model:value="state.val0"
+      @change="change"
+      type="password"
+      label="密码:"
+    />
+    <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="数字:"
+    />
+    <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>
 
 <script lang="ts">
+import { reactive } from 'vue';
 import { createComponent } from '@/utils/create';
 const { createDemo } = createComponent('input');
 export default createDemo({
-  props: {},
   setup() {
-    return {};
+    const state = reactive({
+      val0: '',
+      val1: '初始数据',
+      val2: '禁止修改',
+      val3: 'readonly 只读',
+      val4: '',
+      val5: '',
+      val6: '',
+      val7: '',
+      val8: '文案'
+    });
+    setTimeout(function() {
+      state.val1 = '异步数据';
+    }, 2000);
+    const change = (num: string | number) => {
+      console.log('change: ', num);
+    };
+    return {
+      state,
+      change
+    };
   }
 });
 </script>
 
 <style lang="scss" scoped>
-.nut-temp {
+.demo-nopading {
+  height: 100%;
+  background: #f7f8fa;
+  overflow-x: hidden;
+  overflow-y: auto;
+  padding: 0;
+  padding-top: 57px;
+  h2 {
+    padding-left: 25px;
+    margin-top: 25px;
+  }
 }
 </style>

+ 54 - 1
src/packages/input/index.scss

@@ -1,2 +1,55 @@
-.nut-temp {
+.nut-input {
+  width: 100%;
+  padding: 10px 0px 10px 25px;
+  display: flex;
+  background: rgba(255, 255, 255, 1);
+  border: 1px solid rgba(234, 240, 251, 1);
+  input {
+    width: 230px;
+    flex: 1;
+    padding: 0 10px;
+  }
+  .nut-input-label {
+    width: 80px;
+    overflow: hidden;
+    display: inline-block;
+    text-align: left;
+  }
+  .nut-textinput-clear {
+    width: 16px;
+    height: 16px;
+    margin-right: 15px;
+  }
+  .nut-text {
+    flex: 1;
+    padding:0 10px;
+    .nut-text-limit{
+        float: right;
+    }
+    .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;
+  input:disabled {
+    background: none;
+    color: #c8c9cc;
+    cursor: not-allowed;
+    opacity: 1;
+    -webkit-text-fill-color: #c8c9cc;
+  }
 }

+ 168 - 33
src/packages/input/index.vue

@@ -1,45 +1,63 @@
 <template>
-  <div class="nut-input">
-    <span class="nut-require" v-if="requireShow">*</span>
-    <span class="nut-field-label" v-if="label">{{ label }}</span>
+  <view :class="['nut-input', { 'nut-input-disabled': disabled }]">
+    <view class="nut-input-label">
+      <view class="nut-input-require" v-if="requireShow">*</view>
+      <view v-if="label">{{ label }}</view>
+    </view>
 
-    <div v-if="type === 'textarea'" class="nut-text-core">
-      <textarea @input="txtIptLength" v-model="currentValue"> </textarea>
-      <span class="nut-text-limit" v-if="limitShow"
-        ><span :class="[{ 'nut-field-over': overLmitNumber }]">{{
-          txtNum
-        }}</span
-        >/{{ maxLength }}</span
+    <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"
       >
-    </div>
+      </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"
+      :maxlength="maxLength"
+      :placeholder="placeholder"
       :disabled="disabled"
       :readonly="readonly"
-      :value="currentValue"
-      @input="handleInput"
+      v-model="state.curretvalue"
+      @input="valueChange"
+      @focus="focus"
+      @blur="blur"
     />
-
-    <div
+    <!-- <view
       @click="handleClear"
       class="nut-textinput-clear"
-      v-if="!disableClear"
-      v-show="currentValue && type !== 'textarea' && active"
+      v-if="!disableClear && !readonly"
+      v-show="type !== 'textarea' && active"
     >
       <svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
         <path
           d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm2.8 9.7c.3.3.3.8 0 1.1s-.8.3-1.1 0L8 9.1l-1.7 1.7c-.3.3-.8.3-1.1 0-.3-.3-.3-.8 0-1.1L6.9 8 5.2 6.3c-.3-.3-.3-.8 0-1.1.3-.3.8-.3 1.1 0L8 6.9l1.7-1.7c.3-.3.8-.3 1.1 0 .3.3.3.8 0 1.1L9.1 8l1.7 1.7z"
         />
       </svg>
-    </div>
-  </div>
+    </view> -->
+  </view>
 </template>
 <script lang="ts">
-//import { toRefs } from 'vue';
+import { ref, toRefs, reactive, computed } from 'vue';
 import { createComponent } from '@/utils/create';
-const { componentName, create } = createComponent('input');
-
+const { create } = createComponent('input');
+import { formatNumber } from './util';
 export default create({
   props: {
     type: {
@@ -48,11 +66,11 @@ export default create({
     },
     textAlign: {
       type: String,
-      default: 'right'
+      default: 'left'
     },
     limitShow: {
       type: Boolean,
-      default: true
+      default: false
     },
     maxLength: {
       type: String,
@@ -64,28 +82,145 @@ export default create({
     },
     rows: String,
     label: String,
-    placeholder: String,
+    placeholder: {
+      type: String,
+      default: '请输入信息'
+    },
     readonly: Boolean,
     disabled: Boolean,
     autosize: {
       type: Boolean,
       default: false
     },
-    value: String
+    value: {
+      type: [String, Number],
+      default: ''
+    },
+    disableClear: {
+      type: Boolean,
+      default: false
+    }
   },
   components: {},
-  emits: ['click'],
+  emits: ['change', 'update:value', 'blur', 'focus'],
 
   setup(props, { emit }) {
-    console.log('componentName', componentName);
+    interface Events {
+      eventName: 'change';
+      params: (string | number | Event)[];
+    }
 
-    // const { name, txt } = toRefs(props);
-
-    const handleClick = (event: Event) => {
-      emit('click', event);
+    const {
+      label,
+      placeholder,
+      disabled,
+      readonly,
+      requireShow,
+      maxLength,
+      rows
+    } = props;
+    const { value } = toRefs(props);
+    const active = ref(false);
+    const state = reactive({
+      curretvalue: value,
+      textNum: String(value.value).length
+    });
+    const styles = computed(() => {
+      const rize =
+        props.type == 'textarea'
+          ? `'resize':${props.autosize ? 'none' : 'horizontal'}`
+          : '';
+      return {
+        'text-align': props.textAlign,
+        rize
+      };
+    });
+    const emitChange = envs => {
+      envs.forEach(item => {
+        emit(item.eventName, ...item.params);
+      });
     };
+    const valueChange = (e: Event) => {
+      const input = e.target as HTMLInputElement;
+      let val = input.value;
 
-    return { handleClick };
+      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);
+      }
+      if (props.type == 'number') {
+        val = formatNumber(val, false);
+      }
+      state.textNum = val.length;
+      input.value = val;
+      state.curretvalue = val;
+      emitChange([
+        {
+          eventName: 'update:value',
+          params: [val]
+        },
+        {
+          eventName: 'change',
+          params: [val]
+        }
+      ]);
+    };
+    const focus = (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 blur = () => {
+      //active.value = false;
+      // const input = e.target as HTMLInputElement;
+      // let val = input.value;
+      // emitChange([
+      //   {
+      //     eventName: 'update:modelValue',
+      //     params: [val]
+      //   },
+      //   {
+      //     eventName: 'focus',
+      //     params: [val]
+      //   }
+      // ]);
+    };
+    return {
+      value,
+      requireShow,
+      readonly,
+      placeholder,
+      label,
+      disabled,
+      rows,
+      state,
+      styles,
+      active,
+      maxLength,
+      valueChange,
+      focus,
+      blur,
+      emitChange
+    };
   }
 });
 </script>

+ 35 - 0
src/packages/input/util.ts

@@ -0,0 +1,35 @@
+function trimExtraChar(value: string, char: string, regExp: RegExp) {
+  const index = value.indexOf(char);
+
+  if (index === -1) {
+    return value;
+  }
+
+  if (char === '-' && index !== 0) {
+    return value.slice(0, index);
+  }
+
+  return value.slice(0, index + 1) + value.slice(index).replace(regExp, '');
+}
+
+export function formatNumber(
+  value: string,
+  allowDot = true,
+  allowMinus = true
+) {
+  if (allowDot) {
+    value = trimExtraChar(value, '.', /\./g);
+  } else {
+    value = value.split('.')[0];
+  }
+
+  if (allowMinus) {
+    value = trimExtraChar(value, '-', /-/g);
+  } else {
+    value = value.replace(/-/, '');
+  }
+
+  const regExp = allowDot ? /[^-0-9.]/g : /[^-0-9]/g;
+
+  return value.replace(regExp, '');
+}