当前位置: 首页 > article >正文

手写MVVM框架-渲染v-for列表(修改List)

上一章我们实现了初始渲染时渲染了v-for列表,这一章我们来实现修改list后重新渲染list

实现步骤:

1.收集依赖时添加上对虚拟节点的依赖收集(前提)

2.从Object.defineProperty中劫持到数据变化调用重新渲染的rebuild方法

3.rebuild实现:先获取模板关联的依赖节点,遍历每一个节点(虚拟节点),清空虚拟节点父级(UL)中的html,然后把当前虚拟节点的dom重新添加到当前虚拟节点的父节点(UL), 此时因为数据发生了变化,所以虚拟节点下挂载的真实节点失效,根据这个真实节点(LI)重新虚拟节点,构建完成后,把当前的虚拟节点添加到父节点UL的children中

4.因为list发生了变化并且重新生成了虚拟节点,所以之前收集的依赖失效,需要清空依赖重新调用prepareRender方法

4.依赖收集完成之后,重新渲染当前虚拟节点

代码实现:

/**
 * 代理执行数组方法
 * @param {*} obj 
 * @param {*} func 
 * @param {*} namespace 
 */
function defineProxyMethod(obj, func, namespace) {
    const vm = this
    Object.defineProperty(obj, func, {
        configurable: true, // 可配置
        enumerable: true, // 可枚举
        value: function() {
            // 获取执行方法
            let method = arrayProto[func]
            // 执行数组方法获取返回结果
            let result = method.call(this, ...arguments) 
            // 重新收集依赖渲染节点
            rebuild(vm, getNameSpace(namespace, ''))
            return result; // 返回执行结果
        }
    })
}


export function prepareRender(vm, vnode) {
    if(vnode == null) {
        return null;
    }
    // 如果是文本节点
    if(vnode.nodeType == 3) {
        // 解析文本节点,并记录模板与节点之间的关系
        analysisTemplateString(vnode);
    }
    // 如果是元素节点
    if(vnode.nodeType == 1) {
        analysisAttr(vm, vnode);
    }
    // 收集虚拟节点的依赖
    if (vnode.nodeType == 0) {
        setTemplateToVnode("{
  
  {" + vnode.data + "}}", vnode);
        setVnodeToTemplate("{
  
  {" + vnode.data + "}}", vnode);
    }
    // 循环遍历子节点
    for (let i = 0 ; i < vnode.children.length ; i ++) {
        prepareRender(vm, vnode.children[i]);
    }
}

export function rebuild(vm, data) {
    // 获取当前data关联的vnode数据
    const nodes = templateToNode.get(data)
    nodes && nodes.forEach((node)=> {
        // 清空父级的innerHTML
        node.parent.ele.innerHTML = ""
        // 重新设置父级的html
        node.parent.ele.appendChild(node.ele)
        // 重新渲染节点
        const vnode = constructVnode(vm, node.ele, node.parent)
        // 给父级(UL)添加children
        node.parent.children = [vnode]
        // 清空失效的依赖
        clearMap()
        // 重新收集依赖
        prepareRender(vm, vm._vnode)
        // 重新渲染节点
        renderNode(vm, vnode)
    })
}

我们在浏览器上或者在页面上添加一个事件向list中追加一个元素看效果

 


http://www.kler.cn/a/535060.html

相关文章:

  • Yageo国巨的RC系列0402封装1%电阻库来了
  • 逻辑起源 - 比较DS与豆包对“逻辑”源头的提炼差异
  • 备考蓝桥杯嵌入式4:使用LCD显示我们捕捉的PWM波
  • 硬件电路基础
  • 【Elasticsearch】文本分类聚合Categorize Text Aggregation
  • 电梯系统的UML文档14
  • VUE 集成企微机器人通知
  • hot100(8)
  • 《工业4.0时代?!》
  • 【Flutter】【WEB3】判断一个String是不是钱包地址
  • Linux——基础命令1
  • 线程同步时定义 std::mutex 为什么要在前面添加 mutable 关键字
  • 旋转变压器工作及解调原理
  • Vue3-管理状态 effectScope
  • OpenAI向所有用户开放ChatGPT搜索,无需账号登录
  • 网络工程师 (20)计算机网络的概念
  • [SAP ABAP] 面向对象程序设计-构造方法
  • SpringCloud基础 入门级 学习SpringCloud 超详细(简单通俗易懂)
  • 为什么使用springboot框架,springboot常用的配置文件,如何读取配置文件中自定义的内容,多环境下如何切换配置文件,包扫描原理,自动装配的原理
  • 变压器-000000
  • Android性能调优之需要掌握Dalvik和ART的知识
  • win编译openssl
  • 前部分知识复习05
  • 机器学习大模型问题记录
  • ESP-Skainet智能语音助手,ESP32-S3物联网方案,设备高效语音交互
  • 《图解设计模式》笔记(五)一致性