Vue 声明式编程与虚拟 DOM 简单了解

152 阅读2分钟

Vue 是个声明式的框架

  • 声明式:告诉 Vue 如何渲染,而不是告诉 Vue 如何去做,声明式框架更关注结果。
  • 命令式:如 Jquery,每一行都可以明确的知道干嘛了,命令式更加关注过程
  • 响应式:数据发生变化,视图也会跟着变化。
  • 虚拟 DOM,通过 JavaScript 对象来描述 UI,其实就是虚拟 DOM
const vnode = {
  tag: 'div',
  props: {
    id: 'app',
    class: 'container',
    onClick: () => {
      console.log('clicked')
    }
  },
  children: [
    {
      tag: 'p',
      text: 'Hello, Vue!'
    }
  ]
}

渲染器

  • 渲染器是 Vue 的核心,它负责将虚拟 DOM 渲染成真实 DOM。
  • 渲染器是一个函数,它接受一个虚拟 DOM 对象作为参数,创建、更新、删除真实 DOM 对象。
// 一个简单的渲染器、不包含更新、删除的渲染器(更新才是是精髓)
const renderer = (vnode, container) => {
  const el = document.createElement(vnode.tag)
  for (const key in vnode.props) {
    if (/^on/.test(key)) {
      // 如果key以on开头,表明是一个事件
      el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
    } else {
      // 否则,是一个属性
      el.setAttribute(key, vnode.props[key])
    }
  }
  if (typeof vnode.children === 'string') {
    // 字符串的话就是一个文本节点
    el.textContent = vnode.children
  } else if (Array.isArray(vnode.children)) {
    // 数组的话就是一个子节点,递归渲染
    vnode.children.forEach((child) => renderer(child, el))
  }
  container.appendChild(el)
}
  • 组件、对象渲染(渲染一个组件、对象)
  • Vue 单独状态的组件就是对象格式创建的
const Component = () => { // 组件是个函数,返回一个虚拟 DOM 对象
  return {
    div: 'div',
    props: {
      id: 'app',
      class: 'container',
      onClick: () => {
        console.log('clicked')
      }
    },
    children: 'hello world'
  }
}
const obj = { // 组件是个对象,返回一个虚拟 DOM 对象
  render: () => {
    div: 'div',
    props: {
      id: 'app',
      class: 'container',
      onClick: () => {
        console.log('clicked')
      }
    },
    children: 'hello world'
  }
}
const vnode = {
  tag: Component || obj
}

const rendererComponent = (vnode, container) => {
  if (typeof vnode.tag === 'function') {
    // 如果tag是一个函数,说明是一个组件
    const component = vnode.tag()
    renderer(component, container)
  } else if (typeof vnode.tag === 'object') {
    // 如果tag是一个对象,说明是一个组件
    const component = vnode.tag.render()
    renderer(component, container)
  } else {
    // 否则,就是一个普通的元素
    renderer(vnode, container)
  }
}

编译器

  • 编译器是 Vue 的另一个核心,它负责将模板字符串编译成虚拟 DOM 对象。
  • 编译器是一个函数,它接受一个模板字符串作为参数,返回一个虚拟 DOM 对象。
<template>
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

// 把上面的模板最终渲染成这样, 这就是编译器的作用
<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  render() {
    return h('div', { id: 'app' }, h('p', {}, this.message))
  }
}
</script>

组合器(.vue 文件渲染到页面上)

  1. vue 文件 编译成 js 文件(编译器)
  2. js 文件 执行 render 函数编译(渲染器)生成虚拟 DOM 节点。
  3. 虚拟 DOM 被转换成实际的 DOM,并插入到页面中。Vue 通过 diff 算法优化这个过程,只更新有变化的部分。