vue -- 虚拟dom

137 阅读2分钟

这是我参与11月更文挑战的第22天, 活动详情查看:2021最后一次更文挑战

承接上文:vue双向绑定

先说下vue里面用到es6的语法:proxy

在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。参考阮大神的 es6入门

question:能否监听对象属性的删除操作? 基于proxy实现一下响应式。

let observeStore = new Map();

function markObservable(target){
    let handleName = Symbol('handle');
    observeStore.set(handleName, []);
    target.observe = function(handle){
        observeStore.get(handleName).push(handle);
    }
    const proxyHandler = {
        get(target,property,receiver){
            if(typeof target[property] === 'object' && target[property] !== null){
                return new Proxy(target[property],proxyHandler);
            }

            let success = Reflect.get(...arguments); // 对原来数据的一个映射
            if(success){
                observeStore.get(handleName).forEach(handle => handle('GET',property,target[property]))
            }
            return success;
        },
        set(target,prototype,receiver){
            let success = Reflect.set(...arguments);
            if(success){
                observeStore.get(handleName).forEach(handler => handler('SET', property, value));
            }
            return success;
        },
        deleteProperty(target,property){
            let success = Reflect.deleteProperty(...arguments);
            if(success){
                observeStore.get(handleName).forEach(handler => handler('DELETE', property));
            }
            return success;
        }
    };

    // 创建proxy,拦截更改
    return new Proxy(target,proxyHandler);
};

let user = {};

user = markObservable(user); // 已经是响应式的

user.observe((action,key,value) => {
    console.log(`${action} key=${key} value=${value || ''}`);
});

user.name = 'John'; // SET key=name value=John
console.log(user.name); // GET key=name value=John // John
delete user.name; // DELETE key=name value

你了解虚拟DOM吗?能说一下它的优缺点吗?

什么是虚拟dom?其实就是js对象。

即:对于真实DOM的抽象,用嵌套对象表示,用属性来描述节点,最终通过一系列操作映射到真实dom上

虚拟dom优点
  1. 保证性能下限。在不通过手动优化的前提下,也能提供过得去的性能。
  2. 无需手动操作dom
  3. 跨平台

虚拟dom本质上其实就是一个js对象,它可以很方便的跨平台了,比如服务端渲染 比如 uniapp

缺点
  • 首次渲染大量dom的对象,由于多了一层虚拟DOM的计算,会比innerHTML的插入速度慢
  • 做一些针对性的优化时,真实dom的操作还是会更快一些。

question: 给你一段数据结构,将其转换为真实dom

const vnode = {
    tag: 'DIV',
    attrs: {
        id: 'app'
    },
    children: [
        {
            tag: 'SPAN',
            children: []
        },
        {
            tag: 'SPAN',
            children: [{
                tag: 'A',
                children: []
            },
            {
                tag: 'A',
                children: []
            }]
        }
    ]
}

function render (vnode) {
    if(typeof vnode === 'number'){
        vnode = String(vnode);
    }
    if(typeof vnode === 'string'){
        return document.createTextNode(vnode);
    }
    const element = document.createElement(vnode.tag);
    if(vnode.attrs){
        Object.keys(vnode.attrs).forEach(attrKey => {
            element.setAttribute(key,vnode.attrs[attrKey])
        })
    }
    // 开始递归
    if(vnode.children){
        vnode.children.forEach(childNode => {
            element.appendChild(render(childNode));
        })
    }
    return element;
}