前言
- 近期專案中使用的vux中的input,以及使用自定義校驗規則和動態匹配錯誤提示,有時間記錄下自己的使用經歷和原始碼分析。希望大家多多指正,留言區發表自己寶貴的建議。
詳解
- 列舉官方文件中常用的幾個屬性的使用方法,程式碼如下
<group ref="group">
<x-input v-model="name"
class="vux-input__name"
title="名字"
placeholder="tell me your name"
required
:is-type="checkNameValid"
@on-change="onValueChange">
<div slot="label"
class="name__icon">
<icon type="success"></icon>
</div>
</x-input>
</group>
複製程式碼
官方文件有詳細的解釋,required
屬性表示此選項為必填,is-type
可以繫結一個函式,作為校驗,這個函式得返回一個物件。格式如下
checkValid(name) {
return {
valid: name === '三隻萌新',
msg: '你不是萌新'
}
}
複製程式碼
valid可以設定為你的校驗規則,需要返回一個布林值,msg是錯誤的提示資訊。
vux本身寫好幾種校驗方式,如果使用email,china-name,china-mobile這幾種方式直接繫結字串即可。
solt插槽如slot="label"用於自定義title,原始碼如下
<slot name="label">
<label class="weui-label"
:class="labelClass"
:style="{width: labelWidth || $parent.labelWidth || labelWidthComputed, textAlign: $parent.labelAlign, marginRight: $parent.labelMarginRight}"
v-if="title"
v-html="title"
:for="`vux-x-input-${uuid}`"></label>
<inline-desc v-if="inlineDesc">{{ inlineDesc }}</inline-desc>
</slot>
複製程式碼
分析:class="labelClass"動態繫結樣式以物件的形式返回一個{[className]:Boolean}的格式的物件
labelClass() {
return {
'vux-cell-justify':
this.$parent.labelAlign === 'justify' ||
this.$parent.$parent.labelAlign === 'justify'
}
}
複製程式碼
同樣的方式檢視他父級是否有labelAlign屬性,vux-cell-justify類名對應的樣式沒有應用。
使用場景
場景1
假設在一個提交頁面,當我們提交時判斷輸入框中的值是否是符合我們的要求,如果不符合,給出錯誤提示,如果符合提交後將輸入框中的資料清空。
需求:
- 如果還有停留在本頁面我們需要將上一次的資料全部清空
問題:
- 我們需要初始化值,但是會發現如果我們設定了required後校驗還是會觸發。如何讓資料清空並且讓校驗也清空。
解決方法:
- 文件中寫了reset可以重置輸入框值,清除錯誤資訊 使用方式:
- 在x-input外層的group標籤上繫結ref來訪問子元件。因此我們可以通過 this.$refs.group.$children獲取到input元件集合並且可以使用元件中定義的reset方法 檢視原始碼
- 如果你的專案中已經安裝了vux可以通過安裝Search node_modules查詢node_modules資料夾中vux安裝包路徑為
vux/src/components/x-input/index.vue
檔案 reset方法原始碼如下:
reset(value = '') {
this.dirty = false
this.currentValue = value
this.firstError = ''
this.valid = true
}
複製程式碼
回到我們的業務邏輯中當我們點選提交按鈕時程式碼如下
onSubmitClick() {
if (!this.isInvalid) {
this.$refs.group.$children.forEach(child => {
child.reset()
})
} else {
// 展示提示資訊
this.isShowToast = true
}
複製程式碼
本以為這樣就可以清空資料了,沒想到點選按鈕時資料是清空了,但是還是有報錯圖示顯示。
通過vue-devtools可以看到valid的值為false檢視vux原始碼檢視涉及到valid程式碼如下
validate() {
// ...省略與本次無關的校驗方法
if (!this.currentValue && this.required) {
this.valid = false
this.errors.required = '必填哦'
this.getError()
return
if (typeof this.isType === 'function') {
/*
取出自定義函式中的校驗結果 是一個Boolean
checkNameValid(name) {
return {
valid: name === '三隻萌新',
msg: '你不是萌新'
}
}
*/
const validStatus = this.isType(this.currentValue)
this.valid = validStatus.valid
if (!this.valid) {
// 如果校驗值無效將自定義校驗的msg賦值給errors物件下的format
this.errors.format = validStatus.msg
this.forceShowError = true
this.getError()
return
} else {
// 如果校驗值有效則將error物件下的format刪除
delete this.errors.format
}
// 如果都符合將valid賦值為有效
this.valid = true
}
}
複製程式碼
validate函式校驗當前是否有值,是否為必填,如果當前值的校驗方式是函式,將校驗結果賦值給valid
。如果valid是false則將自定義的msg統一儲存在errors物件下,errors是用來儲存不同型別的錯誤資訊
。 然後執行getError函式
getError() {
let key = Object.keys(this.errors)[0]
this.firstError = this.errors[key]
console.log('firstError' + this.firstError)
}
複製程式碼
Object.keys(this.errors)返回errors物件下的所有可列舉屬性,並且取第一個作為鍵名,取出對於的值賦值給firstError ,firstError是提示框文字
<toast v-model="showErrorToast"
type="text"
width="auto"
:time="600">{{ firstError }}</toast>
複製程式碼
當點選錯誤圖示判斷是否有firstError,shouldToastError未傳入值預設為true,點選時如果valide校驗為錯誤時會觸發getError函式將錯誤提示賦值給firstError,所以會將fistError對應的提示資訊顯示出來。而圖示的顯示與否與valid有關,其中一個條件是valid為false時才會顯示。
<icon @click.native="onClickErrorIcon"
class="vux-input-icon"
type="warn"
:title="!valid ? firstError : ''"
v-show="showWarn"></icon>
shouldToastError: {
type: Boolean,
default: true
}
showWarn() {
return (
!this.novalidate &&
!this.equalWith &&
!this.valid &&
this.firstError &&
(this.touched || this.forceShowError)
)
}
onClickErrorIcon() {
if (this.shouldToastError && this.firstError) {
this.showErrorToast = true
}
this.$emit('on-click-error-icon', this.firstError)
}
複製程式碼
分析了上面的程式碼,為什麼執行了reset方法後,校驗報錯還是在,原因是valid依然還是false,導致showWarn返回值是ture,而reset中方法中明明將valid設定為true了,為什麼最後結果為false。
watch:{
currentValue(newVal, oldVal) {
if (newVal && this.equalWith) {
if (newVal.length === this.equalWith.length) {
this.hasLengthEqual = true
}
this.validateEqual()
} else {
this.validate()
}
}
}
複製程式碼
因為監聽了input繫結currentValue的值,當reset方法執行的時候this.currentValue = ' ' 觸發了變動執行validate方法,導致再次給this.valid賦值false。
該如何解決這個問題,問題發生的原因是currentValue發生變化導致觸發validate方法校驗,所以我們只要當執行reset方法後不觸發currentValue改變就可以不觸發validate方法校驗
方法一:
onSubmitClick() {
this.$refs.group.$children.forEach(child => {
// 這次reset是將currentValue全部置為""
child.reset()
})
this.$nextTick(() => {
// 當所以input的值都置為空後在此執行reset方法,這次前後currentValue沒有發生變化不會觸發validate校驗所以valide為true不會導致圖示出現
this.$refs.group.$children.forEach(child => {
child.reset()
})
})
}
複製程式碼
方法二: 其實想做的就是在reset方法執行之前將currentValue置為空
created(){
this.currentValue =
this.value === undefined || this.value === null
? ''
: this.mask ? this.maskValue(this.value) : this.value
},
props:{
value: [String, Number]
},
watch:{
value(val) {
this.currentValue = val
}
}
複製程式碼
可以通過傳入value來改變currentValue的值,將v-model="name"繫結值的方式改為:value="name"
onSubmitClick() {
this.name = ''
this.$nextTick(() => {
this.$refs.group.$children.forEach(child => {
child.reset()
})
})
}
複製程式碼
場景2
當我們點選提交時,如果有校驗選項不符合規則能提示相匹配的警告
data(){
return {
message: '還未填寫資訊'
}
}
複製程式碼
將message提示資訊初始值設定為還未填寫資訊,當我們未進行填寫資訊的時候點選提交顯示。然後使用on-change函式繫結校驗規則,實時更新message對應的提示語,業務邏輯如下:
onValueChange() {
// 多次使用賦值給變數
const children = this.$refs.group.$children
let statusList = []
// 篩選出有值的,作為是否全部未填的判斷依據 如果length小於1則還沒填寫任何內容
statusList = children.filter(item => {
return item.currentValue
})
if (statusList.length < 1) {
this.message = '還未填寫資訊'
return
}
// 找到第一個沒有值的那一項,如果都有則返回undefined
const firstInvalid = children.find(item => {
return !item.valid
})
if (firstInvalid !== undefined) {
this.message = `請填寫正確的${firstInvalid.title}`
}
// 顯示的將是否有效賦值給valid增加程式碼可讀性
this.valid = Boolean(firstInvalid)
}
複製程式碼