如何幹掉知乎的所有DIV

歡迎訂閱React技術揭祕react

這是個無聊的問題嗎

當提出這個問題時,個人第一反應是——我還真是無聊 🤷‍♂️git

轉念一想,em~,好像事情沒有這麼簡單🤔github

若是直接選擇全部div再遍歷刪除的話,div的子孫節點也被刪除了。有什麼辦法能在保留整棵DOM樹層級關係的前提下,只刪除div節點呢?面試

我陷入了沉思。。。。。chrome

知乎是React寫的,React用JSX來表示頁面層次結構,JSX在編譯時會被babel轉換爲React.createElement瀏覽器

在代碼運行時,React獲取的實際上是React.createElement()的返回值。babel

辦法來了!markdown

咱們只須要覆寫一下React.createElement方法,當遇到type === 'div',咱們將type修改成React.Fragment,即咱們把全部div節點都變成Fragment,那不就能在保持樹的層級關係的同時去掉div了?ide

讓咱們開始吧!!函數

如何拿到React對象

這時候遇到了第一個問題:知乎沒把React暴露到全局(廢話,固然不會😠),怎麼獲取React對象呢?

好在當咱們使用React Dev Tools時,Dev Tools會向頁面注入全局變量__REACT_DEVTOOLS_GLOBAL_HOOK__,這個變量會成爲連接ReactDev Tools的橋樑。

其中的renderers屬性指頁面使用的渲染器,在網頁端就是咱們熟悉的React-DOM(在客戶端固然就是React-Native啦)

咱們發現一個方法findFiberByHostInstance

方法名竟然出現了Fiber字樣!!

咱們知道,Fiber是React的最小可調度單元(別問爲何,問就是安利我寫的React技術揭祕

findFiberByHostInstance方法所在文件必定有React相關定義。咱們右鍵跳轉到定義函數的文件,

在文件內搜.createElement

果真讓咱們找到了。打上斷點,刷新頁面試試~

果真進來了,事情愈加有趣了 😊😊😊

看看o.a是什麼,em~~一個對象,內部有ChildrencreateElement。。。。。。

看來這就是React對象了

趕緊把來之不易的React對象保存在全局,順便把React.createElement也保存一份。

如今放開斷點,window.React已經指向知乎首頁內部使用的React啦。

修改React.createElement方法

咱們知道,React.createElement方法第一個參數爲type(別問爲何,問又是一波安利React技術揭祕),咱們再到React文檔中找來React.Fragment的定義。

if (typeof Symbol === 'function' && Symbol.for) {
 const symbolFor = Symbol.for;  REACT_ELEMENT_TYPE = symbolFor('react.element');  REACT_PORTAL_TYPE = symbolFor('react.portal');  REACT_FRAGMENT_TYPE = symbolFor('react.fragment');  REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode');  REACT_PROFILER_TYPE = symbolFor('react.profiler');  REACT_PROVIDER_TYPE = symbolFor('react.provider');  // ... } 複製代碼

接下來,修改全局變量

React.createElement = (type, ...args) => {
 if (type === 'div') {  type = Symbol.for('react.fragment');  }  // originCreateElement纔是正經的React.createElement  return originCreateElement(type, ...args); } 複製代碼

讓咱們康康此時的頁面結構

ok~~~ 滿屏的div套div(嫌棄臉),接着咱們輕輕的點一下關注按鈕,觸發隨便啥組件的setState

接下來,就是見證奇蹟的時刻。。。

除了根節點,其餘div都消失啦,終於恢復了往日的清爽界面(大誤)

總結

經過這篇無聊的文章,咱們認識到:

  1. React每次觸發setState更新,都會從新遍歷整棵Fiber樹。(不然也不會點擊一個按鈕整個頁面的div都消失)
  2. React.createElement的深度應用。
  3. 知乎真是有太多div

PS:若是你用Chrome將被壓縮後的代碼formatted後打上斷點,刷新頁面進入斷點後瀏覽器卡死,不要懷疑,這是Chrome的bug,截止版本 81.0.4044.138(正式版本) (64 位)還未修復,建議使用chrome開發者版本 Chrome Canary

相關文章
相關標籤/搜索