學習就比如是座大山,人們沿着不一樣的路爬山,分享着本身看到的風景。你不必定能看到別人看到的風景,體會到別人的心情。只有本身去爬山,才能看到不同的風景,體會更加深入。一千個讀者就有一千個哈姆雷特,可是莎士比亞心中的哈姆雷特確定只有一個。就比如element源碼只有一個,但每一個人看到的都是不同的風景。element源碼解讀是一個系列,每個組件細膩的背後都能看到前端工程師付出的心血,本篇帶來的是Element源碼分析系列4-Radio(單選框)css
單選框這個組件看似簡單,實則知識點衆多,較爲複雜,若是寫一個html的原生單選框,那確實很簡單,可是封裝一個完整的單選組件就不那麼簡單了。element團隊在整個radio組件的設計和構思真可謂十分的細緻,沒有一行多餘的代碼。從基礎的css到選擇邏輯都無不彰顯其巧奪天工的思想。html
咱們都知道原生的radio標籤很醜,樣式在各個瀏覽器不統一,做爲一個組件不可能就這樣屈服,何況人這種物種老是但願統駕馭全部的物質之上,包括代碼。因此必須本身實現全部radio按鈕的樣式,那麼如何本身實現一個可控制的radio標籤呢?看element是怎麼實現的。 前端
看圖不難分析出radio組件的html樣式,整個大盒子被一個laber標籤包裹着,laber裏分爲兩個span,第一個span是用來展現選擇按鈕的,第二個span是來描述選項的。第一個span裏應該包括input(用來作radio)和span(隱藏真正的input)兩個標籤。其相關的html結構以下:<label className='el-radio'>
<span>
<span className="el-radio__inner"></span>
<input
type="radio"
className="el-radio__original"
/>
</span>
<span className="el-radio__label">
{children || value}
</span>
</label>
複製代碼
問題一:如何作到隱藏原始radio標籤默認樣式?做者巧用opacity:0,真正的input透明度爲0,且是絕對定位脫離文檔流,所以不佔空間且咱們看不到,注意不是display:none或者visibility:hidden,若是是none或者hidden的話則沒法觸發鼠標點擊了,因此只有opacity:0才能達到目的.react
.el-radio__original {
opacity: 0;
outline: 0;
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
}
複製代碼
如何作到點擊旋鈕顯示不一樣的狀態。經過radio標籤可分析出,點擊便可以理解爲一個事件(這裏用onChange表示)。經過點擊事件傳遞一個props值(checked)顯示不一樣的狀態。因此在input上必定會有一個事件和一個所要傳遞的狀態。git
<input
type="radio"
className="el-radio__original"
checked={checked} // 傳遞的狀態
onChange={this.onChange.bind(this)} // 事件
/>
複製代碼
那麼接下來就是定義事件了,其核心代碼爲:github
constructor(props) {
super(props);
this.state = {
checked: this.getChecked(props) // 定義一個state,受props影響
};
}
componentWillReceiveProps(props) {
const checked = this.getChecked(props);
if (this.state.checked !== checked) { // 維持每次點擊時只選中一個
this.setState({ checked });
}
}
getChecked(props) {
return Boolean(props.checked) // 根據傳遞的props,輸出true/false
}
onChange(e) {
const checked = e.target.checked; // 定義被點擊項的checked爲true
if (checked) {
if (this.props.onChange) {
this.props.onChange(this.props.value); // 向外暴露一個onChange事件並攜帶value值
}
}
this.setState({ checked }); // 更新被點擊項的state爲true
}
複製代碼
若是你對上述描述的仍是雨裏霧裏,那麼下面這張圖能夠更好的幫組你理解element-radio標籤事件的邏輯: 數組
從圖中咱們能夠看出,radio是如何作到點擊改變狀態,而且又如何維護每次點擊完後radio的狀態。單選框組故名思議是將全部的radio包裹一層,由最外層原始事件來決定每一個radio的狀態。故須要用到React的兩個API:React.Children.map、React.cloneElement瀏覽器
技術擴展:bash
React.Children.map(children, function[(thisArg)])前端工程師
在 children 裏的每一個直接子節點上調用一個函數,並將 this 設置爲 thisArg。若是 children 是一個數組,它將被遍歷併爲數組中的每一個子節點調用該函數。若是子節點爲 null 或是 undefined,則此方法將返回 null 或是 undefined,而不會返回數組。
React.cloneElement(element, [props], [...children])
先了解這兩個API,在來看看element中Radio.Group的源碼就很簡單來。
<div ref='RadioGroup' className='el-radio-group'>
{
React.Children.map(this.props.children, element => {
if (!element) {
return null
}
return React.cloneElement(element, Object.assign({}, element.props, {
onChange: this.onChange.bind(this),
value: this.props.value,
}))
})
}
</div>
複製代碼
經過遍歷全部的radio組件,克隆出相應的radio組件,併爲其附上radio的一些屬性,包括方法和value。
縱觀整個radio的設計和實現,每一個設計的過程都十分的微妙,尤爲是radio如何更新狀態,在平時業務中,咱們也常常會遇到這種需求,可是真正的實現起來卻沒有這麼簡潔。源碼的學習或多或少可讓咱們加強本身的代碼能力和業務能力。那麼跟隨個人腳步,帶你一步一步解析整個element源碼的奇思妙想。山再也不高,有仙則靈;水不在深,有心則成。後續將推出更多源碼解析文章。源碼請👇這裏element-radio源碼