Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON2DOM = react的render函数 #37

Open
Sunny-117 opened this issue Nov 3, 2022 · 14 comments
Open

JSON2DOM = react的render函数 #37

Sunny-117 opened this issue Nov 3, 2022 · 14 comments

Comments

@Sunny-117
Copy link
Owner

{
  tag: 'DIV',
  attrs:{
  id:'app'
  },
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>
@Sunny-117
Copy link
Owner Author

// 真正的渲染函数
function _render(vnode) {
  // 如果是数字类型转化为字符串
  if (typeof vnode === "number") {
    vnode = String(vnode);
  }
  // 字符串类型直接就是文本节点
  if (typeof vnode === "string") {
    return document.createTextNode(vnode);
  }
  // 普通DOM
  const dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    // 遍历属性
    Object.keys(vnode.attrs).forEach((key) => {
      const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    });
  }
  // 子数组进行递归操作
  vnode.children.forEach((child) => dom.appendChild(_render(child)));
  return dom;
}

@truejiang
Copy link

truejiang commented Nov 4, 2022

function render(vnode) {

  const { tag, attrs = {}, children } = vnode

  // 开始通过vnode去创建dom
  const el = document.createElement(String(tag).toLocaleLowerCase())

  // 处理 attrs
  for (const key in attrs) {
    el.setAttribute(key, attrs[key])
  }


  // 处理children
  if(typeof children === 'string') {
    // 如果children是字符串,当做文本文本节点插入
    el.appendChild(document.createTextNode(children))
  } else if(Array.isArray(children) && children.length > 0) {
    // 如果是数组需要递归的render
    children.forEach(child => render(child, el))
  }

  return el
}

@lxy-Jason
Copy link
Contributor

仅完成题目要求版本,可以直接F12查元素看结果

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    function render(vnode) {
      const { tag, attrs = {}, children } = vnode;
      //创建dom
      let el = document.createElement(tag);
      //添加attr
      for (const key in attrs) {
        el.setAttribute(key, attrs[key]);
      }
      //处理children
      if (Array.isArray(children) && children.length > 0) {
        children.forEach(child => el.appendChild(render(child)));//子元素添加在父元素中
      }
      return el
    }
    const vnode = {
      tag: 'DIV',
      attrs: {
        id: 'app'
      },
      children: [
        {
          tag: 'SPAN',
          children: [
            { tag: 'A', children: [] }
          ]
        },
        {
          tag: 'SPAN',
          children: [
            { tag: 'A', children: [] },
            { tag: 'A', children: [] }
          ]
        }
      ]
    }
    document.body.appendChild(render(vnode))
  </script>
</body>
</html>

@lxy-Jason
Copy link
Contributor

function render(vnode) {

  const { tag, attrs = {}, children } = vnode

  // 开始通过vnode去创建dom
  const el = document.createElement(String(tag).toLocaleLowerCase())

  // 处理 attrs
  for (const key in attrs) {
    el.setAttribute(key, attrs[key])
  }


  // 处理children
  if(typeof children === 'string') {
    // 如果children是字符串,当做文本文本节点插入
    el.appendChild(document.createTextNode(children))
  } else if(Array.isArray(children) && children.length > 0) {
    // 如果是数组需要递归的render
    children.forEach(child => render(child, el))
  }

  return el
}

你忘记把子元素要添加到父元素中了吧?

@yang-xianzhu
Copy link

yang-xianzhu commented Nov 10, 2022

   function renderer(vnode) {
      const el = document.createElement(vnode.tag.toLocaleLowerCase());

      // 处理attrs
      for (const k in vnode.attrs) {
        el.setAttribute(k, vnode.attrs[k]);
      }
      //  如果children是字符串
      if (typeof vnode.children === "string") {
        const textNode = document.createTextNode(vnode.children);
        el.appendChild(textNode);
      }
      // 如果chidlren是数组,并且不是空数组时,就递归转化
      if (Array.isArray(vnode.children) && vnode.children.length > 0) {
        vnode.children.forEach((child) => {
          el.appendChild(renderer(child, el));
        });
      }
      return el;
    }

@Leadgq
Copy link

Leadgq commented Jan 12, 2023

function _render(vNode) {
// 解构
const {tag, attrs, children} = vNode;
const root = document.createElement(tag.toLowerCase());
for (const key in attrs) {
root.setAttribute(key, attrs[key])
}
// 字符串
if (typeof children === 'string') {
root.appendChild(document.createTextNode(children));
// 数组
} else if (Array.isArray(children) && children.length > 0) {
// 递归添加
children.forEach(item => root.appendChild(_render(item)))
}
return root
}

@veneno-o
Copy link
Contributor

function _render(vnode) {
  // 考虑非一般性, 临界值
	if (typeof vnode === "number") {
		vnode = String(vnode);
	}
	if (typeof vnode === "string") {
		return document.createTextNode(vnode);
	}
  // 不失一般性
	const dom = document.createElement(vnode.tag);
	if (vnode.attrs) {
		for (const key in vnode.attrs) {
			dom.setAttribute(key, vnode.attrs[key]);
		}
	}
	if (vnode.children) {
		vnode.children.forEach((newVnode) => {
			dom.appendChild(_render(newVnode));
		});
	}
	return dom;
}

@sunshineLixun
Copy link

/**
 * {
  tag: 'DIV',
  attrs:{
  id:'app'
  },
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>
 */

function render(vnode) {
  if (typeof vnode === "string") {
    return document.createTextNode(vnode);
  }
  if (typeof vnode === "number") {
    vnode = String(vnode);
  }
  let dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    for (const key in vnode.attrs) {
      dom.setAttribute(key, vnode.attrs[key]);
    }
  }

  if (vnode.children) {
    if (typeof vnode.children === "object") {
      vnode.children.forEach((child) => {
        dom.appendChild(render(child));
      });
    } else if (
      typeof vnode.children === "string" ||
      typeof vnode.children === "number"
    ) {
      if (typeof vnode.children === "number") {
        vnode.children = String(vnode.children);
      }
      dom.appendChild(document.createTextNode(vnode.children));
    }
  }

  return dom;
}

function test() {
  const vnode = {
    tag: "DIV",
    attrs: {
      id: "app",
    },
    children: [
      {
        tag: "SPAN",
        children: [
          {
            tag: "A",
            children: [{ tag: "P", attrs: { text: "p" }, children: 123213 }],
          },
        ],
      },
      {
        tag: "SPAN",
        children: [
          { tag: "A", children: [] },
          { tag: "A", children: [] },
        ],
      },
    ],
  };

  const dom = render(vnode);
  console.log(dom);
}

test();

@whale2002
Copy link

题目要求,这里增加了具体的节点内容,便于理解。

把上诉虚拟Dom转化成下方真实Dom
<div id="app">
  <span>
    <a></a>
  </span>
  <span>
    <a>123</a>
    <a>456</a>
    789
  </span>
</div>

实现

const vDom = {
    tag: 'DIV',
    attrs: {
        id: 'app'
    },
    children: [
        {
            tag: 'SPAN',
            children: [{tag: 'A', children: []}]
        },
        {
            tag: 'SPAN',
            children: [
                {tag: 'A', children: [123]},
                {tag: 'A', children: [456]},
                789
            ]
        }
    ]
};

function render(vNode) {
    // 递归终止条件
    if (typeof vNode === 'number')
        return document.createTextNode(String(vNode));
    if (typeof vNode === 'string') return document.createTextNode(vNode);

    const {tag, attrs = {}, children = []} = vNode;
    const dom = document.createElement(tag);

    Object.keys(attrs).forEach((attr) => {
        dom.setAttribute(attr, attrs[attr]);
    });

    children.forEach((child) => {
        dom.append(render(child));
    });

    return dom;
}

const dom = render(vDom);

@Bbbtt04
Copy link

Bbbtt04 commented Mar 11, 2023

function render(vnode) {
  if (typeof vnode === 'number') {
    vnode = String(vnode)
  }

  if (typeof vnode === 'string') {
    return document.createTextNode(vnode)
  }

  let dom = document.createElement(vnode.tag)
  if (vnode.attrs) {
    Object.keys(vnode.attrs).map(key => {
      let value = vnode.attrs[key]
      dom.setAttribute(key, value)
    })
  }
  vnode.children && vnode.children.map(item => {
    dom.appendChild(render(item))
  })
  return dom
}

@xun-zi
Copy link

xun-zi commented Mar 13, 2023

function render(data) {
        const curNode = document.createElement(data.tag);
        for (let key in curNode.attrs) {
            curNode.setAttribute(key, curNode.attrs[key]);
        }
        for (let child of data.children) {
            curNode.append(render(child));
        }
        return curNode;
    }

@ashwat07
Copy link

ashwat07 commented Apr 11, 2023

const renderDom = function (jsonDom) {
  const mainEl = document.createElement(jsonDom?.tag?.toLowerCase());

  if (jsonDom.attrs) {
    Object.keys(jsonDom.attrs).forEach((attr) => {
      mainEl.setAttribute(attr, jsonDom.attrs[attr]);
    });
  }
  jsonDom.children.forEach((child) => {
    mainEl.appendChild(renderDom(child));
  });
  return mainEl;
};

@Simonduya
Copy link

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      const jump = () => {
        alert(666);
      };
      const vnode = {
        tags: "div",
        props: {
          id: "box",
          style: "width:100px; color:red",
        },
        children: [
          {
            tags: "a",
            props: {
              onClick: jump,
            },
            children: "hahaha",
          },
        ],
      };
      const render = (vnode) => {
        const { tags, props, children } = vnode;
        const el = document.createElement(tags);

        if (props) {
          for (const key in props) {
            const value = props[key];
            if (key.startsWith("on")) {
              el.addEventListener(key.slice(2).toLowerCase(), value);
            } else {
              el.setAttribute(key, value);
            }
          }
        }
        console.log(children);
        if (children) {
          if (typeof children === "string") {
            el.textContent = children;
          } else {
            children.forEach((item) => {
              el.appendChild(render(item));
            });
          }
        }

        return el;
      };
      document.body.appendChild(render(vnode));
    </script>
  </body>
</html>

就是mount的一些步骤

@why-ztc
Copy link

why-ztc commented Aug 11, 2023

const render = (root) => {
  const dfs = (vdom) => {
    const { tag, attrs, children } = vdom
    if (!vdom) {
      return
    }
    const dom = document.createElement(tag)
    if (attrs) {
      Object.keys(attrs).forEach(key => {
        dom.setAttribute(key, attrs[key])
      })
    }
    if (Array.isArray(children) && children.length) {
      children.forEach(item => {
        dom.appendChild(dfs(item))
      })
    }
    return dom
  }
  const res = dfs(root)
  return res
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests