Skip to content
vue
<template>
  <div id="demo"></div>
</template>

<script setup>
import { onMounted } from 'vue'
onMounted(() => {
  function render(vnode, root) {
    if (typeof vnode.tag === 'string') {
      mountElement(vnode, root)
    } else if (typeof vnode.tag === 'object') {
      mountComponent(vnode, root)
    }
  }
  function mountElement(vnode, container) {
    const el = document.createElement(vnode.tag)
    for (const key in vnode.props) {
      if (/^on/.test(key)) {
        el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
      }
    }
    if (typeof vnode.children === 'string') {
      const text = document.createTextNode(vnode.children)
      el.appendChild(text)
    } else if (vnode.children) {
      vnode.children.forEach(child => {
        render(child, el)
      });
    }
    container.appendChild(el)
  }
  function mountComponent(vnode, container) {
    const subtree = vnode.tag.render()
    render(subtree, container)
  }

  const obj = {
    tag: 'div',
    props: {
      onClick: () => alert('asdf')
    },
    children: [
      {
        tag: 'div',
        children: '123'
      },
      {
        tag: 'div',
        children: '321'
      }
    ]
  }
  const myComponent = {
    render: () => {
      return {
        tag: 'div',
        props: {
          onClick: () => alert('asdf2')
        },
        children: [
          {
            tag: 'span',
            children: 'span'
          }
        ]
      }
    }
  }
  const obj2 = {
    tag: myComponent
  }
  render(obj, document.querySelector('#demo'))
  render(obj2, document.querySelector('#demo'))
})
</script>
<template>
  <div id="demo"></div>
</template>

<script setup>
import { onMounted } from 'vue'
onMounted(() => {
  function render(vnode, root) {
    if (typeof vnode.tag === 'string') {
      mountElement(vnode, root)
    } else if (typeof vnode.tag === 'object') {
      mountComponent(vnode, root)
    }
  }
  function mountElement(vnode, container) {
    const el = document.createElement(vnode.tag)
    for (const key in vnode.props) {
      if (/^on/.test(key)) {
        el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
      }
    }
    if (typeof vnode.children === 'string') {
      const text = document.createTextNode(vnode.children)
      el.appendChild(text)
    } else if (vnode.children) {
      vnode.children.forEach(child => {
        render(child, el)
      });
    }
    container.appendChild(el)
  }
  function mountComponent(vnode, container) {
    const subtree = vnode.tag.render()
    render(subtree, container)
  }

  const obj = {
    tag: 'div',
    props: {
      onClick: () => alert('asdf')
    },
    children: [
      {
        tag: 'div',
        children: '123'
      },
      {
        tag: 'div',
        children: '321'
      }
    ]
  }
  const myComponent = {
    render: () => {
      return {
        tag: 'div',
        props: {
          onClick: () => alert('asdf2')
        },
        children: [
          {
            tag: 'span',
            children: 'span'
          }
        ]
      }
    }
  }
  const obj2 = {
    tag: myComponent
  }
  render(obj, document.querySelector('#demo'))
  render(obj2, document.querySelector('#demo'))
})
</script>