1. 对象 组合成 树形结构,表示 “部分-整体” 层次结构,组合模式 使 客户端单个对象组合对象 保持一致的 方式处理;

  2. 适用场景:

    • 忽略差异:希望 客户端 可以忽略 组合对象单个对象 的差异;
    • 处理树形结构;
  3. 优点:

    • 定义层次:清楚地 定义 分层次复杂对象,表示 对象 的 全部部分 层次;
    • 忽略层次:让 客户端 忽略 层次之间的差异,方便对 整个层次结构 进行控制;
    • 简化客户端代码;
    • 符合开闭原则;
  4. 缺点:

    • 限制类型复杂:限制类型时,比较复杂,如:某个目录中只能包含文本文件,使用组合模式时,不能依赖类型系统,施加约束,它们都来自于节点的抽象层; 在这种情况下,必须通过在运行时进行类型检查,这样就变得比较复杂;
    • 使设计变得更加抽象;

类图

代码

<!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>
    <style>
        .red {
            color: red;
        }
    </style>
</head>

<body>
    <div id="root"></div>
    <script>
        function ReactElement(type, props) {
            this.type = type;
            this.props = props;
        }

        let React = {
            createElement(type, props = {}, ...childrens) {
                childrens.length === 1 ? childrens = childrens[0]: void 0
                return new ReactElement(type, { ...props, children: childrens })
            }
        };

        let render = (eleObj, container) => {
            // 先取出第一层 进行创建真实 dom
            let { type, props } = eleObj;
            let elementNode = document.createElement(type); // 创建第一个元素

            for (let attr in props) { // 循环所有属性
                if (attr === 'children') { // 如果是 children 表示有嵌套关系
                    if (typeof props[attr] == 'object') { // 看是否是只有一个文本节点
                        props[attr].forEach(item => { // 多个的话循环判断 如果是对象再次调用 render 方法
                            if (typeof item === 'object') {
                                render(item, elementNode);
                            } else { //是文本节点 直接创建即可
                                elementNode.appendChild(document.createTextNode(item));
                            }
                        })
                    } else { // 只有一个文本节点直接创建即可
                        elementNode.appendChild(document.createTextNode(props[attr]));
                    }
                } else if (attr === 'className') { // 是不是 class 属性,class 属性特殊处理
                    elementNode.setAttribute('class', props[attr]);
                } else {
                    elementNode.setAttribute(attr, props[attr]);
                }
            }
            container.appendChild(elementNode)
        };

        //ReactDOM.render(<div>hello<span>world</span></div>);
        //ReactDOM.render(React.createElement("div",null,"hello,",React.createElement("span",null,"world")));
        render(React.createElement("div", null, "hello,", React.createElement("span", { class: "red" }, "world")), document.getElementById('root'));
    </script>
</body>

</html>

应用场景

文件夹和文件

function Folder(name) {
  this.name = name;
  this.children = [];
  this.parent = null;
  this.level = 0;
}
Folder.prototype.add = function (child) {
  child.level = this.level + 1;
  child.parent = this;
  this.children.push(child);
}
Folder.prototype.show = function () {
  console.log(' '.repeat(this.level) + '文件夹' + this.name);
  for (let i = 0; i < this.children.length; i++) {
    this.children[i].show();
  }
}
Folder.prototype.remove = function () {
  if (!this.parent) return;
  for (let i = 0; i < this.parent.children.length; i++) {
    let current = this.parent.children[i];
    if (current === this) {
      return this.parent.children.splice(i, 1);
    }
  }
}

function File(name) {
  this.name = name;
}
File.prototype.add = function () {
  throw new Error(`文件下面不能再添加文件`);
}
File.prototype.show = function () {
  console.log(' '.repeat(this.level) + '文件' + this.name);
}

let folder = new Folder('视频');
let vueFolder = new Folder('Vue视频');
let reactFolder = new Folder('React视频');
let vueFile = new File('Vue从入门到精通');
let reactFile = new File('React从入门到精通');
folder.add(vueFolder);
folder.add(reactFolder);
vueFolder.add(vueFile);
reactFolder.add(reactFile);

folder.show();
vueFolder.remove();
folder.show();

绘制表单

// 容器
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);
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 类图
  2. 2. 代码
  3. 3. 应用场景
    1. 3.1. 文件夹和文件
    2. 3.2. 绘制表单