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样式
/**
* 查询所有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的位置
/**
* 循环设置位置
* @param flexBox
*/
const render = (flexBox) => {
flexBox.forEach(item => {
//说明是flexBox
if (item.isFlex) {
new Flex(item);//设置每个flexBox的位置
} else {
render(item.children)
}
})
Flex类的一些实现细节
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
欢迎吐槽