第四期:vue输入组件封装

任务描述:

      使用vue封装一个输入框组件,实现基本的正则验证,前后缀图标插入等功能

具体完成内容:

router/index.js中路由配置

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',      //这里是路由也就是网址跳转的路径
      name: 'home',    //路由名称
      component: Home   //注册组件,注意这里要与具体组件中export default中设置的一致
    }
  ]
})

page/home/index.vue:使用输入框组件构建的页面

<template>
    <div id="wrap">
        <p class="text">普通输入框:</p>
        <input-box placeholder="请输入内容" id="normal"/>     //注意普通类型的参数传递,直接就是常规的属性写法
          
        <p class="text">字数限制输入框:</p>
        <input-box placeholder="输入限制为最多10个" maxlength="10"/>       

        <p class="text">禁止输入框:</p>
        <input-box :disabled="true" placeholder="禁止输入" class="wrap-no-input" id="forbid"/>  //布尔值的参数传递需要加冒号变成动态的,表示传入的不是字符串,是一个表达式

        <p class="text">密码输入框:</p>
        <input-box type="password" placeholder="请输入密码" id="pwd">
            <i class="iconfont icon-hidepwd right" slot="right" @click="change"></i>   //事件绑定使用v-on的简写形式@事件名="函数名"
        </input-box>

        <p class="text">带前后缀图标输入框:</p>
        <input-box placeholder="请输入要搜索的内容" id="withIcons"> 
            <i class="iconfont icon-search left" slot="left"></i>     //有名插槽的写法
            <i class="iconfont icon-close right" slot="right"></i>
        </input-box>
        
        <p class="text">正则验证输入框:</p>
        <input-box placeholder="6-8位字母或数字" id="regConfirm" pattern="/^([0-9a-zA-Z]){6,8}$/g"  @addTip = "showTip"/>  
        
    </div>
</template>

<script> 
    import InputBox  from '@/components/InputBox';       //引入组件
    export default {
        name: 'Home',
        components:{
            InputBox     //注册组件
        },
        data () {
            return {

            }
        },
        methods:{
            showTip(res){
                var tip = document.getElementById("tip");
                if(tip)
                {               
                    if(res == "验证成功")
                    {
                        tip.style.color = "green";                   
                    }else{
                        tip.style.color = "red";                   
                    }
                    tip.innerText = res;
                   
                }else{
                    var wrap = document.getElementById('wrap');
                    var el = document.createElement('p');
                    el.id = "tip";
                    el.innerText = res;
                    el.style.fontSize ="10px";
                    if(res == "验证成功")
                    {
                        el.style.color = "green";                   
                    }else{
                        el.style.color = "red";                   
                    }
                    wrap.appendChild(el);
                }
            },

            change(e){
                var list = e.target.classList;
                if(list.contains('icon-hidepwd')){

                    list.remove('icon-hidepwd');
                    list.add('icon-showpwd');
                    document.getElementById("pwd").type="text"

                }else if (list.contains('icon-showpwd')){
                    
                    list.remove('icon-showpwd');
                    list.add('icon-hidepwd');
                    document.getElementById("pwd").type="password"
                }               
            }
        }
    }
</script>
      
<style>
    @import "../../assets/css/iconfont.css";    //引入样式,注意这里引入的是外部的,style标签上不要添加scoped
    .text{
        font-size:15px;
    }
    
    .left,.right{
        color:rgb(150, 149, 149);    
    }
</style>

components/InputBox.vue:输入框组件具体封装

<template>
  <div  :class="className">    
        <slot name="left" class="left"></slot>
        <input 
            :type="type"                    //动态参数的绑定,使用v-bind的简写形式冒号:
            :placeholder="placeholder"
            :disabled = "disabled"
            :maxlength="maxlength"
            :id = "id"
            :pattern = "pattern"  
            class="input"
            v-model = "content"        //v-model双向数据绑定
            @blur = "blur"
        />
        <slot name="right"></slot>
  </div>
</template>

<script>
  export default {
    name: 'InputBox',
    props:{                         //参数接收。注意一般会校验类型,以及设置default默认值
        type:{
            type:String,
            default:'text'
        },
        placeholder:{
            type:String,
            default:''
        },
        leftshow:{
          type:Boolean,
          default:false
        },
        rightshow:{
          type:Boolean,
          default:false
        },
        disabled:{
          type:Boolean,
          default:false
        },
        maxlength:{
          type:String,
          default:'100'
        },
        className:{
            type:String,
            default:'wrap'
        },
        id:{
            type:String,
            default:''
        },
        pattern:{
          type:String,
          default:''
        }
    },
    data () {
      return {
          content:'',
          succShow:false,
          errShow:false
      }
    },
    methods:{
      blur(e){
          if(this.id === 'regConfirm'){
                var patt = eval(this.pattern);     //子组件接收到的props参数,也是可以直接使用this.参数名来调用的
                if(patt.test(e.target.value)){         //e.target.value获取输入框中的内容
                     var res = "验证成功"
                }else{
                    var res = "验证失败"
                }             
          }
          this.$emit('addTip',res);   //子组件中触发事件,参数分别为事件名和参数,父组件中监听的话,也是直接@事件名,与这里是一致的
      }
    }
  }

</script>


<style>
    *{
      padding:0;
      margin:0;
    }
   
    .wrap{
        display: flex;
        align-items: center;
        width: 200px;
        height: 30px;
        padding: 0 12px;
        margin:10px auto;
        background-color: #fff;
        border:1px solid rgb(31, 31, 31);
        border-radius: 5px;
    }


    .input{
        flex: 1;
        background: none;
        border: 0;
        margin: 0 10px;
        color: #999;
        line-height: 1.5; 
        outline:none; 

        /* 兼容火狐浏览器,去掉input本身红色边框的写法 */
        -moz-appearance: none !important;
        outline: none !important;
        -moz-outline: none !important;
        box-shadow: none !important;
        -moz-box-shadow: none !important;
    }

 
    .wrap-no-input{
        display: flex;
        align-items: center;
        width: 200px;
        height: 30px;
        padding: 0 12px;
        margin:10px auto;
        background-color: rgb(185, 184, 184);
        border:1px solid rgb(31, 31, 31);
        border-radius: 5px;
        color:#fff;
    }

    .wrap-no-input .input{
        color:#fff;
    }


     .wrap-textarea{
        display: flex;
        align-items: center;
        width: 200px;
        height: 100px;
        padding: 0 12px;
        margin:10px auto;
        background-color: #fff;
        border:1px solid rgb(31, 31, 31);
        border-radius: 5px;
        color:#fff;
     }

</style>

assets/css中引入字体图标文件并且创建fonts文件夹放入字体图标相关文件,注意修改下面的路径,不然报错:

@font-face {font-family: "iconfont";
  src: url('../fonts/iconfont.eot?t=1587914589125'); /* IE9 */
  src: url('../fonts/iconfont.eot?t=1587914589125#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAASEAAsAAAAACPAAAAQ1AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDKgqFBIQ/ATYCJAMUCwwABCAFhG0HWxvWB8iemjwJgtkgAgAFMo0jIYKv/dB9d/chhC5RgAqAVKKiItOycCxcK1vVqVJsVH3ZiAz/nvZeMwiZ1HYw2h2UtUmWKbs0EzLrhC8J5Yl/0tctJxb0E3AN+If7Ga98gPns21yywqJtOsEBdV+H6B3Iifotw6sOcjdOE+g0LhA8zsgrA3oKfVIgnlIkBvQSSqUiM7RCXbCygHgLKm0a5t0DvPF+P/6DxdADkioD/ayr++lSkPST+uSDdC9ykznwuj892HVkLAAK8bjQeAsJggsQnXK8lnVAa+gTfQW9PvksLlJYT/ZaGJX/8jpRhCQTNdCF3Ri3Hyr8pCyEwi9PhOCXF0Lil4/IuWIqcWdP4e9AjHHSiT6/KUtyY2pipW9kZGfk5A9JEdz6JKK7rBhseRw+b1t8ykClEm8Ti6zPKYRKpWi0XJTYiPnx3ZutRBfVgpK5I4ow0bqT5LFH3Y9H5dyTJWm9Wl1erlMolpn8Mp8ej1epWsRX1bCYlZ40qi4UzY/a2q7jWmv2LlOp2owW9nB7DY3FC85TjlqL5q3nu63mrMrmRvZwtssg9yTC5NgjUL9+HG56Ug4ht+cU8G6Xp0nZdaAut9fHdHS3Peg+vRf+uypdow2XtNY7hNl5bzMlD/X0y4Fr1sAcvf3vCgpfHk4utwyS3Z3oBZcXDszaewQRNCK9kFlRu1SKxRbz+eyd8V7olWZskJv719r/f79sw/LhZcNBltkARDNojjUb5EQ5OQd74Z3xIBlhNJL2kVlg67Wh/MlOQUcmslOj2WnbEbUGcWVqNd4tq0PgIJc3WhHrSavQtwre4LGjg4hBc+S8wQhz7ErHwOrH0tFH7k7uJnOlZRsdQh2HWtunic0um8gpf+aQY4jjBttDtKeHMDbJw7OAxifFCu9GW/5IlsJm1Mxi2MLdYsjMzLKZt9SS94NmujI/+xR6yC9464G7s8FPpsLye4T7VP7Ghy5ov9o07nebFoAfd2+txPY7BcBEnjcLzPowWMCGonB0VVWkYospmSpnsTgJnYaGDyLKoFf9iEfA6YTWSARJYwyy1gSq4Bag0mUZaq096DQvc32XIQxEFH3AnH4Eod9BSHp9gqzffVTBvYTKqM9Q6w8EOl2H5Y5dpoIySGVwjMWlaEULSknoOsLUsAZ+ZglONtRgTJzjEcQ4I6M8aDBfmI5k4nU408ccWSMZwrIESjB0LZqBzsNrami0nqGrcAnLr2TZ+hiBgCh6Jb6ErgUGjjBwGBZOClWhBYoiQatDOJ1ZBpmfL4EjNaiBYSpKytRiOIYM1T0qGJ8QgMoU1oFKzqW/TCNSCBaLoMYRGLRaqAysx9UYQRqqvnhYFZwEi6+yhb9eDAFpRUCF/PHFtdeY9WeW1Q+pggcRqAW1oQ7ofsjWYjXh+98mjIr1iDYgsDpSilVRTqEO20BJKhsAAAAAAA==') format('woff2'),
  url('../fonts/iconfont.woff?t=1587914589125') format('woff'),
  url('../fonts/iconfont.ttf?t=1587914589125') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('../fonts/iconfont.svg?t=1587914589125#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-hidepwd:before {
  content: "\e624";
}

.icon-showpwd:before {
  content: "\e625";
}

.icon-search:before {
  content: "\e627";
}

.icon-close:before {
  content: "\e569";
}

最后运行的结果:

猜你喜欢

转载自www.cnblogs.com/xurui-blog/p/12796097.html