如何干掉知乎的所有DIV

这是个无聊的问题吗

当提出这个问题时,个人第一反应是——我还真是无聊 🤷‍♂️react

转念一想,em~,好像事情没有这么简单🤔git

若是直接选择全部div再遍历删除的话,div的子孙节点也被删除了。有什么办法能在保留整棵DOM树层级关系的前提下,只删除div节点呢?github

我陷入了沉思。。。。。web

知乎是React写的,React用JSX来表示页面层次结构,JSX在编译时会被babel转换为React.createElement面试

在代码运行时,React获取的实际上是React.createElement()的返回值。chrome

办法来了!浏览器

咱们只须要覆写一下React.createElement方法,当遇到type === 'div',咱们将type修改成React.Fragment,即咱们把全部div节点都变成Fragment,那不就能在保持树的层级关系的同时去掉div了?babel

让咱们开始吧!!编辑器

如何拿到React对象

这时候遇到了第一个问题:知乎没把React暴露到全局(废话,固然不会😠),怎么获取React对象呢? ide

好在当咱们使用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

相关文章
相关标签/搜索