
Vincent van Gogh – Self-Portrait
因為手撸CSS的時間長了,是以在使用Element時會出現一些因為習慣而導緻的錯誤。其中最大的遺留習慣就是寫完樣式之後加一個分号。
起因是最近的一個項目,用到了Vue,元件選的是Element,在用el-form或el-form-item元件時設定的标簽寬度總是不生效,然後一檢查發現是
元件屬性label-width設定時多寫了一個分号。正确的是(label-width寫在el-form上和el-form-item上都可以):
<el-form>
<el-form-item label="姓名:" label-width="100px">
<el-input placeholder="請輸入姓名"></el-input>
</el-form-item>
</el-form>
錯誤的是:
<el-form>
<el-form-item label="姓名:" label-width="100px;">
<el-input placeholder="請輸入姓名"></el-input>
</el-form-item>
</el-form>
這就是典型的CSS寫多的後果,敲分号跟敲回車似的順手。這個習慣還不容易糾正,是以,發現标簽寬度不生效時不時就出現,次數多了,就毛了,于是一沖動去改源碼了。
在沒有看源碼之前,我們可以大概猜測一下Element對于label-width設定的原理:我們設定這個屬性并傳值,元件檢查到這個屬性有值之後,就把這個寬度設定給标簽。好吧,其實這段話跟廢話一樣,傳的這個值最終肯定是設定給了标簽啊,不然還能幹嘛。是以重點是看源碼是怎麼實作的。
Github上有源碼,下載下傳之後搜尋el-form可以找到相關的元件,檔案名字叫form-item.vue,按照Vue的設定,駝峰寫法的prop屬性對應着短橫線分隔的prop名,那麼反過來,我們知道了label-width的prop名,找屬性,肯定就是labelWidth了,果然,有。
props: {
labelWidth: String,
}
那麼這個屬性的值是怎麼擷取的呢?肯定不是簡單地取個值,裡面涉及到一些判斷,尤其是父節點的判斷。主要思路就是
先檢查一下el-form-item的label-width屬性,如果有就拿這個值,如果沒有就看它爸(el-form)有沒有label-width,它爸有就用它爸的這個屬性值,最後把這個屬性值指派給width屬性,組成一個JS對象傳回,看這個方法名字,就知道這個對象是一個包含樣式(Style)的對象。
labelStyle() {
const ret = {};
...
const labelWidth = this.labelWidth || this.form.labelWidth;
if (labelWidth) {
ret.width = labelWidth;
}
return ret;
}
那麼,很自然的,這個組成的樣式對象肯定要加在标簽上了吧,是的。下面這個源碼說明了它是通過動态綁定樣式的方式給對應的标簽設定了樣式。
<label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
<slot name="label">{{label + form.labelSuffix}}</slot>
</label>
到這裡,就水落石出了,動态綁定樣式的值是一個JS對象,JS對象裡面的key就是width,value就是我們傳的值,如果我們傳"100px"那麼一切安好,如果我們傳"100px;"那這個value值就是錯的,因為它不是一步到位拼接成一個"width:100px;",而是先變成一個JS對象然後再動态綁定做處理。
知道原因了,那優化就簡單了。我們在上面擷取值的步驟做個處理就好了。比如這樣:
labelStyle() {
...
if (labelWidth) {
ret.width = labelWidth.substring(0,labelWidth.length - 1);
}
return ret;
}
看這個項目的package.json可以知道用
npm run dist進行編譯。我們可以使用的檔案在
/lib/index.js中。引用之後,發現,哎,我們寫成"100px;"有效了,但标簽和表單怎麼依然不在一行呢。
原來,表單的樣式設定了"relative",并且它本來應該有一個"margin-left",這個"margin-left"的值就是标簽對應的"width"值,是以,
在擷取"label-width"值的時候,還有一個設定表單"margin-left"的地方。好吧,繼續找,仍然在同一個檔案中,有下面這個方法,設定了一個内容樣式,并且把這個内容樣式加在了表單上。我們仍然是把設定"margin-left"的地方修改一下即可。
contentStyle() {
const ret = {};
if (labelWidth === 'auto') {
...
} else {
// ret.marginLeft = labelWidth;
ret.marginLeft = labelWidth.substring(0,labelWidth.length - 1);
}
return ret;
}
這下子就可以了。
但是,
如果我一個項目裡隻是偶爾會手賤不小心加了分号,大部分時候都遵紀守法,操作就是這麼騷,怎麼辦?那就在需要修改的上面兩處判斷一下再修改即可:
if(labelWidth.substring(labelWidth.length - 1) == ";"){
ret.width = labelWidth.substring(0,labelWidth.length - 1);
}else{
ret.width = labelWidth;
}
以及:
if(labelWidth.substring(labelWidth.length - 1) == ";"){
ret.marginLeft = labelWidth.substring(0,labelWidth.length - 1);
}else{
ret.marginLeft = labelWidth;
}
編譯,引用。至此,随便加不加分号,都OK了。
要不要用在項目裡?呵呵哒,還是慢慢改習慣吧。
再見。