vue 封装input组件

涉及到的知识点其实就是父子组件之间属性和方法的使用

第一步:在components目录下新建一个子组件(field.vue)
<template>
  <div
    class="cell-wrapper"
    :class="showVerify ? 'include-verify flex-base' : ''"
  >
    <div
      class="cell-item flex-base"
      :style="{backgroundColor: cellBgColor}"
    >
      <div
        class="left"
        :class="label !== undefined && label !== '' ? 'flex-label' : ''"
      >
        <label>{{ label }}</label>
        <i class="van-icon" :class="`van-icon-${leftIcon}`"></i>
      </div>
      <div class="right flex-base">
        <input
          v-if="type === undefined"
          ref="input"
          type="text"
          v-on:value="value"
          :placeholder="placeHolder"
          :style="{backgroundColor: cellBgColor === undefined ? inputBgColor : cellBgColor}"
          @input="updateValue($event.target.value)"
          @focus="onFocus"
          @blur="onBlur"
          @click="clickInput"
        >

        <select
          v-if="type === 'select'"
          @change="changeSelect($event.target.value)"
        >
          <option value="">请选择</option>
          <option
            v-for="(option, index) in options"
            :key="index"
            :value="option.value"
          >
            {{ option.label }}
          </option>
        </select>

        <i
          class="van-icon van-icon-clear"
          v-if="!success && showClear"
          @click="clearValue"
        />
        <i
          class="van-icon van-icon-passed"
          v-if="success"
        />
        <p class="error">{{ errorMsg }}</p>
      </div>
    </div>
    <div
      v-if="showVerify"
      class="getCode"
      @click="getVerifyCode"
      :class="showCodeBtn ? '' : 'disabled-get'"
    >
      {{ showCodeBtn ? '获取验证码' : `${authTime}s后重试` }}
    </div>
  </div>
</template>

<script>
  export default {
    name: 'formCell',
    props: {
      type: {},
      label: {},
      leftIcon: {},
      clearIcon: {}, // 清除图标
      successIcon: {}, // 校验成功时显示的图标
      placeHolder: {}, // input的placeholder
      errorMsg: {}, // 显示错误信息
      inputBgColor: { // input输入框的背景
        type: String,
        default: '#F5F5F5'
      },
      cellBgColor: {}, // 整行背景
      success: { // 校验成功
        type: Boolean,
        default: false
      },
      showVerify: {}, // 显示验证码
      showCodeBtn: {}, // 显示获取验证码按钮
      authTime: {},
      options: { // 下拉选项
        type: Array
      }
    },
    data () {
      return {
        showClear: false,
        inputRef: '',
        value: ''
      }
    },
    methods: {
      setValue (val) {
        this.$emit('input', val);
      },

      // 更新选择项
      changeSelect (val) {
        this.$emit('change', val, this.label);
      },

      // 更新input的value值
      updateValue (val) {
        if (val) {
          this.showClear = true;
        } else {
          this.showClear = false;
        }
        this.setValue(val);
      },

      // 点击input无延迟聚焦
      clickInput () {
        this.inputRef.focus();
      },

      // 聚焦事件
      onFocus () {
        this.$emit('watchFocus');
      },

      // 失焦事件
      onBlur () {
        this.$emit('watchBlur');
      },

      // 清空input的value值
      clearValue () {
        this.inputRef.value = '';
        this.inputRef.focus();
        this.updateValue('');
      },

      getVerifyCode () {
        this.$emit('getVerifyCode')
      }
    },
    created () {
      let _this = this;
      this.$nextTick(() => {
        _this.inputRef = this.$refs.input;
      })
    }
  };
</script>

<style scoped lang="scss" type="text/scss">
  .getCode{
    flex: 1;
    font-size: 30px;
    color: #FFF;
    text-align: center;
    background: $theme;
    padding: 25px 5px;
    margin-left: 25px;
    border-radius: 20px;
  }

  .disabled-get{
    background: #8d8d8d;
  }

  .cell{
    &-wrapper{
      position: relative;
      padding: 15px 20px 30px;
    }
    &-item{
      padding: 15px 20px;
      .flex-label{
        flex: .2;
        text-align: right;
      }
      .left{
        margin-right: 20px;
        .van-icon{
          font-size: 45px;
          color: $theme;
        }
      }
      .right{
        position: relative;
        flex: 1;
        input{
          width: 100%;
          height: 60px;
          text-indent: 15px;
        }
        select{
          appearance:none;
          -moz-appearance:none;
          -webkit-appearance:none;
          width: 100%;
          height: 80px;
          border: none;
          outline: none;
          color: #888;
          font-size: 30px;
          text-indent: 15px;
          background: #F5F5F5;
          &::after{
            content: '';
            width: 50px;
            height: 50px;
            background: #000;
            position: absolute;
            right: 0;
          }
        }

        ::-webkit-input-placeholder { /* WebKit browsers */
          color: #888;
          font-size: 28px;
        }
        :-moz-placeholder { /* Mozilla Firefox 4 to 18 */
          color: #888;
          font-size: 28px;
        }
        ::-moz-placeholder { /* Mozilla Firefox 19+ */
          color: #888;
          font-size: 28px;
        }
        :-ms-input-placeholder { /* Internet Explorer 10+ */
          color: #888;
          font-size: 28px;
        }

        .van-icon{
          position: absolute;
          top: 20px;
          right: 10px;
          &-clear{
            color: $theme;
          }
          &-passed{
            color: #1bbb00;
          }
        }

        .error{
          position: absolute;
          bottom: -50px;
          font-size: 25px;
          color: $theme;
          margin: 0;
        }
      }
    }
  }

  .include-verify {
    .cell-item{
      flex: 2;
    }
  }
</style>

第二步、父组件使用field组件
<template>
  <div class="verified">
    <new-layout centerColor="#FFF">
      <template slot="center">
        <div class="field-group">
          <form-field
            leftIcon="yonghu"
            placeHolder="请输入您的姓名"
            cellBgColor="#F5F5F5"
            v-model="formData.name.value"
            :errorMsg="formData.name.err"
            :success="formData.name.success"
            @watchFocus="watchInputFocus('name')"
            @watchBlur="watchInputBlur(formData.name.value, 'name')"
          />

          <form-field
            leftIcon="Id"
            placeHolder="请输入您的身份证号"
            cellBgColor="#F5F5F5"
            v-model="formData.idCard.value"
            :errorMsg="formData.idCard.err"
            :success="formData.idCard.success"
            @watchFocus="watchInputFocus('id')"
            @watchBlur="watchInputBlur(formData.idCard.value, 'id')"
          />

          <form-field
            leftIcon="shouji1"
            placeHolder="请输入您的手机号"
            cellBgColor="#F5F5F5"
            v-model="formData.phone.value"
            :errorMsg="formData.phone.err"
            :success="formData.phone.success"
            @watchFocus="watchInputFocus('phone')"
            @watchBlur="watchInputBlur(formData.phone.value, 'phone')"
          />

          <form-field
            leftIcon="queren"
            placeHolder="请输入手机验证码"
            cellBgColor="#F5F5F5"
            v-model="formData.verifyCode.value"
            :errorMsg="formData.verifyCode.err"
            :success="formData.verifyCode.success"
            :showVerify="showVerify"
            :showCodeBtn="showCodeBtn"
            :authTime="authTime"
            @watchFocus="watchInputFocus('verify')"
            @watchBlur="watchInputBlur(formData.verifyCode.value, 'verify')"
            @getVerifyCode="getVerifyCode"
          />

          <div
            class="commit"
            @click="commitData"
            :class="isPassAll ? '' : 'disabled'"
          >
            确认提交
          </div>
        </div>
      </template>
    </new-layout>
  </div>
</template>

<style lang="scss" scoped>
  .field-group{
    padding-top: 20px;
  }
  .commit{
    width: 70%;
    padding: 25px;
    margin: 70px auto 30px;
    border-radius: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    background: $theme;
    color: #FFF;
  }

  .disabled{
    background: #8d8d8d;
  }
</style>

<script>
  import infoCell from '@/components/addresses/infoCell';
  import { _debounce } from '../../../mixins/utils';

  export default {
    name: '',
    components: {
      infoCell
    },
    data() {
      return {
        showVerify: true,
        showCodeBtn: true,
        clearAble: true, // input清除控件
        authTime : 0,
        // 表单数据
        formData: {
          name: {
            value: '',
            err: '',
            success: false
          },
          idCard: {
            value: '',
            err: '',
            success: false
          },
          phone: {
            value: '',
            err: '',
            success: false
          },
          verifyCode: {
            value: '',
            err: '',
            success: false
          }
        }
      };
    },
    computed: {
      isPassAll () {
        if (
          this.formData.name.success && this.formData.idCard.success &&
          this.formData.phone.success && this.formData.verifyCode.success
        ) {
          return true
        } else {
          return false
        }
      }
    },
    created() {
    },
    methods: {
      // 重置错误信息
      setErrMsg (value) {
        return value ? true : false;
      },

      clearValue () {
      },

      // 监听input组件聚焦事件
      watchInputFocus (flag) {
        switch (flag) {
          case 'name':
            this.formData.name.success = false;
            break;
          case 'id':
            this.formData.idCard.success = false;
            break;
          case 'phone':
            this.formData.phone.success = false;
            break;
          case 'verify':
            this.formData.verifyCode.success = false;
            break;
          default:
            break;
        }
      },

      // 监听input组件失焦事件
      watchInputBlur (value, flag) {
        switch (flag) {
          case 'name':
            this.formData.name.err = this.setErrMsg(value) ? '' : '请输入姓名';
            this.formData.name.success = this.setErrMsg(value) ? true : false;
            break;
          case 'id':
            this.formData.idCard.err = '';
            let idEmpty = this.setErrMsg(value);
            let isId = this.regIdCard(value);
            if (idEmpty) {
              if (!isId) {
                this.formData.idCard.err = '身份证号码格式错误'
              }
            } else {
              this.formData.idCard.err = '身份证号不能为空'
            }
            this.formData.idCard.success = idEmpty && isId ? true : false;
            break;
          case 'phone':
            let phoneEmpty = this.setErrMsg(value);
            let isPhone = this.regPhoneNumber(value);
            this.formData.phone.err = '';
            if (phoneEmpty) {
              if (!isPhone) {
                this.formData.phone.err = '手机号格式错误';
              }
            } else {
              this.formData.phone.err = '手机号不能为空';
            }
            this.formData.phone.success = phoneEmpty && isPhone ? true : false;
            break;
          case 'verify':
            this.formData.verifyCode.err = '';
            this.formData.verifyCode.err = this.setErrMsg(value) ? '' : '请输入验证码';
            this.formData.verifyCode.success = this.setErrMsg(value) ? true : false;
            break;
          default:
            break;
        }
      },

      /**
       * 获取验证码
       * 60s倒计时
       */
      getVerifyCode () {
        if (this.showCodeBtn) {
          this.showCodeBtn = false;
          this.authTime = 59;
          let authTimer = setInterval(() => {
            this.authTime--;
            if (this.authTime <= 0) {
              this.showCodeBtn = true;
              clearInterval(authTimer);
            }
          }, 1000);
        }
      },
      // 提交
      commitData: _debounce(function() {
        if (this.isPassAll) {
          console.log('提交表单数据!');
        }
      }, 800),
    }
  };
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值