基于 anujs 和 webpack4 兼容 ie7-8 的配置
该 webpack.config 只考虑了对 ie7 ie8 进行配置。
// 安装依赖
npm i
// 开启 development 模式
npm start
// 开启 production 模式
npm run buildPreview
// 开启 使用 react库的开发模式
npm run react
// 开启 使用 react库的生产模式
npm run reactPreview
// 浏览器访问
http://127.0.0.1:8087/production.html
- 在一个组件渲染完成后,通过 dom 操作改变了其中一部分的内容,然后再对组件进行更新,会导致 ie(ie7,8,9,10,11)报错,chrome 下面渲染结果和 react 不一致
代码如下
import React from 'react';
import ReactDom from 'react-dom';
export default class ChangeDom extends React.PureComponent {
state = {
list: [],
};
componentDidMount() {
console.log('box componentDidMount trigger');
}
renderSpan = () => {
const { list } = this.state;
const last = list[list.length - 1];
document.getElementById(`box${last}`).innerHTML = `update_${last}`;
};
clickHandle = () => {
this.setState(
{
list: [...this.state.list, this.state.list.length],
},
() => {
this.renderSpan();
},
);
};
render() {
const { list } = this.state;
return (
<div style={{ width: 800, border: '1px solid #f00', margin: 20 }}>
<h1>修改已有dom的内容导致ie下面出错</h1>
<button onClick={this.clickHandle}>点击增加数据</button>
{list.map((item, index) => {
return (
<div key={index} id={`list${index}`}>
{item}:<span id={`box${index}`}>0</span>
</div>
);
})}
</div>
);
}
}
- 在一个组件渲染完成后,通过 dom 操作在其中插入了 dom 节点,然后再对组件进行更新,dom 的渲染顺序和 react 的渲染结果不符(chrome,ie 都有)
代码如下
import React from 'react';
import ReactDom from 'react-dom';
export default class InsertDom extends React.PureComponent {
state = {
list: [],
};
componentDidMount() {
console.log('box componentDidMount trigger');
}
renderSpan = () => {
const { list } = this.state;
const last = list[list.length - 1];
const dom = document.createElement('div');
dom.innerHTML = `insert_${last}`;
const div = document.getElementById(`list${last}`);
div.parentElement.insertBefore(dom, div);
};
clickHandle = () => {
this.setState(
{
list: [...this.state.list, this.state.list.length],
},
() => {
this.renderSpan();
},
);
};
render() {
const { list } = this.state;
return (
<div style={{ width: 800, border: '1px solid #f00', margin: 20 }}>
<h1>在列表中插通过dom操作插入数据</h1>
<button onClick={this.clickHandle}>点击增加数据</button>
{list.map((item, index) => {
return (
<div key={index} id={`list${index}`}>
{item}:<span id={`box${index}`}>0</span>
</div>
);
})}
</div>
);
}
}
- 使用 PureComponent 时,组件两次 setState 值不变并且父组件在此之前也进行过 setState,会导致该组件与其相邻的前面组件的 dom 节点位置互换 (chrom 67, ie7, ie8)
该问题出现需要满足如下几个条件:
- 组件使用 PureComponent
- 父组件进行过 setState(改不改变值都可以)
- 子组件 setState,但是值跟上一次相同
- 子组件前面存在相邻的组件
组件代码如下
// innerBox.jsx
import React from 'react';
class InnerBox extends React.PureComponent {
state = {
current: 0,
};
componentDidMount() {
console.log('InnerBox render');
setTimeout(() => {
console.log('current跟上次不一样,一切正常');
this.setState({ current: 1 });
}, 500);
setTimeout(() => {
console.log('current跟上次一样,dom位置互换');
this.setState({ current: 1 });
}, 1000);
setTimeout(() => {
console.log('current跟上次不一样,dom位置复原');
this.setState({ current: 2 });
}, 1500);
setTimeout(() => {
console.log('current跟上次一样,dom位置互换');
this.setState({ current: 2 });
}, 2000);
}
render() {
console.log('inner render trigger');
return (
<div style={{ border: '1px solid #f00', background: '#ffc' }}>
<div style={{ height: 100 }}>内部组件</div>
</div>
);
}
}
export default InnerBox;
// wrapBox
import React from 'react';
import InnerBox from './innerBox';
class WrapBox extends React.PureComponent {
state = {
value: 1,
};
componentDidMount() {
console.log('WrapBox render');
// 此处如果在组件创建以后,再次setState,会导致dom位置错误的现象发生
setTimeout(() => {
console.log('父容器state值改变');
this.setState({
value: 1,
});
}, 700);
}
/**
* 渲染组件
*/
render() {
console.log('wrap render trigger');
return (
<div>
<div style={{ border: '1px solid #0f0', background: '#cff', cursor: 'pointer' }}>标题区域1</div>
<div style={{ border: '1px solid #0f0', background: '#cff', cursor: 'pointer' }}>标题区域2</div>
<InnerBox />
<div style={{ border: '1px solid #0f0', background: '#cff', cursor: 'pointer' }}>标题区域3</div>
</div>
);
}
}
export default WrapBox;
- 在 webpack 的
production
mode 下面,代码执行有错误,(chrome 66,ie7,ie8)
// dist/ReactIE.js 84
function miniCreateClass(ctor, superClass, methods, statics) {
var className = ctor.name || String(ctor).match(/^function\s(\w+)/)[1];
var Ctor = Function("superClass", "ctor", "return function " + className + " (props, context) {\n superClass.apply(this, arguments); \n ctor.apply(this, arguments);\n }")(superClass, ctor);
Ctor.displayName = className;
var fn = inherit(Ctor, superClass);
extend(fn, methods);
if (statics) {
extend(Ctor, statics);
}
return Ctor;
}
- 在使用 ref 的时候,表现和 react 不一致
export default class DifferentParent extends React.PureComponent {
box = React.createRef();
componentDidMount() {
console.log('react 的行为是获取的父元素高度是一致的,anujs是不一致的,', this.box.current.parentElement.offsetHeight);
setTimeout(() => {
console.log('async', this.box.current.parentElement.offsetHeight);
}, 100);
}
render() {
return <div ref={this.box}>box</div>;
}
}
- 组件中包含元素的时候,如果组件被再次 render,在 ie7、ie8 下面报错
export default class SelectBox extends React.PureComponent {
data = [{ name: 'a', text: 'aaaa' }, { name: 'b', text: 'bbbb' }, { name: 'c', text: 'cccc' }];
state = {
current: 0,
};
handlerChange = e => {
console.log(e.currentTarget.value);
const index = e.currentTarget.value;
this.setState({
current: index,
});
};
handlerClick = e => {
console.log(e.currentTarget);
const index = e.currentTarget.getAttribute('value');
this.setState({
current: index,
});
};
render() {
const data = this.data;
const { current } = this.state;
return (
<div>
<div>
{data.map((item, index) => (
<span
key={index}
style={{
display: 'inline-block',
padding: 5,
border: '1px solid #f00',
margin: 5,
cursor: 'pointer',
}}
value={index}
onClick={this.handlerClick}>
{item.name}
</span>
))}
</div>
<select>
<option value="0">a</option>
<option value="1">b</option>
<option value="2">c</option>
</select>
<div>{data[current].text}</div>
</div>
);
}
}
SCRIPT87: 参数无效。报错代码如下
function insertElement(fiber) {
var dom = fiber.stateNode,
parent = fiber.parent;
try {
var insertPoint = fiber.forwardFiber ? fiber.forwardFiber.stateNode : null;
var after = insertPoint ? insertPoint.nextSibling : parent.firstChild;
if (after == dom) {
return;
}
if (after === null && dom === parent.lastChild) {
return;
}
Renderer.inserting = fiber.tag === 5 && document.activeElement;
parent.insertBefore(dom, after);
Renderer.inserting = null;
} catch (e) {
throw e;
}
}
执行到
parent.insertBefore(dom, after); 出错,出错时
parent 为 DispHTMLOptionElement
dom 为 DispHTMLDOMTextNode
after 为 DispHTMLDOMTextNode