DOM DOM

如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @icedesign/base@latest -S

使用指南

DOM

何时使用

提供静态方法对 DOM 元素进行样式、事件、定位等类型的处理。

代码示例

基本定位

目标元素相对基准元素的基本定位。

DOM DOM - 图1

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { position } = dom;
  3. class App extends React.Component {
  4. state = {
  5. pinElementAlign: "tl",
  6. baseElementAlign: "tl"
  7. };
  8. render() {
  9. return (
  10. <div className="basic-demo">
  11. <div className="cell">
  12. <div id="b1" className="elem2">
  13. 基准元素 b1
  14. </div>
  15. <div id="a1" className="elem1">
  16. 目标元素 a1
  17. </div>
  18. </div>
  19. <div>
  20. <h3>pinElement(目标元素 a1)</h3>
  21. {this.renderRadio("pin")}
  22. </div>
  23. <div>
  24. <h3>baseElement(基准元素 b1)</h3>
  25. {this.renderRadio("base")}
  26. </div>
  27. </div>
  28. );
  29. }
  30. componentDidMount() {
  31. position.place(
  32. document.getElementById("a1"),
  33. document.getElementById("b1"),
  34. this.state.pinElementAlign + " " + this.state.baseElementAlign
  35. );
  36. }
  37. componentDidUpdate() {
  38. position.place(
  39. document.getElementById("a1"),
  40. document.getElementById("b1"),
  41. this.state.pinElementAlign + " " + this.state.baseElementAlign
  42. );
  43. }
  44. onPinElementAlignChange(e) {
  45. const value = e.target.value;
  46. this.setState({
  47. pinElementAlign: value
  48. });
  49. }
  50. onBaseElementAlignChange(e) {
  51. const value = e.target.value;
  52. this.setState({
  53. baseElementAlign: value
  54. });
  55. }
  56. renderRadio(type) {
  57. const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
  58. const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
  59. return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
  60. return (
  61. <label key={value}>
  62. <input
  63. type="radio"
  64. value={value}
  65. onChange={onChange}
  66. checked={value == this.state[`${type}ElementAlign`]}
  67. />{" "}
  68. {value}{" "}
  69. </label>
  70. );
  71. });
  72. }
  73. }
  74. ReactDOM.render(<App />, mountNode);
  1. .basic-demo .elem1 {
  2. z-index: 99;
  3. background-color: #7FBF4D;
  4. background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
  5. background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
  6. background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
  7. background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
  8. background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
  9. background-image: linear-gradient(top, #7FBF4D, #63A62F);
  10. border: 1px solid #63A62F;
  11. border-bottom: 1px solid #5B992B;
  12. box-shadow: inset 0 1px 0 0 #96CA6D;
  13. color: white;
  14. padding: 7px 3px 8px;
  15. text-align: center;
  16. text-shadow: 0 -1px 0 #4C9021;
  17. opacity: 0.8;
  18. width: 100px;
  19. }
  20. .basic-demo .elem2 {
  21. box-sizing: border-box;
  22. border: 20px solid #999;
  23. background-color: #eee;
  24. width: 340px;
  25. height: 240px;
  26. margin: 50px 0 0 100px;
  27. line-height: 200px;
  28. text-align: center;
  29. }

事件封装

DOM DOM - 图2

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { events } = dom;
  3. const { on, off } = events;
  4. class App extends React.Component {
  5. componentDidMount() {
  6. const { btn, inner, outter, link, btnOnce, btnOrder, btnOff } = this.refs;
  7. on(btn, "click", function(e) {
  8. console.log(this, e.target, e.currentTarget);
  9. });
  10. on(inner, "click", function(e) {
  11. alert("Stop propagation!");
  12. e.stopPropagation();
  13. });
  14. on(outter, "click", function() {
  15. alert("Stop propagation failed!");
  16. });
  17. on(link, "click", function(e) {
  18. alert("Prevent default!");
  19. e.preventDefault();
  20. });
  21. const onceHandler = function() {
  22. alert("trigger");
  23. };
  24. on(btnOnce, "click", onceHandler);
  25. on(btnOnce, "click", onceHandler);
  26. on(btnOrder, "click", function() {
  27. alert("1");
  28. });
  29. on(btnOrder, "click", function() {
  30. alert("2");
  31. });
  32. const removeHandler = function() {
  33. alert("Remove event listener failed!");
  34. };
  35. on(btnOff, "click", removeHandler).off();
  36. }
  37. render() {
  38. return (
  39. <div className="events-demo">
  40. <h2>Add event listener</h2>
  41. <button ref="btn">Click me!</button>
  42. <h2>Stop propagation</h2>
  43. <div ref="outter" className="outter">
  44. Click me!
  45. <div ref="inner" className="inner">
  46. Click me!
  47. </div>
  48. </div>
  49. <h2>Prevent default</h2>
  50. <a ref="link" href="http://www.taobao.com">
  51. Taobao
  52. </a>
  53. <h2>Same handler trigger once</h2>
  54. <button ref="btnOnce">Click me!</button>
  55. <h2>Triggering order follows the registration order</h2>
  56. <button ref="btnOrder">Click me!</button>
  57. <h2>Remove event listener</h2>
  58. <button ref="btnOff">Click me!</button>
  59. </div>
  60. );
  61. }
  62. }
  63. ReactDOM.render(<App />, mountNode);
  1. .events-demo .outter {
  2. box-sizing: border-box;
  3. color: #fff;
  4. width: 200px;
  5. height: 200px;
  6. line-height: 50px;
  7. padding: 0 50px 50px;
  8. background: #999;
  9. text-align: center;
  10. }
  11. .events-demo .inner {
  12. color: #333;
  13. width: 100px;
  14. height: 100px;
  15. line-height: 100px;
  16. background: #eee;
  17. text-align: center;
  18. }

fixed 类型的定位

目标元素为 fixed 时的定位。

DOM DOM - 图3

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { position } = dom;
  3. class App extends React.Component {
  4. state = {
  5. pinElementAlign: "tl",
  6. baseElementAlign: "tl"
  7. };
  8. render() {
  9. return (
  10. <div className="fixed-demo">
  11. <div id="a4" className="elem1">
  12. 目标元素 a4
  13. </div>
  14. <div>
  15. <h3>pinElement(目标元素 a4)</h3>
  16. {this.renderRadio("pin")}
  17. </div>
  18. <div>
  19. <h3>baseElement(window)</h3>
  20. {this.renderRadio("base")}
  21. </div>
  22. </div>
  23. );
  24. }
  25. componentDidMount() {
  26. position.place(
  27. document.getElementById("a4"),
  28. position.VIEWPORT,
  29. this.state.pinElementAlign + " " + this.state.baseElementAlign
  30. );
  31. }
  32. componentDidUpdate() {
  33. position.place(
  34. document.getElementById("a4"),
  35. position.VIEWPORT,
  36. this.state.pinElementAlign + " " + this.state.baseElementAlign
  37. );
  38. }
  39. onPinElementAlignChange(e) {
  40. const value = e.target.value;
  41. this.setState({
  42. pinElementAlign: value
  43. });
  44. }
  45. onBaseElementAlignChange(e) {
  46. const value = e.target.value;
  47. this.setState({
  48. baseElementAlign: value
  49. });
  50. }
  51. renderRadio(type) {
  52. const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
  53. const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
  54. return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
  55. return (
  56. <label key={value}>
  57. <input
  58. type="radio"
  59. value={value}
  60. onChange={onChange}
  61. checked={value == this.state[`${type}ElementAlign`]}
  62. />{" "}
  63. {value}{" "}
  64. </label>
  65. );
  66. });
  67. }
  68. }
  69. ReactDOM.render(<App />, mountNode);
  1. .fixed-demo .elem1 {
  2. z-index: 99;
  3. background-color: #7FBF4D;
  4. background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
  5. background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
  6. background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
  7. background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
  8. background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
  9. background-image: linear-gradient(top, #7FBF4D, #63A62F);
  10. border: 1px solid #63A62F;
  11. border-bottom: 1px solid #5B992B;
  12. box-shadow: inset 0 1px 0 0 #96CA6D;
  13. color: white;
  14. padding: 7px 3px 8px;
  15. text-align: center;
  16. text-shadow: 0 -1px 0 #4C9021;
  17. opacity: 0.8;
  18. width: 100px;
  19. position: fixed;
  20. }

自动调整定位

为不让目标元素超出当前可视区域,可设置 needAdjust 参数为 true ,定位时会自动调整目标元素的定位方向。

DOM DOM - 图4

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { position } = dom;
  3. class App extends React.Component {
  4. state = {
  5. pinElementAlign: "tl",
  6. baseElementAlign: "tl"
  7. };
  8. render() {
  9. return (
  10. <div className="adjust-demo">
  11. <div className="cell">
  12. <div className="ele-wrapper">
  13. <div id="a3" className="elem1">
  14. 目标元素 a3
  15. </div>
  16. <div id="b3" className="elem2">
  17. 基准元素 b3
  18. </div>
  19. </div>
  20. </div>
  21. <div>
  22. <h3>pinElement(目标元素 a3)</h3>
  23. {this.renderRadio("pin")}
  24. </div>
  25. <div>
  26. <h3>baseElement(基准元素 b3)</h3>
  27. {this.renderRadio("base")}
  28. </div>
  29. </div>
  30. );
  31. }
  32. componentDidMount() {
  33. console.log(
  34. position.place(
  35. document.getElementById("a3"),
  36. document.getElementById("b3"),
  37. this.state.pinElementAlign + " " + this.state.baseElementAlign,
  38. [0, 0],
  39. true
  40. )
  41. );
  42. }
  43. componentDidUpdate() {
  44. console.log(
  45. position.place(
  46. document.getElementById("a3"),
  47. document.getElementById("b3"),
  48. this.state.pinElementAlign + " " + this.state.baseElementAlign,
  49. [0, 0],
  50. true
  51. )
  52. );
  53. }
  54. onPinElementAlignChange(e) {
  55. const value = e.target.value;
  56. this.setState({
  57. pinElementAlign: value
  58. });
  59. }
  60. onBaseElementAlignChange(e) {
  61. const value = e.target.value;
  62. this.setState({
  63. baseElementAlign: value
  64. });
  65. }
  66. renderRadio(type) {
  67. const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
  68. const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
  69. return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
  70. return (
  71. <label key={value}>
  72. <input
  73. type="radio"
  74. value={value}
  75. onChange={onChange}
  76. checked={value == this.state[`${type}ElementAlign`]}
  77. />{" "}
  78. {value}{" "}
  79. </label>
  80. );
  81. });
  82. }
  83. }
  84. ReactDOM.render(<App />, mountNode);
  1. .adjust-demo .elem1 {
  2. z-index: 99;
  3. background-color: #7FBF4D;
  4. background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
  5. background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
  6. background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
  7. background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
  8. background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
  9. background-image: linear-gradient(top, #7FBF4D, #63A62F);
  10. border: 1px solid #63A62F;
  11. border-bottom: 1px solid #5B992B;
  12. box-shadow: inset 0 1px 0 0 #96CA6D;
  13. color: white;
  14. padding: 7px 3px 8px;
  15. text-align: center;
  16. text-shadow: 0 -1px 0 #4C9021;
  17. opacity: 0.8;
  18. width: 100px;
  19. height: 200px;
  20. }
  21. .adjust-demo .elem2 {
  22. border: 1px solid #999;
  23. background-color: #eee;
  24. width: 300px;
  25. height: 30px;
  26. margin: 50px 0 0 100px;
  27. line-height: 200px;
  28. text-align: center;
  29. }
  30. .adjust-demo .ele-wrapper {
  31. position: relative;
  32. margin: 20px 20px 60px;
  33. border: 2px red solid;
  34. padding: 10px;
  35. }

offsetParent

当目标元素的 offsetParent 不为 body 时的定位。

DOM DOM - 图5

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { position } = dom;
  3. class App extends React.Component {
  4. state = {
  5. pinElementAlign: "tl",
  6. baseElementAlign: "tl"
  7. };
  8. render() {
  9. return (
  10. <div className="offset-demo">
  11. <div className="cell">
  12. <div className="ele-wrapper">
  13. <div id="a2" className="elem1">
  14. 目标元素 a2
  15. </div>
  16. </div>
  17. <div id="b2" className="elem2">
  18. 基准元素 b2
  19. </div>
  20. </div>
  21. <div>
  22. <h3>pinElement(目标元素 a2)</h3>
  23. {this.renderRadio("pin")}
  24. </div>
  25. <div>
  26. <h3>baseElement(基准元素 b2)</h3>
  27. {this.renderRadio("base")}
  28. </div>
  29. </div>
  30. );
  31. }
  32. componentDidMount() {
  33. position.place(
  34. document.getElementById("a2"),
  35. document.getElementById("b2"),
  36. this.state.pinElementAlign + " " + this.state.baseElementAlign
  37. );
  38. }
  39. componentDidUpdate() {
  40. position.place(
  41. document.getElementById("a2"),
  42. document.getElementById("b2"),
  43. this.state.pinElementAlign + " " + this.state.baseElementAlign
  44. );
  45. }
  46. onPinElementAlignChange(e) {
  47. const value = e.target.value;
  48. this.setState({
  49. pinElementAlign: value
  50. });
  51. }
  52. onBaseElementAlignChange(e) {
  53. const value = e.target.value;
  54. this.setState({
  55. baseElementAlign: value
  56. });
  57. }
  58. renderRadio(type) {
  59. const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
  60. const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
  61. return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
  62. return (
  63. <label key={value}>
  64. <input
  65. type="radio"
  66. value={value}
  67. onChange={onChange}
  68. checked={value == this.state[`${type}ElementAlign`]}
  69. />{" "}
  70. {value}{" "}
  71. </label>
  72. );
  73. });
  74. }
  75. }
  76. ReactDOM.render(<App />, mountNode);
  1. .offset-demo .elem1 {
  2. z-index: 99;
  3. background-color: #7FBF4D;
  4. background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
  5. background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
  6. background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
  7. background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
  8. background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
  9. background-image: linear-gradient(top, #7FBF4D, #63A62F);
  10. border: 1px solid #63A62F;
  11. border-bottom: 1px solid #5B992B;
  12. box-shadow: inset 0 1px 0 0 #96CA6D;
  13. color: white;
  14. padding: 7px 3px 8px;
  15. text-align: center;
  16. text-shadow: 0 -1px 0 #4C9021;
  17. opacity: 0.8;
  18. width: 100px;
  19. }
  20. .offset-demo .elem2 {
  21. box-sizing: border-box;
  22. border: 20px solid #999;
  23. background-color: #eee;
  24. width: 340px;
  25. height: 240px;
  26. margin: 50px 0 0 100px;
  27. line-height: 200px;
  28. text-align: center;
  29. }
  30. .offset-demo .ele-wrapper {
  31. position: relative;
  32. margin: 20px;
  33. border: 2px red solid;
  34. padding: 20px;
  35. }

相对 Viewport 的定位

目标元素相对 viewport 的定位。

DOM DOM - 图6

查看源码在线预览

  1. import { dom } from "@icedesign/base";
  2. const { position } = dom;
  3. class App extends React.Component {
  4. state = {
  5. pinElementAlign: "tl",
  6. baseElementAlign: "tl"
  7. };
  8. render() {
  9. return (
  10. <div className="viewport-demo">
  11. <div className="cell">
  12. <div className="ele-wrapper">
  13. <div id="a5" className="elem1">
  14. 目标元素 a5
  15. </div>
  16. </div>
  17. </div>
  18. <div>
  19. <h3>pinElement(目标元素 a5)</h3>
  20. {this.renderRadio("pin")}
  21. </div>
  22. <div>
  23. <h3>baseElement(viewport)</h3>
  24. {this.renderRadio("base")}
  25. </div>
  26. </div>
  27. );
  28. }
  29. componentDidMount() {
  30. console.log(
  31. position.place(
  32. document.getElementById("a5"),
  33. position.VIEWPORT,
  34. this.state.pinElementAlign + " " + this.state.baseElementAlign
  35. )
  36. );
  37. }
  38. componentDidUpdate() {
  39. console.log(
  40. position.place(
  41. document.getElementById("a5"),
  42. position.VIEWPORT,
  43. this.state.pinElementAlign + " " + this.state.baseElementAlign
  44. )
  45. );
  46. }
  47. onPinElementAlignChange(e) {
  48. const value = e.target.value;
  49. this.setState({
  50. pinElementAlign: value
  51. });
  52. }
  53. onBaseElementAlignChange(e) {
  54. const value = e.target.value;
  55. this.setState({
  56. baseElementAlign: value
  57. });
  58. }
  59. renderRadio(type) {
  60. const typeUpperCase = type.charAt(0).toUpperCase() + type.substring(1);
  61. const onChange = this[`on${typeUpperCase}ElementAlignChange`].bind(this);
  62. return ["tl", "tc", "tr", "cl", "cc", "cr", "bl", "bc", "br"].map(value => {
  63. return (
  64. <label key={value}>
  65. <input
  66. type="radio"
  67. value={value}
  68. onChange={onChange}
  69. checked={value == this.state[`${type}ElementAlign`]}
  70. />{" "}
  71. {value}{" "}
  72. </label>
  73. );
  74. });
  75. }
  76. }
  77. ReactDOM.render(<App />, mountNode);
  1. .viewport-demo .elem1 {
  2. z-index: 99;
  3. background-color: #7FBF4D;
  4. background-image: -webkit-gradient(linear, left top, left bottom, from(#7FBF4D), to(#63A62F));
  5. background-image: -webkit-linear-gradient(top, #7FBF4D, #63A62F);
  6. background-image: -moz-linear-gradient(top, #7FBF4D, #63A62F);
  7. background-image: -ms-linear-gradient(top, #7FBF4D, #63A62F);
  8. background-image: -o-linear-gradient(top, #7FBF4D, #63A62F);
  9. background-image: linear-gradient(top, #7FBF4D, #63A62F);
  10. border: 1px solid #63A62F;
  11. border-bottom: 1px solid #5B992B;
  12. box-shadow: inset 0 1px 0 0 #96CA6D;
  13. color: white;
  14. padding: 7px 3px 8px;
  15. text-align: center;
  16. text-shadow: 0 -1px 0 #4C9021;
  17. opacity: 0.8;
  18. width: 100px;
  19. }
  20. .viewport-demo .ele-wrapper {
  21. position: relative;
  22. margin: 20px 20px 60px;
  23. border: 2px red solid;
  24. padding: 20px;
  25. }

相关区块

DOM DOM - 图7

暂无相关区块