Vue3 的设计思路

0. vue是如何将模板渲染到页面的

假设我们有如下模板

<div id="foo" :class="cls"></div>

vue的编译器会把这段代码编译成渲染函数:

render() {
    // return h('div', {id: "foo", class: cls})
    return {
        tag: 'div',
        props: {
            id: 'foo',
            class: cls
        },
        patchFlags: 1 // 假设数字1代表class是动态的
    }
}

然后渲染器再把渲染函数返回的虚拟DOM渲染为真实的DOM。

function renderer(vnode, container) {
    const el = document.createElement(vnode.tag);
    for (const key in vnode.props) {
        if (/^on/.test(key)) {
            // 以on开头说明它是事件
            el.addEventListener(
                key.substring(2).toLowerCase(),
                vnode.props[key]
            )
        }
    }
​
    if (typeof vnode.children === 'string') {
        el.appendChild(document.createTextNode(vnode.children))
    }
    else if (Array.is(vnode.children)) {
        vnode.children.forEach(child => renderer(child, el));
    }
​
    container.appendChild(el);
}

编辑器与渲染器是vuejs的核心组成部分,下面开始逐渐深入讲解。

1. 声明式的描述UI

vue是一个声明式的UI框架,即用户再使用vue开发页面时是声明式的描述UI的。

模板声明式描述UI

<div class="cls"><span>hello world</span></div>

js对象声明式描述UI

const title = {
    tag: 'h1',
    props: {
        class: 'title',
        onclick: handler
    },
    children: [
        {
            tag: 'span'
        }
    ]
}

js对象即虚拟DOM。虚拟DOM描述UI更加灵活,但模板更加直观。

小知识点: h函数是一个辅助创建虚拟dom的工具函数,render函数中调用h函数生成了一个虚拟dom对象。

2. 初识渲染器

渲染器的作用: 就是把虚拟DOM渲染成真实DOM。

h('div', 'htllo')   ===> 渲染器 ===>  真实DOM

举例:

// 虚拟DOM
const vnode = {
    tag: 'div', // 描述标签名称
    props: { // 描述标签的属性事件等内容
        class: 'cls',
        onClick: () => alert('hello') 
    },
    children: [  // 描述子节点
        'click me'
    ]
}

该虚拟节点通过上文的renderer函数,渲染为真实的DOM。

renderer(vnode, document.body); // body 为真实DOM元素,作为虚拟DOM挂载点。

renderer实现思路

  • 创建元素

  • 为元素添加属性和事件

  • 处理children

  • 挂载到真实DOM节点

渲染器的工作原理很简单,就是利用一些DOM操作API来完成渲染工作。

组件的本质

vue组件就是一组DOM元素的封装。可以定义一个函数来代表组件,函数的返回值就代表组件要渲染的内容。

const MyComponent = () => {
    return {
        tag: 'div',
        props: {
            onClick: () => alert('hello')
        },
        children: [
            'click me'
        ]
    }
}

组件的返回值也是一个虚拟dom,他代表了组件要渲染的内容。

用虚拟DOM描述组件,利用对象中的tag值

cpnst vnode = {
    tag: MyComponent
}

渲染器为了能渲染组件,需要做出修改:

function renderer(vnode, container) {
    if (typeof vnode.tag === 'string') {
        // 虚拟dom是标签元素
        mountElement(vnode, container);
    }
    else if (typeof vnode.tag === 'function') {
        // 说明vnode描述的是组件
        mountComponent(vnode, container)
    }
}

function mountComponent(vnode, container) {
    const subtree = vnode.tag()
    renderer(subtree, container)
}
​

也可以用对象描述组件,渲染函数只需修改 typeof vnode.tag === ‘object’。

模板的工作原理

文章开头已经介绍了模板渲染到页面的原理,核心是编译器和渲染器配合完成。

针对一个vue组件(.vue文件就是一个组件)

<template>
    <div @click="handler">
        click me
    </div>
</template>
​
<script>
export default {
    data() {}
    methods: {
        handler: () => {}
    }
}    
</script>

编译器会把模板内容编译成渲染函数并添加到script标签块的组件对象上

// 最中浏览器里运行的代码如下
<script>
export default {
    data() {}
    methods: {
        handler: () => {}
    },
    render() {
        return h('div', {onClick: handler}, 'click me')
    }
}    
</script>

由此也能看出,vuejs是一个编译时+运行时的框架。

备注:结合《VUE.js设计与实现》深入学习vuejs,记录学习过程。

<think>嗯,用户想了解Vue.js设计理念和实现思路。首先,我需要回忆一下Vue的核心概念。记得Vue是渐进式框架,强调响应式系统和组件化开发。它的设计理念可能包括声明式编程、虚拟DOM、数据驱动等。 用户提到了引用[1]和[2],特别是引用[2]中提到的框架设计理念,比如命令式与声明式的区别,虚拟DOM的作用,运行时和编译时的权衡。这些应该是重点。需要解释Vue如何在这些方面做出选择,比如为什么选择声明式,虚拟DOM如何优化性能,以及运行时和编译时的结合。 还要考虑Vue的架构原理,比如响应式系统如何通过Object.defineProperty或Proxy实现数据绑定。组件化方面,单文件组件和生命周期钩子也是关键点。可能还需要提到Vue 3的改进,比如Composition API和性能优化。 用户可能还希望了解Vue设计哲学,比如渐进式采用,可以逐步集成到项目中,而不是全盘接受。同时,需要确保回答结构清晰,分点说明设计理念和架构原理,并引用提供的参考资料中的内容,比如特性开关、错误处理等设计考虑因素。 需要检查是否有遗漏的重要概念,比如虚拟DOM的diff算法、响应式依赖追踪、模板编译过程等。可能还需要比较其他框架(如React或Angular)的不同设计选择,突出Vue的优势和特点。 最后,确保回答符合用户的要求:使用中文,行内公式正确,引用标注正确,并生成相关问题。需要避免技术错误,比如正确区分Vue 2和Vue 3的不同实现(如Proxy vs defineProperty),同时语言要通俗易懂,帮助用户逐步理解。</think>### Vue.js 设计思想与架构原理 #### 一、核心设计理念 1. **渐进式框架** Vue.js 定位于“渐进式框架”,允许开发者从轻量级视图层逐步扩展到复杂应用。例如,可通过 CDN 直接引入核心库实现数据绑定,或结合 Vue Router、Vuex 构建完整单页应用[^2]。 2. **声明式编程与响应式系统** Vue 采用声明式模板语法(如 `{{ data }}`)而非命令式 DOM 操作,通过响应式系统自动追踪依赖。数据变更时,Vue 利用虚拟 DOM 的 diff 算法高效更新视图,公式化表示为: $$ \text{UI} = f(\text{state}) $$ 这一设计减少了开发者手动维护状态与视图同步的负担。 3. **编译时与运行时结合** - **编译时**:将模板编译为渲染函数,支持语法优化(如静态节点提升) - **运行时**:处理虚拟 DOM 的创建、更新与 patch 操作 这种混合模式平衡了开发灵活性和运行性能。 #### 二、核心架构模块 1. **响应式模块** 通过 `Object.defineProperty`(Vue 2)或 `Proxy`(Vue 3)实现数据劫持。当数据变化时,触发依赖的 Watcher 更新视图: ```javascript // Vue 3 响应式简化示例 const reactive = (target) => new Proxy(target, { get(target, key) { track(target, key); return target[key] }, set(target, key, value) { trigger(target, key); return true } }); ``` 2. **虚拟 DOM 与渲染器** 虚拟 DOM 以 JavaScript 对象描述真实 DOM 结构,渲染器通过 `patch` 函数对比新旧虚拟 DOM,公式化表示为: $$ \text{Patch}(V_\text{old}, V_\text{new}) \rightarrow \Delta_\text{DOM} $$ 这种设计减少了直接操作 DOM 的性能损耗。 3. **组件化系统** 单文件组件(`.vue` 文件)将模板、逻辑、样式封装为独立单元,支持组合式 API(Vue 3): ```vue <script setup> import { ref } from &#39;vue&#39;; const count = ref(0); </script> <template> <button @click="count++">{{ count }}</button> </template> ``` #### 三、关键设计权衡 1. **体积控制** 通过 Tree-shaking(Vue 3)实现按需加载,核心运行时仅约 30KB。 2. **开发体验优化** 提供模板语法错误提示、DevTools 集成等,降低调试成本。 3. **特性开关** 编译时可通过配置启用/禁用兼容性特性(如 Options API),平衡新旧版本兼容性与代码体积。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值