DOM DOM
如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。
安装方法
- 在命令行中执行以下命令
npm install @icedesign/base@latest -S
使用指南
DOM
何时使用
提供静态方法对 DOM 元素进行样式、事件、定位等类型的处理。
代码示例
目标元素相对基准元素的基本定位。
查看源码在线预览
import { dom } from "@icedesign/base";
const { position } = dom;
class App extends React.Component {
state = {
pinElementAlign: "tl",
baseElementAlign: "tl"
};
render() {
return (
<div className="basic-demo">
<div className="cell">
<div id="b1" className="elem2">
基准元素 b1
</div>
<div id="a1" className="elem1">
目标元素 a1
</div>
</div>
<div>
<h3>pinElement(目标元素 a1)</h3>
{this.renderRadio("pin")}
</div>
<div>
<h3>baseElement(基准元素 b1)</h3>
{this.renderRadio("base")}
</div>
</div>
);
}
componentDidMount() {
position.place(
document.getElementById("a1"),
document.getElementById("b1"),
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
componentDidUpdate() {
position.place(
document.getElementById("a1"),
document.getElementById("b1"),
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
onPinElementAlignChange(e) {
const value = e.target.value;
this.setState({
pinElementAlign: value
});
}
onBaseElementAlignChange(e) {
const value = e.target.value;
this.setState({
baseElementAlign: value
});
}
renderRadio(type) {
const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
return (
<label key={value}>
<input
type="radio"
value={value}
onChange={onChange}
checked={value == this.state[`${type}ElementAlign`]}
/>{" "}
{value}{" "}
</label>
);
});
}
}
ReactDOM.render(<App />, mountNode);
.basic-demo .elem1 {
z-index: 99;
background-color: #7FBF4D;
background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
background-image: linear-gradient(top, #7FBF4D, #63A62F);
border: 1px solid #63A62F;
border-bottom: 1px solid #5B992B;
box-shadow: inset 0 1px 0 0 #96CA6D;
color: white;
padding: 7px 3px 8px;
text-align: center;
text-shadow: 0 -1px 0 #4C9021;
opacity: 0.8;
width: 100px;
}
.basic-demo .elem2 {
box-sizing: border-box;
border: 20px solid #999;
background-color: #eee;
width: 340px;
height: 240px;
margin: 50px 0 0 100px;
line-height: 200px;
text-align: center;
}
查看源码在线预览
import { dom } from "@icedesign/base";
const { events } = dom;
const { on, off } = events;
class App extends React.Component {
componentDidMount() {
const { btn, inner, outter, link, btnOnce, btnOrder, btnOff } = this.refs;
on(btn, "click", function(e) {
console.log(this, e.target, e.currentTarget);
});
on(inner, "click", function(e) {
alert("Stop propagation!");
e.stopPropagation();
});
on(outter, "click", function() {
alert("Stop propagation failed!");
});
on(link, "click", function(e) {
alert("Prevent default!");
e.preventDefault();
});
const onceHandler = function() {
alert("trigger");
};
on(btnOnce, "click", onceHandler);
on(btnOnce, "click", onceHandler);
on(btnOrder, "click", function() {
alert("1");
});
on(btnOrder, "click", function() {
alert("2");
});
const removeHandler = function() {
alert("Remove event listener failed!");
};
on(btnOff, "click", removeHandler).off();
}
render() {
return (
<div className="events-demo">
<h2>Add event listener</h2>
<button ref="btn">Click me!</button>
<h2>Stop propagation</h2>
<div ref="outter" className="outter">
Click me!
<div ref="inner" className="inner">
Click me!
</div>
</div>
<h2>Prevent default</h2>
<a ref="link" href="http://www.taobao.com">
Taobao
</a>
<h2>Same handler trigger once</h2>
<button ref="btnOnce">Click me!</button>
<h2>Triggering order follows the registration order</h2>
<button ref="btnOrder">Click me!</button>
<h2>Remove event listener</h2>
<button ref="btnOff">Click me!</button>
</div>
);
}
}
ReactDOM.render(<App />, mountNode);
.events-demo .outter {
box-sizing: border-box;
color: #fff;
width: 200px;
height: 200px;
line-height: 50px;
padding: 0 50px 50px;
background: #999;
text-align: center;
}
.events-demo .inner {
color: #333;
width: 100px;
height: 100px;
line-height: 100px;
background: #eee;
text-align: center;
}
目标元素为 fixed 时的定位。
查看源码在线预览
import { dom } from "@icedesign/base";
const { position } = dom;
class App extends React.Component {
state = {
pinElementAlign: "tl",
baseElementAlign: "tl"
};
render() {
return (
<div className="fixed-demo">
<div id="a4" className="elem1">
目标元素 a4
</div>
<div>
<h3>pinElement(目标元素 a4)</h3>
{this.renderRadio("pin")}
</div>
<div>
<h3>baseElement(window)</h3>
{this.renderRadio("base")}
</div>
</div>
);
}
componentDidMount() {
position.place(
document.getElementById("a4"),
position.VIEWPORT,
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
componentDidUpdate() {
position.place(
document.getElementById("a4"),
position.VIEWPORT,
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
onPinElementAlignChange(e) {
const value = e.target.value;
this.setState({
pinElementAlign: value
});
}
onBaseElementAlignChange(e) {
const value = e.target.value;
this.setState({
baseElementAlign: value
});
}
renderRadio(type) {
const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
return (
<label key={value}>
<input
type="radio"
value={value}
onChange={onChange}
checked={value == this.state[`${type}ElementAlign`]}
/>{" "}
{value}{" "}
</label>
);
});
}
}
ReactDOM.render(<App />, mountNode);
.fixed-demo .elem1 {
z-index: 99;
background-color: #7FBF4D;
background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
background-image: linear-gradient(top, #7FBF4D, #63A62F);
border: 1px solid #63A62F;
border-bottom: 1px solid #5B992B;
box-shadow: inset 0 1px 0 0 #96CA6D;
color: white;
padding: 7px 3px 8px;
text-align: center;
text-shadow: 0 -1px 0 #4C9021;
opacity: 0.8;
width: 100px;
position: fixed;
}
为不让目标元素超出当前可视区域,可设置 needAdjust 参数为 true ,定位时会自动调整目标元素的定位方向。
查看源码在线预览
import { dom } from "@icedesign/base";
const { position } = dom;
class App extends React.Component {
state = {
pinElementAlign: "tl",
baseElementAlign: "tl"
};
render() {
return (
<div className="adjust-demo">
<div className="cell">
<div className="ele-wrapper">
<div id="a3" className="elem1">
目标元素 a3
</div>
<div id="b3" className="elem2">
基准元素 b3
</div>
</div>
</div>
<div>
<h3>pinElement(目标元素 a3)</h3>
{this.renderRadio("pin")}
</div>
<div>
<h3>baseElement(基准元素 b3)</h3>
{this.renderRadio("base")}
</div>
</div>
);
}
componentDidMount() {
console.log(
position.place(
document.getElementById("a3"),
document.getElementById("b3"),
this.state.pinElementAlign + " " + this.state.baseElementAlign,
[0, 0],
true
)
);
}
componentDidUpdate() {
console.log(
position.place(
document.getElementById("a3"),
document.getElementById("b3"),
this.state.pinElementAlign + " " + this.state.baseElementAlign,
[0, 0],
true
)
);
}
onPinElementAlignChange(e) {
const value = e.target.value;
this.setState({
pinElementAlign: value
});
}
onBaseElementAlignChange(e) {
const value = e.target.value;
this.setState({
baseElementAlign: value
});
}
renderRadio(type) {
const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
return (
<label key={value}>
<input
type="radio"
value={value}
onChange={onChange}
checked={value == this.state[`${type}ElementAlign`]}
/>{" "}
{value}{" "}
</label>
);
});
}
}
ReactDOM.render(<App />, mountNode);
.adjust-demo .elem1 {
z-index: 99;
background-color: #7FBF4D;
background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
background-image: linear-gradient(top, #7FBF4D, #63A62F);
border: 1px solid #63A62F;
border-bottom: 1px solid #5B992B;
box-shadow: inset 0 1px 0 0 #96CA6D;
color: white;
padding: 7px 3px 8px;
text-align: center;
text-shadow: 0 -1px 0 #4C9021;
opacity: 0.8;
width: 100px;
height: 200px;
}
.adjust-demo .elem2 {
border: 1px solid #999;
background-color: #eee;
width: 300px;
height: 30px;
margin: 50px 0 0 100px;
line-height: 200px;
text-align: center;
}
.adjust-demo .ele-wrapper {
position: relative;
margin: 20px 20px 60px;
border: 2px red solid;
padding: 10px;
}
当目标元素的 offsetParent 不为 body 时的定位。
查看源码在线预览
import { dom } from "@icedesign/base";
const { position } = dom;
class App extends React.Component {
state = {
pinElementAlign: "tl",
baseElementAlign: "tl"
};
render() {
return (
<div className="offset-demo">
<div className="cell">
<div className="ele-wrapper">
<div id="a2" className="elem1">
目标元素 a2
</div>
</div>
<div id="b2" className="elem2">
基准元素 b2
</div>
</div>
<div>
<h3>pinElement(目标元素 a2)</h3>
{this.renderRadio("pin")}
</div>
<div>
<h3>baseElement(基准元素 b2)</h3>
{this.renderRadio("base")}
</div>
</div>
);
}
componentDidMount() {
position.place(
document.getElementById("a2"),
document.getElementById("b2"),
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
componentDidUpdate() {
position.place(
document.getElementById("a2"),
document.getElementById("b2"),
this.state.pinElementAlign + " " + this.state.baseElementAlign
);
}
onPinElementAlignChange(e) {
const value = e.target.value;
this.setState({
pinElementAlign: value
});
}
onBaseElementAlignChange(e) {
const value = e.target.value;
this.setState({
baseElementAlign: value
});
}
renderRadio(type) {
const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
return (
<label key={value}>
<input
type="radio"
value={value}
onChange={onChange}
checked={value == this.state[`${type}ElementAlign`]}
/>{" "}
{value}{" "}
</label>
);
});
}
}
ReactDOM.render(<App />, mountNode);
.offset-demo .elem1 {
z-index: 99;
background-color: #7FBF4D;
background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
background-image: linear-gradient(top, #7FBF4D, #63A62F);
border: 1px solid #63A62F;
border-bottom: 1px solid #5B992B;
box-shadow: inset 0 1px 0 0 #96CA6D;
color: white;
padding: 7px 3px 8px;
text-align: center;
text-shadow: 0 -1px 0 #4C9021;
opacity: 0.8;
width: 100px;
}
.offset-demo .elem2 {
box-sizing: border-box;
border: 20px solid #999;
background-color: #eee;
width: 340px;
height: 240px;
margin: 50px 0 0 100px;
line-height: 200px;
text-align: center;
}
.offset-demo .ele-wrapper {
position: relative;
margin: 20px;
border: 2px red solid;
padding: 20px;
}
目标元素相对 viewport 的定位。
查看源码在线预览
import { dom } from "@icedesign/base";
const { position } = dom;
class App extends React.Component {
state = {
pinElementAlign: "tl",
baseElementAlign: "tl"
};
render() {
return (
<div className="viewport-demo">
<div className="cell">
<div className="ele-wrapper">
<div id="a5" className="elem1">
目标元素 a5
</div>
</div>
</div>
<div>
<h3>pinElement(目标元素 a5)</h3>
{this.renderRadio("pin")}
</div>
<div>
<h3>baseElement(viewport)</h3>
{this.renderRadio("base")}
</div>
</div>
);
}
componentDidMount() {
console.log(
position.place(
document.getElementById("a5"),
position.VIEWPORT,
this.state.pinElementAlign + " " + this.state.baseElementAlign
)
);
}
componentDidUpdate() {
console.log(
position.place(
document.getElementById("a5"),
position.VIEWPORT,
this.state.pinElementAlign + " " + this.state.baseElementAlign
)
);
}
onPinElementAlignChange(e) {
const value = e.target.value;
this.setState({
pinElementAlign: value
});
}
onBaseElementAlignChange(e) {
const value = e.target.value;
this.setState({
baseElementAlign: value
});
}
renderRadio(type) {
const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
return (
<label key={value}>
<input
type="radio"
value={value}
onChange={onChange}
checked={value == this.state[`${type}ElementAlign`]}
/>{" "}
{value}{" "}
</label>
);
});
}
}
ReactDOM.render(<App />, mountNode);
.viewport-demo .elem1 {
z-index: 99;
background-color: #7FBF4D;
background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
background-image: linear-gradient(top, #7FBF4D, #63A62F);
border: 1px solid #63A62F;
border-bottom: 1px solid #5B992B;
box-shadow: inset 0 1px 0 0 #96CA6D;
color: white;
padding: 7px 3px 8px;
text-align: center;
text-shadow: 0 -1px 0 #4C9021;
opacity: 0.8;
width: 100px;
}
.viewport-demo .ele-wrapper {
position: relative;
margin: 20px 20px 60px;
border: 2px red solid;
padding: 20px;
}