手撸一个虚拟DOM,不错(1)

  • type参数描述了 HTML 元素的类型,例如h1div等等…

  • props参数的工作方式与 React/Vue 中的 props 完全相同——它允许我们将数据(属性)传递给元素

  • children当前元素内其他子节点。

让我们看看它是如何使用的。




const view = () =>

  h('div', {}, [

    h('h1', {}, ['Hello']),

    h('p', {}, ['from virtual DOM!']),

    h('p', {}, ['from virtual DOM!']),

    h('p', {}, ['from virtual DOM!']),

    h('p', {}, ['from virtual DOM!']),

  ]);



我们创建了一个div元素,里面有h1p元素。这些元素中的每一个都有一个文本节点作为其子节点。

现在是时候将这个虚拟树转换为实际的 DOM。

render方法

让我们实现一个render功能。




const render = (root, view) => {

    const rendered = view();



    diff(root, null, rendered);

};



const diff = (root, oldNode, newNode, index) => {

    // 判断节点是否变化,有变化则更新

    

};



render(app, view);



渲染函数首先调用view函数,然后运行 diff 函数,该函数接受一个根元素(来自真实 DOM)、旧的虚拟节点(因为我们第一次渲染它是null)和新的虚拟节点 。

diff方法

基本上,该diff函数只会将 oldNode 与 newNode 进行比较,看看它是否需要更新root.

现在让我们看看如何实现 diff 函数。


const diff = (root, oldNode, newNode, index) => {

    // 判断节点是否变化,有变化则更新

    if (!oldNode) {

        root.appendChild(createElement(newNode));

    }

};





如果没有oldNode,我们需要创建这个元素并将其插入 DOM。首先,我们使用该函数创建一个元素createElement,然后我们在第二个实现该函数,然后我们appendChild在一个真实的 DOM 元素上使用该方法,将该节点附加为其子节点。

让我们实现createElement功能。


const createElement = (node) => {

    if (typeof node === 'string') {

        return document.createTextNode(node);

    }



    const el = document.createElement(node.type);

    node.children.map(createElement).forEach(el.appendChild.bind(el));



    return el;

};



如果一个节点是一个文本节点(例如“Hello”),我们只需使用document.createTextNode函数渲染它。

如果不是,我们创建给定类型的元素,document.createElement然后循环遍历它的每个子元素,createElement递归调用函数。这样我们就创建了整个树并返回它。

让我们看看到目前为止我们编写的完整代码:




const app = document.querySelector('#app');



const h = (type, props = {}, children = []) => ({

    type,

    props,

    children,

});



const view = () =>

    h("div", {}, [

        h("h1", {}, ["Hello"]),

        h("p", {}, ["from virtual DOM!"]),

        h("p", {}, ["from virtual DOM!"]),

        h("p", {}, ["from virtual DOM!"]),

        h("p", {}, ["from virtual DOM!"]),

    ]);



const render = (root, view) => {

    const rendered = view();



    diff(root, null, rendered);

};



const diff = (root, oldNode, newNode, index) => {

    // 判断节点是否变化,有变化则更新

    if (!oldNode) {

        root.appendChild(createElement(newNode));

    }

};



const createElement = (node) => {

    if (typeof node === 'string') {

        return document.createTextNode(node);

    }



    const el = document.createElement(node.type);

    node.children.map(createElement).forEach(el.appendChild.bind(el));





##### 框架相关

原生JS虽能实现绝大部分功能,但要么就是过于繁琐,要么就是存在缺陷,故绝大多数开发者都会首选框架开发方案。现阶段较热门是React、Vue两大框架,两者工作原理上存在共通点,也存在一些不同点,对于校招来说,不需要两个框架都学得特别熟,一般面试官会针对你简历中写的框架进行提问。

在框架方面,**生命周期、钩子函数、虚拟DOM这些基本知识是必须要掌握的**,在学习的过程可以结合框架的官方文档



**Vue框架**

>**知识要点:**
>**1. vue-cli工程**
>**2. vue核心知识点**
>**3. vue-router**
>**4. vuex**
>**5. http请求**
>**6. UI样式**
>**7. 常用功能**
>**8. MVVM设计模式**

![](https://img-blog.csdnimg.cn/img_convert/9fcd79fec5cb04f5569049d8dc54fc24.webp?x-oss-process=image/format,png)


**React框架**

>**知识要点:**
>**1. 基本知识**
>**2. React 组件**
>**3. React Redux**
>**4. React 路由**

![](https://img-blog.csdnimg.cn/img_convert/b89759c33b9e0856d7c66ab0f1b5ee7c.webp?x-oss-process=image/format,png)

ue核心知识点**
>**3. vue-router**
>**4. vuex**
>**5. http请求**
>**6. UI样式**
>**7. 常用功能**
>**8. MVVM设计模式**

[外链图片转存中...(img-h366VflJ-1718099990756)]


**React框架**

>**知识要点:**
>**1. 基本知识**
>**2. React 组件**
>**3. React Redux**
>**4. React 路由**

[外链图片转存中...(img-zUYlyb8Z-1718099990757)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值