zoukankan      html  css  js  c++  java
  • 基于vue实现的 input 小组件

    最近看到一个挺有趣的input交互效果,尝试着用vue做一个,效果如下:
    1.没有数值时,显示placeholder;

    2.触发焦点时,label动画上移,placeholder清空;

    1.有值时,label依旧存在;

    vue代码如下:

    <template>
        <div class="page">
            <div class="inputBox" :class="{inputBoxActive:isNameInputActive}">
               <input class="inputSelf form-control"  v-model="nameVal" :placeholder="placeholderName" @input="onInputName" @focus="onFocusName" @blur="onBlurName"></input> 
               <label class="inputLabel">your name</label>    
            </div>
            <div class="inputBox" :class="{inputBoxActive:isPhoneInputActive}">
               <input class="inputSelf form-control"  v-model="phoneVal" :placeholder="placeholderPhone" @input="onInputPhone" @focus="onFocusPhone" @blur="onBlurPhone"></input> 
               <label class="inputLabel">your phone</label>    
            </div>
            <div class="inputBox" :class="{inputBoxActive:isEmailInputActive}">
               <input class="inputSelf form-control"  v-model="emailVal" :placeholder="placeholderEmail" @input="onInputEmail" @focus="onFocusEmail" @blur="onBlurEmail"></input> 
               <label class="inputLabel">your email</label>    
            </div>
        </div>
    </template>
    <script>
        export default{
            data(){
                return{
                    isNameInputActive:false,
                    nameVal:'',
                    placeholderName:'your name',
                    isPhoneInputActive:false,
                    phoneVal:'',
                    placeholderPhone:'your phone',
                    isEmailInputActive:false,
                    emailVal:'',
                    placeholderEmail:'your email'
                }
            },
            methods:{
                onFocusName:function(){
                    this.isNameInputActive = true;
                    this.placeholderName = '';
                },
                onInputName:function(){
                    this.isNameInputActive = true;
                    this.placeholderName = '';
                },
                onBlurName:function(){
                    if(!this.nameVal){
                        this.isNameInputActive = false;
                        this.placeholderName = 'your name';
                    }else{
                        this.isNameInputActive = true;
                    } 
                },
                onFocusPhone:function(){
                    this.isPhoneInputActive = true;
                    this.placeholderPhone = '';
                },
                onInputPhone:function(){
                    this.isPhoneInputActive = true;
                    this.placeholderPhone = '';
                },
                onBlurPhone:function(){
                    if(!this.phoneVal){
                        this.isPhoneInputActive = false;
                        this.placeholderPhone = 'your phone';
                    }else{
                        this.isPhoneInputActive = true;
                    } 
                },
                onFocusEmail:function(){
                    this.isEmailInputActive = true;
                    this.placeholderEmail = '';
                },
                onInputEmail:function(){
                    this.isEmailInputActive = true;
                    this.placeholderEmail = '';
                },
                onBlurEmail:function(){
                    if(!this.emailVal){
                        this.isEmailInputActive = false;
                        this.placeholderEmail = 'your email';
                    }else{
                        this.isEmailInputActive = true;
                    } 
                }
            }
        }
    </script>
    <style scoped>
    .form-control {
        display: block;
         100%;
        height: 36px;
        padding: 6px 12px;
        font-size: 16px;
        line-height: 1.42857143;
        color: #555;
        background-color: #fff;
        background-image: none;
        border: 1px solid #ccc;
        border-radius: 2px;
        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
        transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s
    }
    .form-control:focus {
        border-color: #66afe9;
        outline: 0;
        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
    }
    
    .form-control::-moz-placeholder {
        color: #666;
        opacity: 1
    }
    
    .form-control:-ms-input-placeholder {
        color: #666
    }
    
    .form-control::-webkit-input-placeholder {
        color: #666
    }
    
    .form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control {
        cursor: not-allowed;
        background-color: #eee;
        opacity: 1
    }
    
    .inputBox{
        position:relative;
        80%;
        margin:0 auto;
        margin-top:24px;
        margin-bottom:8px;
    }
    .inputSelf{
        z-index: 2;
        position: relative;
        background: 0;
        -webkit-transition: all .4s ease;
        transition: all .4s ease
    }
    .inputLabel {
        position: absolute;
        display: none;
         100%;
        left: 0;
        padding: 12px 16px;
        margin: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        font-size: 12px;
        font-weight: 500;
        color: #333;
        -webkit-transition: all .4s ease;
        transition: all .4s ease;
    }
    label.inputLabel {
        display:block;
        opacity: 0;
        bottom: 0;
        padding: 12px 16px;
    }
    .inputBoxActive label.inputLabel{
        display:block;
        opacity: 1;
        bottom: 100%;
        padding: 0 16px;
    }
    </style>
    

    虽然效果有了,但是同样的交互效果,应该独立成一个组件。
    所以,接下来开始组件化。

    第一步:创建myInput.vue。

    <template>
      <div class="inputBox" :class="{inputBoxActive:isInputActive}">
          <input class="inputSelf form-control"  v-model="inptVal" :placeholder="inptPlaceholder" @input="onInput" @focus="onFocus" @blur="onBlur" v-on:input="updateValue($event.target.value)"></input>
          <label class="inputLabel">{{inptLabel}}</label>
      </div>
    </template>
    <script>
        export default{
            data(){
                return{
                    isInputActive:false,
                    inptVal:this.myVal,
                    inptPlaceholder:this.placeholderText,
                    inptLabel:this.placeholderText
                }
            },
            props: {
                myVal:{
                    type:String,
                    default:''
                },
                placeholderText:{
                    type:String,
                    default:''
                }
            },
            methods: {
                onFocus:function(){
                    this.isInputActive = true;
                    this.inptPlaceholder = '';
                },
                onInput:function(){
                    this.isInputActive = true;
                    this.inptPlaceholder = '';
                },
                onBlur:function(){
                    if(!this.inptVal){
                        this.isInputActive = false;
                        this.inptPlaceholder = this.placeholderText;
                    }else{
                        this.isInputActive = true;
                    } 
                },
                updateValue: function (value) {
                    this.$emit('input', value)
                }
            }
        }
    </script>
    <style scoped>
    .form-control {
        display: block;
         100%;
        height: 36px;
        padding: 6px 12px;
        font-size: 16px;
        line-height: 1.42857143;
        color: #555;
        background-color: #fff;
        background-image: none;
        border: 1px solid #ccc;
        border-radius: 2px;
        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
        transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s
    }
    .form-control:focus {
        border-color: #66afe9;
        outline: 0;
        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
    }
    
    .form-control::-moz-placeholder {
        color: #666;
        opacity: 1
    }
    
    .form-control:-ms-input-placeholder {
        color: #666
    }
    
    .form-control::-webkit-input-placeholder {
        color: #666
    }
    
    .form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control {
        cursor: not-allowed;
        background-color: #eee;
        opacity: 1
    }
    
    .inputBox{
        position:relative;
        80%;
        margin:0 auto;
        margin-top:24px;
        margin-bottom:8px;
    }
    .inputSelf{
        z-index: 2;
        position: relative;
        background: 0;
        -webkit-transition: all .4s ease;
        transition: all .4s ease
    }
    .inputLabel {
        position: absolute;
        display: none;
         100%;
        left: 0;
        padding: 12px 16px;
        margin: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        font-size: 12px;
        font-weight: 500;
        color: #333;
        -webkit-transition: all .4s ease;
        transition: all .4s ease;
    }
    label.inputLabel {
        display:block;
        opacity: 0;
        bottom: 0;
        padding: 12px 16px;
    }
    .inputBoxActive label.inputLabel{
        display:block;
        opacity: 1;
        bottom: 100%;
        padding: 0 16px;
    }
    </style>
    

    需要注意在构建组件时,从父传入的props值,在子组件里不能直接修改,否则会报类似下边的错误:

    [Vue warn]: Avoid mutating a prop directly since the value will be overwritt ...
    

    正确的应对方式是:

    1. 定义一个局部变量,并用 prop 的值初始化它:
    data(){
            return{
                isInputActive:false,
                inptVal:this.myVal,
                inptPlaceholder:this.placeholderText,
                inptLabel:this.placeholderText
            }
    },
    props: {
            myVal:{
                type:String,
                default:''
            },
            placeholderText:{
                type:String,
                default:''
            }
    }
    
    1. 定义一个计算属性,处理 prop 的值并返回:
    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    

    第二步:在页面里引入myInput组件。

    <script>
        import myInput from '../../components/myInput/myInput';
        export default{
            components: {
                myInput
            },
            data(){
                return{
                    nameVal:'',
                    placeholderName:'your name',
                    phoneVal:'',
                    placeholderPhone:'your phone',
                    emailVal:'',
                    placeholderEmail:'your email'
                }
            },
            methods:{
                saveForm:function(){
                    console.log(this.nameVal);
                    console.log(this.phoneVal);
                    console.log(this.emailVal);
                },
                inptParent1:function(params){
                    const trimmedText = params.trim();
                    this.nameVal = trimmedText;
                },
                inptParent2:function(params){
                    const trimmedText = params.trim();
                    this.phoneVal = trimmedText;
                },
                inptParent3:function(params){
                    const trimmedText = params.trim();
                    this.emailVal = trimmedText;
                }
            }
        }
    </script>
    

    第三步:在html中引入myInput元素。

    <template>
        <div class="page">
            <myInput 
                :myVal="nameVal"
                :placeholderText="placeholderName" 
                v-on:input="inptParent1"
            />
            <myInput 
                :myVal="phoneVal"
                :placeholderText="placeholderPhone" 
                v-on:input="inptParent2"
            />
            <myInput 
                :myVal="emailVal"
                :placeholderText="placeholderEmail" 
                v-on:input="inptParent3"
            />
            <div class="btnBox">
                <Button type="ghost" @click="saveForm" shape="circle">提交</Button>  
            </div>
        </div>
    </template>
    <style scoped>
    .btnBox{
        padding-top:24px;
        text-align: center;
    }
    </style>
    

    第四步:myInput组件的数值变化回传到父组件里。

    在myInput组件的input上绑定v-on:input="updateValue($event.target.value)"触发方法:

    <template>
      <div class="inputBox" :class="{inputBoxActive:isInputActive}">
          <input class="inputSelf form-control"  v-model="inptVal" :placeholder="inptPlaceholder" @input="onInput" @focus="onFocus" @blur="onBlur" v-on:input="updateValue($event.target.value)"></input>
          <label class="inputLabel">{{inptLabel}}</label>
      </div>
    </template>
    

    在myInput组件注册updateValue方法:

            methods: {
                updateValue: function (value) {
                    this.$emit('input', value)
                }
            }
    

    在父组件引用myInput组件,绑定v-on:input="inptParent1"方法:

    <myInput 
                :myVal="nameVal"
                :placeholderText="placeholderName" 
                v-on:input="inptParent1"
            />
    

    在父组件注册inptParent1方法:

            methods:{
                inptParent1:function(params){
                    const trimmedText = params.trim();
                    this.nameVal = trimmedText;
                }
            }
    
  • 相关阅读:
    【redis】主从复制
    【redis】订阅功能
    【redis】基础
    MySQL【十二】pymysql操作数据库
    MySQL【十一】创建索引
    MySQL【十】认识索引
    MySQL【九】树
    MySQL【八】多表查询
    ubuntu 制作ISO模块
    ubuntu 开机自启动
  • 原文地址:https://www.cnblogs.com/xmyun/p/7651031.html
Copyright © 2011-2022 走看看