# 十一.组合模式

  • 又称整体-部分模式
  • 将对象组合成树形结构以表示部分-整体的层次结构
  • 客户可以使用统一的方式对待组合对象和叶子对象

# 1.类图

# 2.代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>组合模式</title>
  </head>

  <body>
    <div id="root"></div>
    <script>
      // ReactDOM.render(<span><span>hello</span>world</span>, document.querySelector("#root"))
      class ReactElement {
        constructor(type, props) {
          this.type = type
          this.props = props
        }
      }
      function createElement(type, props = {}, ...children) {
        return new ReactElement(type, {
          ...props,
          children: children.length == 1 ? children[0] : children,
        })
      }
      let rootElement = createElement(
        "span",
        null,
        "hello",
        createElement("span", null, "world")
      )
      function render(element, container) {
        let { type, props } = element
        let domElement = document.createElement(type)
        for (let attr in props) {
          if (attr === "children") {
            if (typeof props[attr] == "object") {
              props[attr].forEach((item) => {
                if (typeof item == "object") {
                  render(item, domElement)
                } else {
                  domElement.appendChild(document.createTextNode(item))
                }
              })
            } else {
              domElement.appendChild(document.createTextNode(props[attr]))
            }
          } else if (attr === "className") {
            domElement.setAttribute("class", props[attr])
          } else {
            domElement.setAttribute(attr, props[attr])
          }
        }
        container.appendChild(domElement)
      }
      render(rootElement, document.querySelector("#root"))
    </script>
  </body>
</html>
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

# 3.应用场景

# 3.1 文件夹和文件

function Folder(name) {
  this.name = name
  this.children = []
  this.parent = null
}
Folder.prototype.add = function(child) {
  child.parnet = this
  this.children.push(child)
}
Folder.prototype.show = function() {
  console.log("文件夹" + this.name)
  for (let i = 0; i < this.children.length; i++) {
    this.children[i].show()
  }
}
function File(name) {
  this.name = name
}
File.prototype.add = function() {
  throw new error("文件夹不能")
}
File.prototype.show = function() {
  console.log("文件" + this.name)
}
let video = new Folder("video")
let vue = new Folder("vue")
let react = new Folder("react")
let vuejs = new File("vuejs")
let reactjs = new File("reactjs")
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

# 3.2 绘制表单

class FormContainer {
  constructor(type) {
    this.element = document.createElement(type)
    this.children = []
  }
  add(child) {
    this.children.push(child)
    this.element.appendChild(child.element)
    return this
  }
}
class FieldContainer {
  constructor(type) {
    this.element = document.createElement(type)
    this.children = []
  }
  add(child) {
    this.children.push(child)
    this.element.appendChild(child.element)
    return this
  }
}
class LabelItem {
  constructor(title) {
    this.element = document.createElement("label")
    this.element.innerHTML = title
  }
}
class InputItem {
  constructor(title) {
    this.element = document.createElement("input")
    this.element.name = title
  }
}
class TipItem {
  constructor(title) {
    this.element = document.createElement("span")
    this.element.innerHTML = title
  }
}
let userform = new FormContainer("form")
  .add(
    new FieldContainer("p")
      .add(new LabelItem("用户名"))
      .add(new InputItem("username"))
      .add(new TipItem("用户名长度为6-8位"))
  )
  .add(
    new FieldContainer("p")
      .add(new LabelItem("密码"))
      .add(new InputItem("password"))
      .add(new TipItem("确认密码"))
  )
document.body.appendChild(userform.element)
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