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

手写MVVM框架-实现v-model(单向绑定)

开始之前我们先修复一下之前的一个BUG、由于我们使用了html-webpack-plugin并且配置了html模板,所以在html模板里面就不需要再引用打包后的bundle.js了,webpack打包时会自动添加上去,不然的话就会导致调用两遍初始化方法!

修改了index页面的UI并且删除了手动引用的bundle.js

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            * {
                padding: 0;
                margin: 0;
                box-sizing: border-box  
            }
            #container {
                width: 100%;
                height: 100vh;
                display: flex;
                align-items: center;
                flex-direction: column;
                padding-top: 20%
            }
            .inputItems {
                width: 100%;
                display: flex;
                flex-direction: column;
                align-items: center;
                margin-top: 50px;
            }
            .inputItems .inputItem {
                border: 1px solid #ccc;
                padding: 5px 10px;
                width: 80%;
                border-radius: 23px;
                margin-top: 30px;
                height: 40px;
                display: flex;
                align-items: center;
            }
            .inputItems .inputItem input {
                border: none;
                outline: none;
                text-align: center;
                width: 100%;
            }
            .fixInfo {
                position: fixed;
                bottom: 3%;
                color: #878787;
                font-size: 12px;
            }
            button {
                width: 80%;
                background-color: #eacc20;
                height: 40px;
                border-radius: 23px;
                margin-top: 50px;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div>{
  
  {title}}</div>
            
            <div class='inputItems'>
                <div class='inputItem'>
                    <input v-model="user.account" placeholder='请输入登录账号'/>
                    <div>{
  
  {user.account}}</div>
                </div>
                <div class='inputItem'>
                    <input v-model="user.password" placeholder='请输入登录密码'/>
                    <div>{
  
  {user.password}}</div>
                </div>
            </div>
            <button>登录</button>
            <div class='fixInfo'>{
  
  {info.name}} {
  
  {info.version}}</div>
        </div>
    </body>
</html>

现在的效果是这样

现在开始实现v-model

实现双向绑定的原理就是构建虚拟dom时,检查当前节点是否含有v-model节点,如果有当前v-model的话就给这个输入标签添加一个input事件或者change事件

我们现在创建一个directive文件夹并且添加一个vmodel.js

import { setObjectValue } from '../../utils/ObjectUtils.js'

/**
 * 注册v-model指令
 */
export function VModel(vm, node, key) {
    // 如果不是元素节点直接返回
    if(node.nodeType != 1) return;
    // 监听元素的onchange事件
    node.oninput = function(e) {
        setObjectValue(vm, key, node.value)
    }
}

并且添加一个ObjectUtils.js 用于给data中的属性设置值

/**
 * 设置Object中的值
 * @param {Object} obj 
 * @param {String} key a, obj.a
 */
export function setObjectValue(obj, keys, value) {
    if(!obj) return obj
    let keyList = keys.split('.')
    let temp = obj;
    for(let i = 0; i < keyList.length -1; i++) {
        if(temp[keyList[i]]) {
            temp = temp[keyList[i]]
        }
    } 
    if(temp[keyList[keyList.length -1]] != null) {
        temp[keyList[keyList.length -1]] = value
    }
}

第二步:input事件添加v-model解析

我们在构建虚拟节点的时候,检测节点是否有v-model属性,检测到了之后就添加调用v-model,当前代码只支持input的双向绑定,如果需要其他标签,请自行添加

/**
 * 构建虚拟dom
 * @param {} vm
 * @param {} el
 * @param {} parent
 */
function constructVnode(vm, el, parent) {
    analysisNodeAttr(vm, el)
    ...其他代码
}

/**
 * 解析Node属性值
 * @param {*} vm 
 * @param {*} vnode 
 * @returns 
 */
function analysisNodeAttr(vm, node) {
    if(node.nodeType != 1) return
    let attrList = node.getAttributeNames();
    if(attrList.includes("v-model")) {
        VModel(vm, node, node.getAttribute("v-model"));
    }
}

现在我们访问页面看效果

从页面上可以看到:

1.我们输入账号密码之后,控制台输出了,说明v-model添加的input事件已经失效

2.账号密码框右侧的模板发生了变化,说明新输入的值已经渲染到了页面上

本章总结:

1.收集依赖时,添加分析元素节点(nodeType == 1)的代码,并添加模板的依赖

2.创建directive文件和vmodel.js,给元素绑定input事件,并修改实例的值

3.构建虚拟dom时,如果是元素节点并且有v-model属性,给调用vmodel方法


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

相关文章:

  • 快速傅里叶离散变换FFT (更新中)
  • k8m 是一款轻量级、跨平台的 Kubernetes 仪表板
  • 0205算法:最长连续序列、三数之和、排序链表
  • 从BIO到NIO:Java IO的进化之路
  • K8S学习笔记-------1.安装部署K8S集群环境
  • 【零基础到精通】小白如何自学网络安全
  • rabbitMQ数据隔离
  • 1 HBase 基础
  • PHP 中 `foreach` 循环结合引用使用时可能出现的问题
  • 【C++】STL——vector的使用
  • 【自然语言处理(NLP)】生成词向量:ELMo(Embedded from Language Models)原理及应用
  • 硬件电路基础
  • 每日Attention学习20——Group Shuffle Attention
  • DeepSeek-V3 大模型哪些地方超越了其他主流大模型
  • 中国通信企业协会 通信网络安全服务能力评定 风险评估二级要求准则
  • 保姆级教程Docker部署Zookeeper官方镜像
  • FPGA学习篇——Verilog学习1
  • Shell条件变量替换
  • PySpark学习笔记5-SparkSQL
  • 在游戏本(6G显存)上本地部署Deepseek,运行一个14B大语言模型,并使用API访问
  • 记录debian12运行时出现卡死的问题
  • http状态码:请说说 503 Service Unavailable(服务不可用)的原因以及排查问题的思路
  • Windows Docker笔记-简介摘录
  • Java synchronized锁升级
  • 算法与数据结构(括号匹配问题)
  • w192中国陕西民俗网的设计与实现