(2)手写mini-vue,实现setup以及render函数中vdom

46 阅读1分钟

接上文中b会随着a的变化而变化,那么将b替换成当前view视图就可以实现响应式改变页面了

1.实现App.js,注意抽离用户不需要操作的effectWatch

//App.js
import {reactive} from './core/reactivity/index.js'
import { h } from './core/h.js'
export default {
  render (context) {
      // //构建view =>b
      // const div = document.createElement('div')
      // div.innerHTML = context.state.count
      // //root
      // return div
      //构建虚拟dom
    return h('div', 
    {
      id:'app - id',
      class:'showTim'
      }, 
      [h('p',null,'hhh'),
        h('p', null, 'heiheihei')
    ]
      )
  },
  setup () {
    //a =>响应式的数据
    const state = reactive({ count: 0 })
    window.state = state
    return { state }
  }
}

2.实现main.js

//index.js
import App from "./App.js";
import { createApp } from "./core/index.js";

createApp(App).mount(document.querySelector('#app'))

3.实现creatApp

//core/index.js
import { effectWatch } from './reactivity/index.js'
import { mountElement } from './renderer/index.js'
//rootComponent ==> App.js
export function createApp (rootComponent) {

  return {
    //rootContainer == #app
    mount (rootContainer) {
      const context = rootComponent.setup()
      effectWatch(() => {
        rootContainer.innerHTML = ''
        //element ==> render函数 return的 div
        // const element = rootComponent.render(context)
        // rootContainer.append(element)
        //传入的是虚拟dom对象
         const subTree = rootComponent.render(context)
         console.log(subTree)
         mountElement(subTree,rootContainer)
      }
      )
    }
  }
}

4.实现mountElement

//core/renderer/index.js
//vdom=>真实dom

export function mountElement(vnode,container){
  const {tag,props,children} = vnode
  //tag
    const el = document.createElement(tag)
    
  //props
    if(props){
      for (const key in props) {
        const val = props[key]
        el.setAttribute(key,val)
      }
    }

  //children
  //1.它可以接受一个string
  if(typeof children==='string'){
    const textNode = document.createTextNode(children)
    el.append(textNode)
   }else if(Array.isArray(children)){
    children.forEach((v) => {
      mountElement(v,el)
    }
    )
  }
  container.append(el)
}

5.渲染函数h

//core/h.js
export function h(tag,props,children){

    return {
      tag,
      props,
      children
    }
}

6.最后实现

image.png