ps:用惯了flex布局 项目要兼容到ie9怎么办
先别急,先看一张flex布局在浏览器兼容性
明显ie9不支持flex 那有没有办法让ie9支持flex呢。我的想法就是去用js控制div的位置
如何去控制每个div的位置呢
1、使用子绝父相 (子类用absolute 父类用relative)
优点: IE6+都支持
缺点:可是这样会打乱原有的布局、需要让每个子类去累加父类的相对位移、计算工作量大、几乎要去对每个element 计算
2、使用transform 的translate属性
好的地方:相对原有位置移动、一般transform属性用的也比较少、不影响布局、
缺点:只支持ie9+
权衡利弊后、一般现在都最低支持ie9、所以决定用方案2
好了现在控制位置的方案定下来了、可是在ie9中如何去读取不支持的display:flex呢
如果去读取element.currentstyle['display'] 得到值是block
好消息是在ie中可以读取浏览器不认识的自定义属性 所以如果这么写是支持的即 -js-display:flex;
通过使用element.currentstyle['-js-display']就可读取到这个flex属性那么我们约定每次在写样式时都加上-js-display
当然也可以通过工具自动去加上这个兼容的写法
我们把实现思路写个伪代码
//读取dom中所有是flex的div样式
//根据每个flex样式去设置该div的位置
读取dom中所有是flex的div样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /** * 查询所有flexbox */ export default function readAll(element) { // whether the element has a display flex style let isDisplayFlex = isFlexBox(element); let _ele = { element, classList:[], style:'', offsetLeft:0, offsetTop:0, computedStyle: {}, tag: element.localName, children: [] }; // children of the element let index = -1; let childNode; if (isDisplayFlex) { element instanceof Element&&resetStyle(element); let alignSelf = 'stretch'; if (isFlexBox(element.parentNode)) { const _props = getStyle(element.parentNode); alignSelf = _props['align-items'] || getDefaultProp('alignItems') } const props = getStyle(element); _ele = { element, isFlex:true, isNativeInline:judgeIsNativeInline(element), tag: element.localName, classList: getClassList(element), style:element.getAttribute('style')||'', offsetLeft:getOffset(element).left, offsetTop:getOffset(element).top, computedStyle:props, children: [], props: { flexDirection:getDefaultStyle(props,'flex-direction','flexDirection')|| getDefaultProp('flexDirection', props) || getDefaultProp('flexDirection'), flexWrap: getDefaultStyle(props,'flex-wrap','flexWrap') || getDefaultProp('flexWrap', props) || getDefaultProp('flexWrap'), //默认不换行 alignItems: getDefaultStyle(props,'align-items','alignItems') || getDefaultProp('alignItems'), alignSelf: getDefaultStyle(props,'align-self')|| alignSelf, alignContent: getDefaultStyle(props,'align-content','alignContent') || getDefaultProp('alignContent'), justifyContent:getDefaultStyle(props,'justify-content','justifyContent') || getDefaultProp('justifyContent'), //默认左对齐 order: getDefaultStyle(props,'order','order') || getDefaultProp('order'), flexShrink: getDefaultStyle(props,'flex-shrink','flexShrink')|| getDefaultProp('flexShrink', props) || getDefaultProp('flexShrink'), flexGrow:getDefaultStyle(props,'flex-grow','flexGrow') || getDefaultProp('flexGrow', props) || getDefaultProp('flexGrow') } }; dealInlineFlex(element) } // for each child node of the element while (childNode = element.childNodes[++index]) { // whether the child is an element let isElement = childNode instanceof Element; if (isElement) { // push the child details to children let childDetails = readAll(childNode); if(isDisplayFlex){ element instanceof Element&&resetStyle(element); //如果父类为flex且自己不是flex的时候 if(!isFlexBox(childNode)){ const _style=getStyle(childNode); childDetails.computedStyle=_style; childDetails.style=childNode.getAttribute('style')||''; childDetails.isNativeInline=judgeIsNativeInline(childNode); childDetails.classList=getClassList(childNode); childDetails.offsetLeft=getOffset(childNode).left; childDetails.offsetTop=getOffset(childNode).top; childDetails.props={ alignSelf: getDefaultStyle(_style,'align-self')||_ele.props.alignItems, order: getDefaultStyle(_style,'order','order') || getDefaultProp('order'), flexShrink: getDefaultStyle(_style,'flex-shrink','flexShrink')|| getDefaultProp('flexShrink', _style) || getDefaultProp('flexShrink'), flexGrow:getDefaultStyle(_style,'flex-grow','flexGrow') || getDefaultProp('flexGrow', _style) || getDefaultProp('flexGrow') } } }else{ childDetails.offsetLeft=getOffset(childNode).left; childDetails.offsetTop=getOffset(childNode).top; } _ele.children.push(childDetails); } } return _ele; } |
设置每个flexbox的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 循环设置位置 * @param flexBox */ const render = (flexBox) => { flexBox.forEach(item => { //说明是flexBox if (item.isFlex) { new Flex(item);//设置每个flexBox的位置 } else { render(item.children) } }) |
Flex类的一些实现细节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | const remakePos = _children.map((item,index) => { const obj = item.element.getBoundingClientRect(); const nativeStyle=item.style; const style = item.computedStyle; //console.log(style.width,obj.width) //排除掉fixed等影响布局的 const isFixed = (style.position === 'absolute' || style.position === 'fixed'); if (isFixed) { return { isFixed, props: {}, borderLeftWidth: 0, borderRightWidth: 0, marginLeft: 0, marginRight: 0, width: 0, height: 0, x: 0, y: 0, } } let width =obj.width + parseInt(style.marginLeft) + parseInt(style.marginRight) + (item.isNativeInline?0:(parseInt(style.borderLeftWidth)+parseInt(style.borderRightWidth))) ; let height =obj.height + parseInt(style.marginTop) + parseInt(style.marginBottom) + (item.isNativeInline?0:(parseInt(style.borderTopWidth)+parseInt(style.borderBottomWidth))); let _x= - (item.offsetLeft - parseInt(style.marginLeft) - parseInt(computedStyle.borderLeftWidth)-parseInt(computedStyle.paddingLeft) - left); let _y= - (item.offsetTop - parseInt(style.marginTop) - parseInt(computedStyle.borderLeftWidth) -parseInt(computedStyle.paddingTop)- top); return { element: item.element, computedStyle:item.computedStyle, style:nativeStyle, isNativeInline:item.isNativeInline, isFixed, props: item.props, borderLeftWidth: parseInt(style.borderLeftWidth), borderRightWidth: parseInt(style.borderRightWidth), marginLeft: parseInt(style.marginLeft), marginRight: parseInt(style.marginRight), paddingLeft: parseInt(style.paddingLeft), paddingRight: parseInt(style.paddingRight), height, width, x: _x, y: _y, } }).filter((item) => !item.isFixed); //创建流动布局 const flowBox = this.createFlowBox(remakePos); this.height = this.computedStyle.height ? this.height : flowBox.reduce((al, b) => { if (flexDirection.includes(FLEX_DIRECTION.COLUMN)) { return al + b.lineArrayWidth } else { return al + b.max } }, 0); //console.log('flowbox',flowBox) //开始布局 const array = this.startLayout(flowBox); |
npm地址:https://www.npmjs.com/package/flex-native
githup地址:https://github.com/robertpanvip/flex-native
欢迎吐槽