者:卡颂
转发链接:https://mp.weixin.qq.com/s/ICjOlJL-fUGRb2S_xqBT7Q
是个无聊的问题吗当提出这个问题时,我的第一反应是——我还真是无聊 ?♂?
转念一想,em~,好像事情没有这么简单如果直接选择所有div再遍历删除的话,div的子孙节点也被删除了。有什么办法能在保留整棵DOM树层级关系的前提下,只删除div节点呢?我陷入了沉思。。。。。
知乎是React写的,React用JSX来表示页面层次结构,JSX在编译时会被babel转换为React.createElement。在代码运行时,React获取的其实是React.createElement()的返回值。办法来了!
我们只需要覆写一下React.createElement方法,当遇到type==='div',我们将type修改为React.Fragment,即我们把所有div节点都变成Fragment,那不就能在保持树的层级关系的同时去掉div了?让我们开始吧!!如何拿到React对象这时候遇到了第一个问题:知乎没把React暴露到全局(废话,当然不会 ),怎么获取React对象呢?
好在当我们使用React Dev Tools时,Dev Tools会向页面注入全局变量__REACT_DEVTOOLS_GLOBAL_HOOK__,这个变量会成为链接React与Dev Tools的桥梁。
其中的renderers属性指页面使用的渲染器,在网页端就是我们熟悉的React-DOM(在客户端当然就是React-Native啦)我们发现一个方法findFiberByHostInstance
方法名居然出现了Fiber字样!!
我们知道,Fiber是React的最小可调度单元(别问为什么,问就是安利我写的React源码揭秘系列)那findFiberByHostInstance方法所在文件一定有React相关定义。我们右键跳转到定义函数的文件,
在文件内搜.createElement
果然让我们找到了。打上断点,刷新页面试试~
果然进来了,事情越发有趣了看看o.a是什么,em~~一个对象,内部有Children、createElement。。。。。。看来这就是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都消失了,终于恢复了往日的清爽界面(大误)
总结通过这篇无聊的文章,我们认识到:
PS:如果你用Chrome将被压缩后的代码formatted后打上断点,刷新页面进入断点后浏览器卡死,不要怀疑,这是Chrome的bug,截止版本 81.0.4044.138(正式版本) (64 位)还未修复,建议使用chrome开发者版本 Chrome Canary
作者姓名:卡颂
转发链接:https://juejin.im/post/5ecb2af0
首先我们通过一张图来解释下元素浮动是什么样的状态。
元素浮动情况
上图的html部分代码为:
html代码
css部分代码为:
css代码
通过上面的图片可以看出,当内部的div设置float后,外部的元素的就会受到以下影响:
背景不能显示
边框不能被撑开
margin和padding设置的值不能正确显示
如果不清除元素浮动的话,浮动层后面的非浮动层内容就有可能被覆盖,造成页面的排版混乱。
例如在上面的例子中再加一个非浮动的div,就会发现该div被前面的三个浮动div覆盖住。
因为浮动,后面的div被覆盖
既然会出现这种情况,我们就应该设法清除掉元素的浮动。
我们可以给父级元素.outer设置为定高,这样就可以不影响后面的非浮动元素。.outer的样式为:
设置定高
达到的效果为
清楚浮动之后
虽然这种方法可以清楚浮动,但是对父元素设置定高会有很多的限制,如果内层div的高度变化,则需要手动修改外层div的高度,相对来说有点麻烦,因此这种方法并不推荐。
在父元素内部的末尾处添加一个新的div,并设置其clear: both;属性。
添加一个新的div
该新增div的css属性为:
新增div的css属性
利用该方法同样可以达到清楚浮动的效果,但是由于会新增DOM元素,这种方法也不推荐。
在父级元素上使用overflow:hidden属性,准确来说只要不给overflow属性设置为visible都可以清除元素浮动。
设置overflow: hidden
使用这种方法可以少写很多css样式代码,同时不会新增DOM元素,因此推荐使用这种方式。
通过对父元素使用:after伪元素,同样可以达到清除浮动的效果。
伪元素清楚浮动
以上方法在伪元素中,通过设置clear与overflow属性来实现。方法4在实际的项目中使用的频率最高,因此极大的推荐使用方法4来清除元素浮动。
看到网上有的资料介绍,通过设置父元素为浮动,或者设置父元素为absolute定位,这两种方法只是能显示父元素而已,但父元素同样会覆盖到后面的非浮动元素,因此这两种方法严格意义来说并不算清除浮动的方法。
今天这篇文章主要介绍了几种通过CSS来清除元素浮动的方法,你掌握了吗?
*请认真填写需求信息,我们会在24小时内与您取得联系。