接上篇文章,費心勞神好幾天的項目框架終於能夠用了。如今能夠開始寫頁面了吧?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就作好了!!功能還算是比較實用