easyui根据select下拉框内容更新表单内容_Ant Design 4.0 的一些杂事儿 - Select 篇
前幾篇:
- Ant Design 4.0 的一些雜事兒 - Table 篇
- Ant Design 4.0 的一些雜事兒 - Form 篇
聊完了 Table 和 Form 兩個重型組件,我們來繼續(xù)聊聊看起來不那么重的 Select 組件。它在 Ant Design 4.0 中有哪些變化。如果你讀過 《Ant Design 4.0 進行時》,那你應該已經(jīng)有了大概的印象。當然,即便沒有讀過也不用擔心。之后會為你細細道來 Select 背后的一些故事~
“滾滾的車輪”
如果你關注過底層實現(xiàn),你會發(fā)現(xiàn) rc-select 和 rc-tree-select 在選擇框部分有大量相似而又有一點點不同的地方。這有一段有趣的歷史,當年先有的 Select 組件之后結合了 Tree 做了一個 TreeSelect 組件。由于這兩個組件有少部分代碼相同,所以 TreeSelect 復制了一部分 Select 的代碼,繼續(xù)開發(fā)。但是隨著時間推移,兩者自分裂之日起,來自社區(qū)的 issue 以及人類的忘性。兩者新增的一些 API 開始出現(xiàn)了矛盾。
一個典型例子就是 inputValue 和 searchValue 之爭:
最早,Select 和 TreeSelect 對于搜索框內(nèi)的文字都不支持受控模式。之后社區(qū)提了 issue 希望對其進行控制,于是乎 rc-select 就多了一個 inputValue 。
然后又過了一段時間,社區(qū)同學提出 TreeSelect 的搜索框內(nèi)容在選擇一個值后會被清空。這在單選沒有問題,但是如果是多選的話,就會遇到需要重復輸入搜索內(nèi)容的情況。嗯嗯,這的確不好。于是我們就在 3.7.0 版本中添加了 autoClearSearchValue。
那么,既然 TreeSelect 有了。Select 也應該有啊。于是在 3.10.0 里我們給 Select 也添加了 autoClearSearchValue 。
你們發(fā)現(xiàn)問題了嗎?rc-select 把搜索框的值叫做 inputValue 但是自動清除卻叫做 autoClearSearchValue。因為兩個 API 各自發(fā)展最后又合到了一塊兒。
于是,我們在之后的版本進行了調(diào)整,統(tǒng)一使用 searchValue ,而遺留的 inputValue 在之后的版本會收到 warning 信息。
樣式誰為先?
如果你是一個設計師,你會發(fā)現(xiàn) v3 版本的 Select 和 TreeSelect 在單選開啟搜索的時候樣子有點不太一樣:
TreeSelect 搜索框在下面Select 搜索框在同級于是我就去做了一下考古。發(fā)現(xiàn)在 0.12.x 版本中,Select 的輸入框是在彈窗內(nèi)部的:
而在之后 1.x 版本中,Select 改成了現(xiàn)在的設計,但是 TreeSelect 卻沒有更新。 于是乎,TreeSelect 隨著 0.12.x 的尾巴一直保留了這個設計。
我們在 issue 中對此有所討論。從 v3 的設計角度來說,下拉框內(nèi)包含搜索框更容易讓用戶明白這個輸入框是用于搜索而非當前的值。但是在 v4 中,我們經(jīng)過討論認為 Select 作為一個更加常用的組件。用戶已經(jīng)培養(yǎng)了使用習慣,搜索框位置已經(jīng)不再是一個會讓人糾結的問題。所以新版設計中,改為 TreeSelect 的搜索框移出于 Select 保持一致。
多米諾骨牌
Select 底層的 rc-select 有著非常古老的歷史,追溯到第一次提交是 2015 年 1 月。 當年,React 還是 0.12.x 的版本。大家對生命周期的理解也不像現(xiàn)在擁有大量文章進行介紹。所以一些陳年代碼片段因為一直運行良好就保留至今,其中一個困擾大家很久的是一段不知道為什么直接設置 state 的代碼。 @Mack 在編寫測試的時候,看到它毅然決然寫下了一個注釋:
對啊,為啥不用 `setState`?@陳帥等13w人 在重構成 Typescript 的時候,看到它,毅然決然的改成了 setState:
事后,我們獲得了一個 bug:
https://github.com/ant-design/ant-design/issues/14262于是, @陳帥等13w人 默默進行了回滾并添加了額外的 comment:
當然,我們在重寫代碼的時候已經(jīng)拋開了這些歷史包袱。在 v4 版本中,Select 沒有這些直接操作 state or DOM or style 的臟代碼。轉(zhuǎn)而使用純粹的生命周期來進行管理,以準備迎接未來的 concurrent 模式。
誰先誰后
在日常維護生活中,我們還收到過一個 issue:
https://github.com/ant-design/ant-design/issues/17630第一反應估計大家都是 onChange 然后清空一下 value,但是正如我們上面所說的。AutoComplete 實際上是一個輸入框。所以用戶輸入的時候是會觸發(fā) onChange 的,所以在 AutoComplete 中如果要觸發(fā)選擇應該使用 onSelect 事件。 但是,我們的順序是先 onSelect 后 onChange 。這導致,如果用戶用 onSelect 清空了值,又會被 onChange 給賦值回來。于是,我們做了調(diào)整,onChange 變成了最先觸發(fā)的。小伙伴本終于可以輕松的通過其他事件來修改 value 啦~
原生的不香嗎?
原生的 select 組件簡單好用。不過如果你想要實現(xiàn)一些額外的效果,它卻又不盡如人意。我們暫時不提 Option 不能接受 ReactNode 這類問題。先來一個簡單的例子,如果你為原生的 select 設置一個空值,你會期望頁面中是一個空選項:
<select value=""><option>one</option> </select>而實際上卻是:
更麻煩的是,原生的 select 由于會默認設置一個值到選項里。所以如果你的 select 只有一個 option 時,你就無法觸發(fā) onChange 了。
為此,大部分使用原生 select 組件為了保留空值不得不提供一個補位:
此外,如果你的 select 需要多選,select 會從一行變成多行展示。其對應的 onChange 事件獲得的 value 也不是你所預期的。
為此,幾乎每一個組件庫總是會著手解決 Select 組件的問題。 將其進行提煉、抽象變得簡單、好看且“好用”。
value 的同步問題
在我們的日常維護中,一個關于 value 的常見提問就是:“為什么 value 不在 options 中卻可以展示。這是一個 bug!”
的確,它的行為和原生的 select 不太一樣,但是這其實是有意為之。從交互角度看,如果你給一個組件賦值。那么無論是用戶還是開發(fā)者,都會存在一個預期。即:
- 用戶:我看到了 Select 的值為 a,我不需要打開這個 Select 看一圈 options ,我也知道它的值是 a。
- 開發(fā)者:我為這個 Select 設置了值為 a,那么我應該對我賦的值負責。組件不應該在我的預期外修改這個值。
這是一個很有趣的問題,試想一下有個 Select ,它的 options 是異步加載的。那么在其 value 加載完成且 options 還沒有準備好的時候。你預期 Select 的值應該是什么?很顯然,如果是沒有值,那么受控的 value 就和展示的值不同步了。更有甚者,如果你的 options 是依賴于另一個控件來動態(tài)加載。那么你的 Select 值就會反復處于 value => null => value 的狀態(tài)。對于用戶而言,它處于即是有值又是無值的狀態(tài)。 即便我并不是想設置這個 Select,我只是打開這個頁面看看配置而已。
所以,無論 options 是什么狀態(tài)。Select 的展示值與其內(nèi)部值都應該跟隨 value 受控。
combobox 是不是一個 Select?
在 v3 初期,我們的 Select 提供了一個 combobox 模式,你可以理解為現(xiàn)在的 AutoComplete 組件。combobox 模式下,Select 相當于一個 Input 組件,只是它提供了一個自動完成的下拉選項卡,其輸入框內(nèi)的值就是 value。
但是,這也正是讓人困擾的地方。開發(fā)者很難分清 combobox 模式到底和其他的模式有什么區(qū)別:
于是,我們不得不反復告知 combobox 設計上的區(qū)別:
然后收獲了為此,我們最終決定將 combobox 從 Select 中抽離出來。轉(zhuǎn)成一個新的組件 AutoComplete。它雖然在內(nèi)部與 Select 共享了大量代碼,但是仍然毅然決然的與 Select 分道揚鑣以降低開發(fā)者的理解成本。
雜談:我們推薦你可以看一下今年 SEE Conf 中 @林外 關于 《Ant Design 4.0:創(chuàng)造快樂工作》的演講。Ant Design 對于組件設計會保持克制,因而我們會從設計與實現(xiàn)的角度共同去探索一個組件所代表的意義。也正是于此,AutoComplete 應該與 Select 進行拆分以達到開發(fā)者更好的開發(fā)體驗。減少困擾就是減少工作量,減少工作量就是早點下班~
選擇生成器
上面我們已經(jīng)描述過了 TreeSelect 和 Select 在選擇框部分非常相似,而 API 更是幾乎 70% 都相同。在解決了布局樣式統(tǒng)一的問題后,我們終于可以將這一部分進行提煉。
在新版的 rc-select 中,我們抽取了一個 generate 方法。它主要接收一個 OptionList 的自定義組件用于渲染下拉框部分。這樣我們就可以直接復用選擇框部分的代碼,而自定義 Select 和 TreeSelect 對應的列表或者樹形結構了。
鍵盤的小把戲
為了讓 Selct 更貼近原生組件,我們需要考慮到一些鍵盤交互的問題。它應該有且唯一有一個能獲取焦點的元素來進行交互處理,否則就會遇到 Tab 到 Select 時需要多次 Tab 才能切換到下一個組件的問題。也會遇到 v3 時期,DatePicker 中 onFocus 和 onBlur 多次觸發(fā)的問題:
因而在設計之初,我們給 Select 預留了一個全組件唯一的焦點入口 input。這個 input 在設置 showSearch 的時候,是那個搜索框;在未設置的時候,是一個 opacity: 0 的幽靈元素;在禁用時,它只需要一個 disabled 就可以略過鍵盤交互。 從而我們將一些組合的鍵盤操作簡化為了對 input 的操作,我們不再需要面對多個焦點組件之間進行焦點的切換。
v3 中打開面板按 ESC 會導致焦點無法還原的問題此外,我們還對鍵盤交互進行了一些細節(jié)調(diào)整。
比如在 v3 版本中,通過 tab 選中 Select 后必須通過 Space 或 Enter 打開下拉框才能進行輸入過濾。在 v4 版本中,利用 input 總是存在的特性。獲取焦點的 Select 可以直接輸入觸發(fā)過濾,減少了用戶額外的操作步驟。
又如 v3 中,多選模式下長按刪除鍵會出現(xiàn)把已經(jīng)選中的值誤刪的情況。在新版中,我們?yōu)榇颂砑恿艘粋€額外的狀態(tài)來確定你是否正在輸入。如果是輸入狀態(tài),刪除至最左時不會觸發(fā)刪除選中值的操作。當停止輸入一段時間后,釋放該狀態(tài)以允許用戶刪除:
v3 的手抖誤刪v4 的輸入檢測防止誤刪同樣的,我們將這套規(guī)則也應用于 Tree 組件上。v4 版本的 Tree 也擁有一個隱藏且唯一的焦點組件用于處理鍵盤交互。更 Cool 的是,由于這個焦點組件是無法被鼠標點擊的。從而我們可以精確的知道,其交互是來自于用戶點擊還是鍵盤聚焦:
Tree 擁有鍵盤 only 的交互樣式看到這里,你或許會想到一個問題。既然下拉內(nèi)容是自定義的,那么如何確定自定義內(nèi)容支持哪些操作呢?其中的奧秘在于,我們規(guī)定的 OptionList 需要提供一個鍵盤交互接口。在上層 Select 消費完畢后仍有未處理的鍵盤事件則會通過該接口傳遞給 OptionList。也因此,我們可以完全復用 rc-tree 組件自身已經(jīng)完成的鍵盤交互。
差不多了~
是的,又到了結尾的時候。這次文章本來還想寫一寫 Tree 更多的故事,不過只是作為一部分的話又略為可惜。其中 Ant Design 支持動畫的虛擬滾動技術可以額外寫一篇大文章,讓大家理解我們?yōu)榱艘恍┙换ゼ毠?jié)額外做了什么事情。而它和 Tree 也非常有關系。所以,這里就不做重復功。下次有機會我們再細聊吧。
PS:雖然這里不提虛擬滾動。但是 Select 也已經(jīng)接入了虛擬滾動,你可以通過這個例子體驗一下 v3 與 v4 版本的性能差異。
總結
以上是生活随笔為你收集整理的easyui根据select下拉框内容更新表单内容_Ant Design 4.0 的一些杂事儿 - Select 篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python大神交流网站_学习Pytho
- 下一篇: 图像sobel梯度详细计算过程_数字图像