【vue高频面试题—基础篇】:vue的基本原理。

158 阅读3分钟

Vue.js 是一个构建用户界面的渐进式 JavaScript 框架。以下是它的基本原理:

响应式原理

  • 数据劫持(Object.defineProperty)

    • Vue.js 在初始化阶段会遍历 data 对象中的所有属性。对于每个属性,使用Object.defineProperty()方法进行数据劫持。这意味着它可以在访问或修改属性时进行拦截。例如,当定义一个名为message的属性时,Vue.js 会将这个属性转换为具有gettersetter的形式。

    • 当读取message属性(通过this.message)时,getter函数被调用,返回属性的值。当修改message属性(如this.message = '新的值')时,setter函数被触发。在setter函数中,Vue.js 会通知相关的依赖(例如模板中使用了message的部分)进行更新。

    • 例如:

let data = {
    count: 0
};
let _count = data.count;
Object.defineProperty(data, 'count', {
    get: function () {
        return _count;
    },
    set: function (newValue) {
        _count = newValue;
        // 这里可以触发更新视图的操作
    }
});
  • 依赖收集

    • 当编译模板时,Vue.js 会解析模板中的表达式(如{{ message }})。对于每个表达式中用到的数据属性,会建立一个依赖关系。这些依赖关系会被收集起来存储在一个依赖收集器中。
    • 例如,在一个组件的模板中有<p>{{ name }}</p>,当解析这个模板时,Vue.js 会发现它依赖于name这个数据属性,然后将这个依赖关系记录下来。
    • 当数据发生变化(通过setter触发),Vue.js 会遍历所有收集到的依赖,通知它们进行更新。这些依赖通常是和 DOM 更新相关的操作,比如更新某个元素的文本内容或者属性。

虚拟 DOM(Virtual DOM)

  • 创建虚拟 DOM 树

    • 虚拟 DOM 是对真实 DOM 的一种抽象表示。在 Vue.js 中,首先会根据组件的模板或者渲染函数创建一个虚拟 DOM 树。虚拟 DOM 树是一个 JavaScript 对象,它的结构类似于真实 DOM 树的结构。

    • 例如,对于一个简单的 HTML 模板<div><p>Hello</p></div>,其虚拟 DOM 树可能是一个类似于下面的 JavaScript 对象:

{
    tag: 'div',
    children: [
        {
            tag: 'p',
            text: 'Hello'
        }
    ]
}
  • 对比虚拟 DOM 差异(Diff 算法)

    • 当数据发生变化导致组件需要重新渲染时,Vue.js 会再次生成一个新的虚拟 DOM 树。然后,通过 Diff 算法来比较新旧虚拟 DOM 树的差异。
    • Diff 算法会尽量高效地找出需要更新的部分。它采用了一些优化策略,比如只比较同层级的节点,对节点进行类型判断(如果节点类型不同,直接替换)等。
    • 例如,如果原来的虚拟 DOM 树中有一个<p>Hello</p>节点,新的虚拟 DOM 树中这个节点变为<p>Hi</p>,Diff 算法会发现这个文本内容的差异,并且只会更新这个p节点的文本,而不是重新渲染整个div及其子节点。
  • 更新真实 DOM

    • 根据 Diff 算法得到的差异,Vue.js 会将这些更新应用到真实 DOM 上。这个过程是批量的、高效的,避免了频繁地直接操作真实 DOM,从而提高性能。
    • 例如,如果发现一个元素的属性需要更新,Vue.js 会使用 DOM API(如setAttribute)来更新真实 DOM 元素的属性;如果是添加或删除节点,会使用appendChildremoveChild等方法。

组件化

  • 组件定义

    • Vue.js 允许用户将页面拆分成一个个独立的组件。一个组件可以是一个具有特定功能的小模块,它包含了模板(template)、数据(data)、方法(methods)等部分。

    • 例如,定义一个简单的按钮组件:

Vue.component('my-button', {
    template: '<button @click="handleClick">{{ buttonText }}</button>',
    data: function () {
        return {
            buttonText: 'Click me'
        };
    },
    methods: {
        handleClick: function () {
            console.log('Button clicked');
        }
    }
});
  • 组件通信

    • 父子组件之间可以通过属性(props)和事件($emit)进行通信。父组件可以通过属性向子组件传递数据,子组件可以通过触发事件向父组件传递消息。

    • 例如,父组件向子组件传递一个message属性:

<parent-component>
    <child-component :message="parentMessage"></child-component>
</parent-component>
  • 子组件接收这个属性并使用:

Vue.component('child-component', {
    props: ['message'],
    template: '<div>{{ message }}</div>'
});
  • 子组件通过事件向父组件传递消息:

Vue.component('child-component', {
    template: '<button @click="sendMessage">Send Message</button>',
    methods: {
        sendMessage: function () {
            this.$emit('message-sent', 'Hello from child');
        }
    }
});
  • 父组件接收子组件发送的事件:

<parent-component>
    <child-component @message-sent="handleMessage"></child-component>
</parent-component>
  • 这样,通过组件化的方式,可以方便地构建大型应用,各个组件可以独立开发、测试和维护。

总结:响应式原理,虚拟dom,组件化,构建了vue的基本原理