<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我在工作中大量使用Ant Design,它為我省去了很多重複勞動,所以有空的時候,我也會為Ant Design做一些微小的貢獻。
本文詳細描述了我處理一個Ant Design的Bug全過程,文章內容較多但難度並不高,新手同學看完也可以嘗試為Ant Design添磚加瓦!
Ant Design有不少Bug,你可以直接存取它的Issues,挑一個簡單的問題嘗試解決,需要注意的是,並不是所以Issue都是Bug,經過管理員確認過的Bug一般會打上Bug的標記。
這次我處理的問題是#37165。
Fork ant-design倉庫到自己的Github,回到自己的Github,將剛剛Fork的倉庫克隆到本地,然後基於master分支新建一個bugfix分支,接著安裝依賴,啟動專案,然後就可以在開發環境存取Ant Design官網上所有的Demo,方便偵錯。
npm install && npm run start
回到問題#37165,它的表現是:一個DatePicker,一個Input, 使用者用滑鼠選中Input的內容進行復制時經常會滑到DatePicker,會觸發日曆控制元件輸入框的focus事件。
這種操作是比較常見的,問題簡化完了就是:只要在日曆控制元件上觸發mouseUp就會開啟日曆控制元件。
檢視官網Demo發現確實存在這個問題,第一反應是日曆控制元件的輸入框繫結了onMouseUp事件,檢視對應的DatePicker
元件原始碼,定位到檔案ant-design/components/date-picker/generatePicker/generateSinglePicker.tsx
第121~156行
(基於antd@4.23.4版本,不同版本行數可能不同):
import RCPicker from 'rc-picker'; // 中間程式碼省略…… <RCPicker<DateType> ref={innerRef} placeholder={getPlaceholder(mergedPicker, locale, placeholder)} suffixIcon={suffixNode} dropdownAlign={transPlacement2DropdownAlign(direction, placement)} dropdownClassName={popupClassName || dropdownClassName} clearIcon={<CloseCircleFilled />} prevIcon={<span className={`${prefixCls}-prev-icon`} />} nextIcon={<span className={`${prefixCls}-next-icon`} />} superPrevIcon={<span className={`${prefixCls}-super-prev-icon`} />} superNextIcon={<span className={`${prefixCls}-super-next-icon`} />} allowClear transitionName={`${rootPrefixCls}-slide-up`} {...additionalProps} {...restProps} {...additionalOverrideProps} locale={locale!.lang} className={classNames( { [`${prefixCls}-${mergedSize}`]: mergedSize, [`${prefixCls}-borderless`]: !bordered, }, getStatusClassNames( prefixCls as string, getMergedStatus(contextStatus, customStatus), hasFeedback, ), className, )} prefixCls={prefixCls} getPopupContainer={customizeGetPopupContainer || getPopupContainer} generateConfig={generateConfig} components={Components} direction={direction} disabled={mergedDisabled} />
以上原始碼沒有傳入onMouseUp,將解構賦值prop的{...restProps}
註釋掉,檢視本地Demo,問題依然存在,說明restProps
也沒有傳入onMouseUp
。
由於DatePicker
元件是基於RCPicker
封裝的,接下來繼續深入RCPicker
元件,看看onMouseUp
是不是在RCPicker
裡面繫結的。
rc-picker
是react-components
元件庫中的日曆元件,Ant Design大部分元件都是在react-components
基礎上封裝的。
檢視rc-picker原始碼,rc-picker預設匯出的是Picker元件:
import Picker from './Picker'; //... export default Picker;
定位到picker/src/Picker.tsx
,搜尋字串"onMouseUp",發現在日曆控制元件輸入框的父級div繫結了onMouseUp事件,對應的回撥函數在287行(基於rc-picker@2.6.10):
// 輸入框父級元素 L530~L555 <div ref={containerRef} className={classNames(prefixCls, className, { [`${prefixCls}-disabled`]: disabled, [`${prefixCls}-focused`]: focused, [`${prefixCls}-rtl`]: direction === 'rtl', })} style={style} onMouseDown={onMouseDown} // 看這裡 onMouseUp={onInternalMouseUp} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} onContextMenu={onContextMenu} // 順便關注一下這裡,後文會說 onClick={onClick} > <div className={classNames(`${prefixCls}-input`, { [`${prefixCls}-input-placeholder`]: !!hoverValue, })} ref={inputDivRef} > {inputNode} {suffixNode} {clearNode} </div> </div> // onMouseUp回撥 L287~L296 const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (...args) => { if (onMouseUp) { onMouseUp(...args); } // 問題就在這裡 if (inputRef.current) { inputRef.current.focus(); triggerOpen(true); } };
就在函數onInternalMouseUp中,除了觸發onMouseUp,還觸發了輸入框的focus事件!
if (inputRef.current) { inputRef.current.focus(); triggerOpen(true); }
此時,應該弄清楚一件事:當時為什麼要寫這幾行程式碼?
最好的途徑就是看看當時的commit message,為了方便後續偵錯,還是將rc-picker倉庫克隆到本地:先Fork,再新建分支,然後安裝依賴,啟動專案。
PS:VSCode安裝GitLens外掛,即可檢視每一行程式碼的commit記錄。
從這幾行程式碼對應的commit瞭解到,這幾行程式碼是為了解決Ant Design的日曆控制元件點選輸入框右側的icon沒有彈出日曆面板的問題。
知道它的作用了,已經成功了一半!看看要怎麼修復?
到這一步,建議先到對應的Issue下面留言說明正在處理中,避免其他開發者再花時間修復同一個問題。
接著,要解決2個問題:
答案顯而易見了,那就是改成在onClick裡觸發,因為icon節點同樣被輸入框的父級包裹,icon的click事件必然會冒泡到父級,從而觸發父級的onClick。
檢視以上原始碼發現,輸入框的父級已經有一個onClick屬性,只需要將以上的4行程式碼挪到onClick的回撥即可,點選這裡檢視詳細修改。
修改完成,檢視本地Demo,問題已經解決了,勝利在望!
原來的commit寫了對應的單元測試,我們修改了它的實現,同時也需要修改對應的單元測試:
// picker/tests/picker.spec.tsx L620~631 it('Picker should open when click inside', () => { const onClick = jest.fn(); const wrapper = mount(<MomentPicker onClick={onClick} />); const inputElement = wrapper.find('input').instance() as any as HTMLInputElement; inputElement.focus = jest.fn(); wrapper.find('.rc-picker').simulate('click'); expect(inputElement.focus).toHaveBeenCalled(); expect(wrapper.isOpen()).toBeTruthy(); expect(onClick).toHaveBeenCalled(); });
修改完成之後,完整地跑一遍單元測試:
npm run test
確保所有單元測試都通過
Test Suites: 8 passed, 8 total
Tests: 294 passed, 294 total
Snapshots: 11 passed, 11 total
Time: 15.643s
程式碼部分到這裡就算圓滿完成了!
這一步,是本文最簡單的一步了!
提交程式碼,push到遠端倉庫,開啟倉庫頁面,會看到頁面上出現了一個【compare & pull request】的入口,點選即可向Ant Design建立合併請求,輸入修復的Issue連結(這個很重要,到時候Issue頁面會自動關聯你的此次的pull request)和修復思路或理由,方便管理員review。
最後,等待管理員review,沒問題的話管理員會合並分支,然後釋出新版本,程式碼最終會應用到數十萬專案中,Bug修復大功告成!
最後,總結一下,第一次提交PR,建議選擇簡單的Issue,重要的是先將整個流程熟悉一遍,不要一開始就挑戰複雜的問題,如果花了很長時間卻解決不了問題,自信心受挫,可能就不想繼續下去了。
以上就是Ant Design 的Bug修復範例詳解的詳細內容,更多關於Ant Design Bug修復的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45