接上篇文章,费心劳神好几天的项目框架终于能够用了。如今能够开始写页面了吧?javascript
既然上司说,UI框架咱们本身来写,那咱们就本身写吧。css
虽然答应的时候挺痛快。真到写的时候,首先就不知道从哪里开始下手了html
那咱们就一点点来。先从组件框架开始一点点作。html5
首先先排布一下UI框架目录。在于上司聊了许久后,最后决定用这种目录架构:java
红色箭头表明业务组件(business components) 存放项目中业务类组件的地方。如头部导航,我的信息卡等正则表达式
绿色箭头表明业务组件(framework components) 存放项目中基础框架组件的地方。如按钮,输入框,开关等
bash
蓝色箭头是导出文件。统一导出全部组件方便调用(文章后面会讲到)架构
好的,那咱们先从input开始app
咱们先看看效果图:框架
大体就是这个样子。很是简洁的UI,功能也算是够用了。(这里给UI大哥的做品点个赞)
我把它拆分红了这个样子(如图) 每一个颜色框内都是不一样的slot(具名插槽)
大体代码就是这个样子的存在:
<template>
<div class="input-wrapper">
<div class="input-content">
<div class="input__left">
<slot name="left"></slot> //红色框插槽
</div>
<div class="input__center">
<input type="text" title="">
<div class="input__center__tools">
<i class="iconfont icon-qingchu" v-show="inputValue" @click="clearInputValue"></i>
//清除value的地方
</div>
</div>
<div class="input__right">
<slot name="right"></slot> //input右侧的自定义区。能够放置“获取验证码”之类的操做
</div>
</div>
<div class="input-tip">
<slot name="tip"></slot> //下方提示区域插槽
</div>
</div>
</template>复制代码
css方面选用flex布局。字体/图标大小,元素间距使用rem布局 class命名使用bem方式
CSS:
<style scoped>
.input__left .iconfont {
font-size: 2rem;
}
.input-content {
display: flex;
flex-direction: row;
}
.input__left {
padding-bottom: 0.4rem;
}
.input__left > span {
font-size: 1.5rem;
}
.input__center {
margin-left: .5rem;
flex: 1;
display: flex;
flex-direction: row;
padding-bottom: .3rem;
border-bottom: 1px solid #E9E9E9;
}
.input__center > .input__center__tools > .iconfont {
color: #141414;
cursor: pointer;
font-size: 2rem;
}
.input__center > input {
text-indent: .3rem;
flex: 1;
border: 0;
width: 100%;
height: 100%;
font-size: 1.3rem;
color: #3b3b3b;
outline: none;
}
.input__right {
padding-left: .5rem;
padding-bottom: .3rem;
border-bottom: 1px solid #E9E9E9;
}
.icon-qingchu {
color: #E9E9E9 !important;
}
.input-tip {
margin-top: .3rem;
margin-left: 2.45rem;
font-size: 1rem;
}
.input-tip i {
font-size: 1rem;
}
.input-tip--info {
color: #BFBFBF;
}
.input-tip--success {
color: #5CD18B;
}
.input-tip--warning {
color: #FFC53D;
}
.input-tip--error {
color: #FF7875;
}
</style>
复制代码
OK,这时候咱们的UI画完了。还能输入文字...不错哦
这时候遇到了一个问题:以前咱们直接v-model就能够双向数据绑定input的value。如今input在组件内包着。那咱们如何在父组件绑定子组件内的input呢??
找了半天教程,找到了这样一个操做:
啊哈,这样就好说了。那咱们能够这样去写:
<input :type="textType" title="" v-model="inputValue"
@input="$emit('input', inputValue)">
export default{
data() {
return {
inputValue: "" //子组件内绑定一遍。等会要用
}
},
}
复制代码
外部调用:
<zb-input v-model="phoneLogin.phone.value">复制代码
这样就大功告成了。这样父组件调用方就能够绑定到输入框的值了
OK,接下来咱们开始作“一键清空”功能
因为咱们传出去的值,是走的子组件内的双向绑定的data。因此理论上咱们只须要把绑定在data内的变量清空就好了
this.inputValue = '';复制代码
可是这样会有问题,子组件内已经清空,父组件仍然保留着值。
那咱们就模仿上面的作法,再$emit一次~~~
clearInputValue() {
this.inputValue = ''; //清空输入框的值
this.$nextTick(function () { //在修改数据以后使用 $nextTick,则能够在回调中获取更新后的 DOM
this.$emit('input', this.inputValue); //执行传出操做
});
},复制代码
这样功能就实现了。以下图( 清除按钮的颜色太浅。动图录制软件看不见~~~ 抱歉)
好的,那接下来实现一下密码“显示”“隐藏“的功能
这个功能也比较有意思。不仅是把输入框的type换成password那么简单。还能还原以前传入的input type
首先咱们先定义一个props:
inputType: { //输入框类型
default: 'text'
}
canHide: { //是否支持隐藏值
required: false,
default: false
},
复制代码
这个props从父组件接收想要的input类型。若是没有就默认text
而后copy一份同义的变量到data里。保持以prop作参考,data负责内部更改~~~
textType: this.inputType //从props里接收初始值
isHideValue: false //如今是否隐藏输入框值复制代码
而后清除事件:
hideInputValue() {
if (this.textType === this.inputType) { //若是props内和data内相等。说明是没隐藏状态
this.textType = "password"; //让他变为password类型
this.isHideValue = true; //控制隐藏按钮的类名。更换icon
} else {
this.textType = this.inputType; //替换为初始化的type
this.isHideValue = false;
}
}复制代码
按钮方面:
<i class="iconfont"
:class="[{'icon-yanjing_yincang_o':!isHideValue},{'icon-yanjing_xianshi_o':isHideValue}]"
@click="hideInputValue" v-show="canHide && inputValue"></i>复制代码
这样就大功告成啦!!
既然咱们作input了,那就作到底呗~~
让他支持一下自定义规则验证
经过和上司商定,暂选了这几个规则支持:
数据格式大概是这样的:
regex: {
required:false,
lengthRange: {
max: 11,
min: 1
},
regular: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/
}复制代码
而后经过props传进去:
regexObject: { //校验对象
required: false
}
:regexObject="regex"复制代码
而后准备工做作好了,开始准备校验工做了
校验顺序按照队列校验。分别各自返回校验结果。没有指定的放行
是否必填校验:
reg_required(value) {
if (this.regexObject.required) { //若是有required这个字段
return !!value //返回value是否有值
} else {
return null; //表明没填required这个字段
}
},复制代码
Tips:" !! " 经常用来作类型判断,在第一步!(变量)以后再作逻辑取反运算。简单理解就是判断这个变量是否存在值。
等价 " value!=null&&typeof(value)!=undefined&&value!='' "
正则表达式校验:
reg_regular(value) {
if (this.regexObject.regular) { //若是有regular这个字段
return this.regexObject.regular.test(value); //返回校验的结果
} else {
return null; //表明没填regular这个字段
}
},复制代码
长度校验:
reg_lengthRange(value) {
if (this.regexObject.lengthRange) { //若是有lengthRange这个字段
return value.length >= this.regexObject.lengthRange.min //若是value的长度大于等于预约最小值
&& value.length <= this.regexObject.lengthRange.max //若是value的长度小于等于预约最大值
} else {
return null; //表明没填lengthRange这个字段
}
},复制代码
主入口方法
regex(value) {
let val = value.toString(); //统一转成字符串。防止没有length属性
let info = {}; //空对象
info.value = val; //一块把输入框的值传出去
if (this.regexObject) { //若是props传了校验对象
info.required = this.reg_required(val);
info.regular = this.reg_regular(val);
info.lengthRange = this.reg_lengthRange(val);
}
return info;
},复制代码
最后在输入框失焦事件(blur)内调用了一下:
inputReg() {
console.log(this.regex(this.inputValue));
},复制代码
控制台:
本身体会~~~
而后发现了个bug,虽然定义了最大输入范围,但超出只是提示不由止输入
因而watch监听一下inputValue
inputValue(){
if (this.regexObject && this.regexObject.lengthRange) {
if (this.inputValue.length > this.regexObject.lengthRange.max) { //若是输入框长度大于了既定最大长度
this.inputValue = this.inputValue.slice(0, this.regexObject.lengthRange.max);//从0开始截取。截到最大长度
return false;
}
} else {
return false;
}
}复制代码
由于html5把maxlength属性去掉了.....因此只能字符串截取
这样一个入门级别的Input就作好了!!功能还算是比较实用