美文网首页
基于Vant的field输入框实现输入内容可见的密码输入框(v-

基于Vant的field输入框实现输入内容可见的密码输入框(v-

作者: KATENGC | 来源:发表于2020-04-23 17:38 被阅读0次

    在实际项目开发中,要实现密码输入框带密码可见切换按钮(右侧的👀),点击👀可以显示或隐藏密码。

    image.png
    我的项目中使用有赞的Vant组件,但在官方文档中Filed密码框没有右侧👀(没有使用过Vant的同学可以先了解下)。
    image.png

    出于这样的原因,我决定自己对field输入框进行二次封装,来实现这个功能

    我们先来了解下v-model

    v-model是什么?
    1. v-model 即可以作用在普通表单元素上,又可以作用在组件上。
    2. vue.js隐式添加 value 的 prop,子组件通过 props.value 接收值。
    3. 子组件通过 this.$emit('input'),改变父组件 v-model 绑定的值。
    4. v-model 可以实现双向绑定,无需定义接收事件。
    那为什么v-model能实现双向绑定呢?
    <input v-model="something">
    

    经过vue转换后变成来这样

    <input
      v-bind:value="something"
      v-on:input="something = $event.target.value">
    

    那开始我的组件封装之旅吧

    1. 先创建组件,命名为PasswordField
    <template>
    <!--带密码可见功能的密码输入框-->
    <van-field
      v-model="password"
      type="password"
      label='密码'
      placeholder='请输入密码'>
      <!--利用插槽添加了右侧图标-->
      <template slot="right-icon">
        <img style="width: 0.59rem;height: 0.59rem"
             src="static/img/icon_login_show@2x.png"
             alt="">
      </template>
    </van-field>
    </template>
    

    我们来看下初步效果


    image.png

    接下来实现下点击右侧眼睛切换图标的功能,需要在img上添加点击事件switchPasswordType,主要是先两个功能:
    1.实现右侧图标切换
    2.动态修改field的type

    <template>
      <!--带密码可见功能的密码输入框-->
      <van-field
        v-model="password"
        :type="passwordType"
        label='密码'
        placeholder='请输入密码'>
        <!--利用插槽添加了右侧图标-->
        <template slot="right-icon">
          <img style="width: 0.59rem;height: 0.59rem"
               :src="passwordType==='password'?'static/img/icon_login_show@2x.png':'static/img/icon_login_hide@2x.png'"
               alt=""
               @click="switchPasswordType">
        </template>
      </van-field>
    </template>
    

    定义了变量passwordType,其默认值为password

    data() {
          return {
            password:'',//当前输入框的值
            passwordType: 'password'//输入框类型
          }
    }
    

    添加switchPasswordType方法,动态修改passwordType的值

    methods: {
          switchPasswordType() {
            this.passwordType = this.passwordType === 'password' ? 'text' : 'password'
          }
    }
    

    接下来就是动态修改输入框类型type,同时改变显示的图标,这样就实现了点击👀实现输入框文字可见或不可见

    //输入框类型修改
    :type="passwordType"
    
    //图标切换
    :src="passwordType==='password'?'static/img/icon_login_show@2x.png':'static/img/icon_login_hide@2x.png'"
    

    以上基本能实现我们要的功能,我们使用下这个组件

    <template>
      <div>
        <title-bar></title-bar>
        <!--自定义的密码输入框-->
        <password-field></password-field>
      </div>
    </template>
    
    image.png

    切换后


    image.png

    但是我们如何能在外部获取到当前输入框的值呢,也就是说父组件如何得到子组件的数据?同时又要实现子组件中修改输入框的内容能实时更新到父组件中。接下来就是重点啦!!!(利用上面v-model来实现双向绑定)
    对于一个子组件来说,首先要先接收一个value,同时value改变时又要通知父组件

    <template>
      <!--带密码可见功能的密码输入框-->
      <van-field
        v-model="password"
        :type="passwordType"
        label='密码'
        placeholder='请输入密码'
        @input="$emit('input',password)">
        <!--利用插槽添加了右侧图标-->
        <template slot="right-icon">
          <img style="width: 0.59rem;height: 0.59rem"
               :src="passwordType==='password'?'static/img/icon_login_show@2x.png':'static/img/icon_login_hide@2x.png'"
               alt=""
               @click="switchPasswordType">
        </template>
      </van-field>
    </template>
    
    <script>
    
      export default {
        name: "PasswordField",
        model: {
          prop: 'inputValue',
          event: 'input'
        },
        props: {
          /**
           * 当前输入的值
           */
          inputValue: {
            type: String,
            default: ''
          }
        },
        data() {
          return {
            password: this.inputValue,
            passwordType: 'password',
          }
        },
        methods: {
          switchPasswordType() {
            this.passwordType = this.passwordType === 'password' ? 'text' : 'password'
          }
        }
      }
    </script>
    

    这里主要做了两个工作:
    1.添加model,将从父组件传入的inputValue赋值给子组件中的password,同时通过v-model实现绑定

    model: {
          prop: 'inputValue',
          event: 'input'
        },
        props: {
          /**
           * 当前输入的值
           */
          inputValue: {
            type: String,
            default: ''
          }
        },
        data() {
          return {
            password: this.inputValue,
            passwordType: 'password',
          }
        },
    

    2.利用field的input事件,将子组件中的password通过$emit实时通知父组件

    @input="$emit('input',password)"
    

    现在我们来测试下

    <template>
      <div>
        <title-bar></title-bar>
    
        <!--自定义的密码输入框-->
        <password-field v-model="parentPassword"></password-field>
    
      </div>
    </template>
    

    我们来打印下parentPassword


    image.png

    可以看到已经获取到了子组件的输入框内容,目的达成👏👏👏

    附上完整的代码(自己完善了下)
    PasswordField.vue

    <template>
      <!--带密码可见功能的密码输入框-->
      <van-field
        class="field"
        v-model="password"
        :type="passwordType"
        :label=label
        :placeholder=placeholder
        :required="required"
        :rules="[{required: rulesRequired, message: placeholder},{ pattern,message: rulesMessage}]"
        @input="$emit('input',password)">
        <template slot="right-icon">
          <img style="width: 0.59rem;height: 0.59rem"
               :src="passwordType==='password'?'static/img/icon_login_show@2x.png':'static/img/icon_login_hide@2x.png'"
               alt=""
               @click.stop="switchPasswordType">
        </template>
      </van-field>
    </template>
    
    <script>
      import * as _ from 'common/js/config'
    
      export default {
        name: "PasswordField",
        model: {
          prop: 'inputValue',
          event: 'input'
        },
        props: {
          /**
           * 当前输入的值
           */
          inputValue: {
            type: String,
            default: ''
          },
          /**
           * 输入框左侧文本
           */
          label: {
            type: String,
            default: '密码'
          },
          /**
           * 占位提示文字
           */
          placeholder: {
            type: String,
            default: '请输入密码'
          },
          /**
           * 是否显示表单必填星号
           */
          required: {
            type: Boolean,
            default: false
          },
          /**
           * 校验提示文案
           */
          rulesMessage: {
            type: String,
            default: '请输入正确的密码'
          },
          /**
           * 校验规则:是否为必须字段
           */
          rulesRequired: {
            type: Boolean,
            default: true
          }
        },
        data() {
          return {
            password: this.inputValue,
            passwordType: 'password',
            pattern: _.pwdReg,//密码规则
          }
        },
        methods: {
          /**
           * 密码是否可见
           */
          switchPasswordType() {
            this.passwordType = this.passwordType === 'password' ? 'text' : 'password'
          }
        }
      }
    </script>
    
    <style scoped lang="stylus" rel="stylesheet/stylus">
      .field {
        padding 0.37rem 0.4rem
      }
    
      .field /deep/ .van-field__right-icon {
        display flex
      }
    
      .field /deep/ .van-field__label {
        width auto
        margin-right 0.4rem
      }
    </style>
    

    ModifyPsw.vue

    <template>
      <div>
        <title-bar></title-bar>
    
        <van-form @submit="onSubmit">
          <password-field v-model="oldPassword" label="旧密码" placeholder="请输入旧密码"></password-field>
    
          <password-field v-model="newPassword" label="新密码" placeholder="6-20位密码,至少含字母及数字"></password-field>
    
          <div style="margin: 0.67rem 0.4rem">
            <van-button class="btn-confirm" round block type="info" native-type="submit">确定修改</van-button>
          </div>
        </van-form>
      </div>
    </template>
    
    <script>
      import TitleBar from "components/base/TitleBar";
    
      import PasswordField from "../../../base/field/PasswordField";
    
      export default {
        name: "ModifyPsw",
        components: {
          PasswordField,
          TitleBar
        },
        data() {
          return {
            oldPassword: '',//旧密码
            newPassword: '',//新密码
          }
        },
        methods: {
          /**
           * 点击【确定修改】
           */
          onSubmit() {
            console.log('oldPassword:', this.oldPassword)
            console.log('newPassword:', this.newPassword)
          }
        }
      }
    </script>
    
    <style scoped lang="stylus" rel="stylesheet/stylus">
      .btn-confirm {
        height 1.2rem
        font-size 0.48rem
      }
    </style>
    

    最终效果


    image.png

    相关文章

      网友评论

          本文标题:基于Vant的field输入框实现输入内容可见的密码输入框(v-

          本文链接:https://www.haomeiwen.com/subject/mduaihtx.html