1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Document</title>
    8. <style>
    9. .dialog{
    10. width: 300px;
    11. height: 300px;
    12. margin:30px auto;
    13. border:1px solid #333;
    14. padding:30px;
    15. }
    16. </style>
    17. </head>
    18. <body>
    19. <!--
    20. Dom操作 为啥比较慢?
    21. 1. 臃肿 有年限
    22. 2. 图形输出
    23. -->
    24. <div id="root">
    25. <p></p>
    26. <Cmp1 click="fn1" mouseover="fn2"></Cmp1>
    27. <UserLogin></UserLogin>
    28. </div>
    29. <script>
    30. // 组件渲染
    31. function render(options) {
    32. let root;
    33. // 判断属性类型
    34. if(typeof options.root === 'string') {
    35. root = document.querySelector(options.root);
    36. if(!root) {
    37. throw new Error(`找不到根元素 ${options.root}`)
    38. }
    39. } else if(options.root instanceof HTMLElement) {
    40. let tags = options.root.getElementsByTagName('*');
    41. tags = Array.from(tags);
    42. // 找出自定义组件标签
    43. tags.forEach(element => {
    44. // 找到这是自定义组件
    45. if(element.constructor === HTMLUnknownElement){
    46. for (let cmpName in options.components) {
    47. if(cmpName.toUpperCase() === element.nodeName) {
    48. let CmpCls = options.components[cmpName];
    49. // 生成一个类的实例
    50. let cmp = new CmpCls();
    51. let res = cmp.render();
    52. // 获取组件定义的 属性和方法
    53. if(element.hasAttribute("click")){
    54. res.addEventListener('click', options.method[element.getAttribute("click")])
    55. }
    56. if(element.hasAttribute("mouseover")){
    57. res.addEventListener('mouseover', options.method[element.getAttribute("mouseover")])
    58. }
    59. element.parentNode.replaceChild(res, element);
    60. }
    61. }
    62. }
    63. });
    64. }
    65. }
    66. // 抽象的父类
    67. class Component {
    68. render() {
    69. throw new Error('render is required');
    70. }
    71. }
    72. class Cmp1 extends Component {
    73. render() {
    74. let div = document.createElement('div');
    75. div.innerHTML = '我是cpm1';
    76. return div;
    77. }
    78. }
    79. class UserLogin extends Component{
    80. render() {
    81. let div = document.createElement('div');
    82. div.className = 'dialog';
    83. div.innerHTML = '我是login';
    84. return div;
    85. }
    86. }
    87. render({
    88. root: document.querySelector('#root'),
    89. components: {
    90. Cmp1,
    91. UserLogin
    92. },
    93. method: {
    94. fn1:() => {console.log('我是cpm1,你点击了我');},
    95. fn2:() => {console.log('我是cpm1,你碰到我了');}
    96. }
    97. })
    98. </script>
    99. </body>
    100. </html>