这是个无聊的问题吗

当提出这个问题时,我的榜首反应是——我还真是无聊 ‍♂️

转念一想,em~,好像工作没有这么简略

假如直接挑选一切div再遍历删去的话,div的子孙节点也被删去了。有什么办法能在保存整棵DOM树层级关系的前提下,只删去div节点呢?

我陷入了深思。。。。。

如何干掉知乎的全部DIV

知乎是React写的,React用D 1 6 3 H ; u a QJSX来表示页面层次结构,JSX在编译时会被babel转换为React.createElement

在代码运行时,React. d f $获取的其实是Read p uct.createElement()的返回值。

办法来了!

如何干掉知乎的全部DIV

咱们只需要覆写一下React.createw Y k 7 A 8 o [ iElement办法,当遇到type === 'div',咱们将type修正为React.Fragment,即咱们把J q A 5 * 1一切div节点都变成Fragment,那不就能在坚持树的层级关系的同时去掉div& a F l E

让咱们开端吧!!

如何拿到React目标

这时候遇到了榜首个问题:知乎没把React暴露到大局(废话,当然不会),怎么获取React目标呢?
如何干掉知乎的全部DIV

好在当咱们运用RZ ^ P zeact Dev Tools时,Dev Tools会向页面注入大局变量__REACT_DEVTO6 4 ] vOLS_GLOBAL_HOOK__,这个变量会成为链接ReactDev Tools的桥梁。

如何干掉知乎的全部DIV

其间的renderers属性指页面运用的渲染器,在网页端便是咱们了解的React-DOM(在客户端当然便是React-Native啦)

J d ? k U们发现一个l + u r V t办法findFiberByHostInstance
如何干掉知乎的全部DIV

办法名竟然出现了Fiber字样!!

如何干掉知乎的全部DIV

咱们知道,Fiber是React的最小可调度单元(别问为什么,问便是安利我写的React源码揭秘系列)

findFiberByHostInstance办法所在文件一定有Rea| H ? % O o | r yct相关界说。咱们右键跳转到界说函数的文件,
如何干掉知乎的全部DIV

在文件内搜.createElemenY | 5 b ^ *t

如何干掉知乎的全部DIV

公然让咱们找到了。打上断点,改写页面试试~

如何干掉知乎的全部DIV

公然进来了,工作越发风趣了

看看o.a是什么,em~~一个目标,内部有ChildrencreateElement。。。。。。

看来这便是React目标了

如何干掉知乎的全部DIV

急忙把来之不易的React目标保存在大局,顺便把React.createElement也保存一份。

如何干掉知乎的全部DIV

现在铺开断点,window.ReacP R ! 9 . ? ht现已指向知乎主页内部运用的React啦。

如何干掉知乎的全部DIV

修正React.createElement办8 } ]

咱们知道j 5 1 R a ;j Y e ( sReact.createElement办法榜首个参数为type(别问为什么,问又是一波安利React源码揭秘系列),咱们再到React文档中找来React.Fragment的界说。

if (typeof Symbol === 'functio7 _ b ( J `n' &&a` 5 X G z 4 P 0 Kmp; Symbol.for) {
  const symbolFor = Symbol.for;
  REACT_ELEMENT_TYQ p G A ^PE = symbolFor(w a , 3 6'reactc y o W o.element');
  REACT_PORTAL_TYPE = symbolFor('react.portal'@ [ H G . $ ] e)s } l P S;
  REACT_+ e q ~ +FRAGMENT_p B 0 { ` oTYPE = symbolFor('react.fragment');
  REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode'k t v U 0 # #);
  REACT_PROFILER_TYPE= U ~ q / U + = symD { 2 1 - 2bolFor('react.pA 9 I 2 e 7rofiler');
  REACT_PROVIDER_TYPK G U O + 2E = symbolFor('react.prof 6 % [ Fvider');
  // ...
}

接下来,修正大局变量

React.createElement = (type, ...F 6 ` 9 A g l &args) => {
    if (type === 'div') {
        type = Symbol.for('react.fragment');
    }E ,  _ I .
    // originj F j / V ` S jCreateElement才是正派的React.createElemeno ` Nt
    return originCreateElement(type, ..u ~ Z ; j & ; a D.args)0 S G;
}

让咱们康康此时的页面结构

如何干掉知乎的全部DIV

ok~~~ 满屏的div套div(厌弃脸),接着咱们轻轻的点一下重视按钮,触发随便啥组件的setState

接下来,便是见证奇迹的时刻。。。

如何干掉知乎的全部DIV

除了根节点,其他div都消失啦,总算恢复了往日的清新界面(大误)

总结

通过这篇无聊的文章,咱们认识到:

  1. React每次触发setState更新,都会从头遍历整棵Fiber树。(否则也不会) f [ n 4 R I E v点击一个按, x C s 7 q I钮整个页面e 0 L Rdiv都消失)
  2. React& O d W h [.createElement的深度使用。
  3. 知乎真是有太多div

PS:假如你用Chrome将被压缩后的代码formatted N | ~ h =打上断点,改写页面进入断点后浏览器卡死o F / x Y o g,不要置疑,这是Chrome的bug,截止版别 81.0.4044.138(正式版别) (64 位)还未修复,主张M N ^ 8 3 J + X 运用cl $ C _ x / N Jhrome开发者版别 Chrome Canary