前段汇总之JS实现数据双向绑定

news2025/6/17 17:54:33

参考vue的关键字:v-model绑定值,{{}},显示值


目录

简单实现双向绑定

 使用Proxy优化双向绑定

动态更新值


简单实现双向绑定

新建html5模板:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>双向数据绑定.v1</title>
</head>
<body>
  
</body>
</html>

然后声明一个H1标签用于展示数据,声明一个input用于输入数据

  显示title:<h1>{{title}}</h1>
  输入title:<input  type="text" v-model="title" />

监听input的值改变,然后设置H1标签新值。

  let inputs = document.querySelectorAll("input");
  let h1s = document.querySelectorAll("h1");
  inputs[0].addEventListener("input",()=>{
    h1s[0].innerHTML=inputs[0].value;
  })

这样只要修改input的值,H1标签就可以实时更新了。

效果如下图所示:

 现在有个问题就是页面初始化或者刷新的时候会出现{{}}里面的变量值,我们可以在页面加载事件的时候把该值置空。代码如下:

  let inputs = document.querySelectorAll("input");
  let h1s = document.querySelectorAll("h1");
  window.onload = ()=>{
    for (let i=0; i<h1s.length; i++) {
        //置空
      h1s[i].innerHTML="";
    }
  }
  inputs[0].addEventListener("input",()=>{
    h1s[0].innerHTML=inputs[0].value;
  })

上面实现并没有跟变量绑定,所以声明一个变量如下:

let data = {
    "title":""
  };

当input的值变化的时候,修改title的值。然后更改H1的标签值

修改监听事件

  inputs[0].addEventListener("input",()=>{
    data.title=inputs[0].value;
    h1s[0].innerHTML=data.title;
  })

这样就实现了数据双向绑定

 使用Proxy优化双向绑定

上面的实现后有一个问题,该变量只跟“唯一”的input进行数据双向绑定了,如果其它逻辑修改了变量值,就不能更新页面了。如下代码所示:

<body>
  显示title:<h1>{{title}}</h1>
  输入title:<input  type="text" v-model="title" />
  <input type="button" value="title+1" />
</body>
  inputs[1].addEventListener("click",()=>{
    data.title+="_1"
  })

当点击新的按钮,title变化后,H1标签并没有变化。所以就要引入Proxy监听对象。

如下修改title的值:

// let data = {"title":""};
let data = new Proxy({"title":""}, {
    get(target, key, receiver) {
        const result = Reflect.get(target, key, receiver)
        console.log('get', key)
        return result; // 返回设置结果
    },
    set(target, key, val, receiver) {
        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        // 更新H1标签
        h1s[0].innerHTML = val;
        return result;
    },
    deleteProperty(target, key) {
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        return result;
    }
})

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>双向数据绑定.v1</title>
</head>

<body>
  显示title:<h1>{{title}}</h1>
  输入title:<input type="text" v-model="title" />
  <input type="button" value="title+1" />
</body>
<script>
  let data = new Proxy({"title":""}, {
    get(target, key, receiver) {
        const result = Reflect.get(target, key, receiver)
        console.log('get', key)
        return result; // 返回设置结果
    },
    set(target, key, val, receiver) {
        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        // 更新H1标签
        h1s[0].innerHTML = val;
        return result;
    },
    deleteProperty(target, key) {
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        return result;
    }
})

  let inputs = document.querySelectorAll("input");
  let h1s = document.querySelectorAll("h1");
  window.onload = () => {
    for (let i = 0; i < h1s.length; i++) {
      h1s[i].innerHTML = "";
    }
  }
  inputs[0].addEventListener("input", () => {
    data.title = inputs[0].value;
    h1s[0].innerHTML = data.title;
  })
  inputs[1].addEventListener("click", () => {
    data.title += "_1"
  })
</script>

</html>

效果如下图:

动态更新值

上面的方式有很多耦合代码,如果有多个双向绑定就要写一堆代码,所以可以再页面加载的时候遍历双向绑定的属性进行关联。

声明对象存储参数和标签的对应关系以及判断{{}}的正则

var regexp = /^{{.*}}$/
const h1Mapping  = {};

首先页面加载事件遍历所有的H1的{{}}(这里仅以H1展示值)

let h1s = document.querySelectorAll("h1");
......
    for (let index = 0; index < h1s.length; index++) {
      const h1 = h1s[index];
      if(regexp.test(h1.innerHTML)){
        let val = h1.innerHTML;
        // 置空
        h1.innerHTML="";
        h1Mapping[val.replace("{{","").replace("}}","")] = h1 ;
      }
    }

然后遍历所有的input包含v-model的:

let inputs = document.querySelectorAll("input[v-model]");
    for (let index = 0; index < inputs.length; index++) {
      const input = inputs[index];
      input.addEventListener('input', function () {
        let val = input.getAttribute("v-model");
        eval(val += "=" + "'" + this.value + "'");
        // updateDataView();
      })
    }

例如input的标签如下:

v-model="data.title"

值改变的时候就会执行js代码

// data.title 等于 input的值
data.title=val

这样就实现了包含v-model的input的值改变后就会对应更新对象的值;

上面保存了变量值和显示标签的对应关系,新增一个方法更新全部视图,如下:

  function updateDataView(_key) {
    if (_key) {
      if (eval(_key)!= undefined) {
        h1Mapping[_key].innerHTML = eval(_key);
      }
    } else {
      for (const key in h1Mapping) {
        if (eval(key)!= undefined) {
          h1Mapping[key].innerHTML = eval(key);
        }
      }
    }
  }

当input值改变的时候,调用改方法,就可以刷新页面。

然后再Proxy值改变监听哪里更新页面,而不是写固定的第一个H1更新值。

  let data = new Proxy({ "title": "" }, {
    get(target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      console.log('get', key)
      return result; // 返回设置结果
    },
    set(target, key, val, receiver) {
      const result = Reflect.set(target, key, val, receiver)
      console.log('set', key, val)
      // 更新html
      updateDataView();
      return result;
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key)
      console.log('delete property', key)
      return result;
    }
  })

HTML代码也更改为调用属性,顺便新增一个name属性,添加一个按钮改变值属性的

显示title:<h1>{{data.title}}</h1>
输入title:<input type="text" v-model="data.title" />
显示name:<h1>{{data.name}}</h1>
输入name:<input type="text" v-model="data.name" />
<input type="button"  value="更改值" onclick="changeValue()" />
  function changeValue(){
    for (const key in data) {
      data[key] = "被改变的值";
    }
  }

运行页面效果如下:

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>双向数据绑定.v1</title>
</head>

<body>
  显示title:<h1>{{data.title}}</h1>
  输入title:<input type="text" v-model="data.title" />
  <br />
  显示name:<h1>{{data.name}}</h1>
  输入name:<input type="text" v-model="data.name" />
  <input type="button"  value="更改值" onclick="changeValue()" />

</body>
<script>
  let data = new Proxy({ "title": "" }, {
    get(target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      console.log('get', key)
      return result; // 返回设置结果
    },
    set(target, key, val, receiver) {
      const result = Reflect.set(target, key, val, receiver)
      console.log('set', key, val)
      // 更新html
      updateDataView();
      return result;
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key)
      console.log('delete property', key)
      return result;
    }
  })

  var regexp = /^{{.*}}$/
  const h1Mapping = {};
  window.onload = () => {
    let h1s = document.querySelectorAll("h1");
    for (let index = 0; index < h1s.length; index++) {
      const h1 = h1s[index];
      if (regexp.test(h1.innerHTML)) {
        let val = h1.innerHTML;
        // 置空
        h1.innerHTML = "";
        //put 对应关系
        h1Mapping[val.replace("{{", "").replace("}}", "")] = h1;
      }
    }

    let inputs = document.querySelectorAll("input[v-model]");
    for (let index = 0; index < inputs.length; index++) {
      const input = inputs[index];
      input.addEventListener('input', function () {
        let val = input.getAttribute("v-model");
        eval(val += "=" + "'" + this.value + "'");
        updateDataView();
      })
    }
  }

  function updateDataView(_key) {
    if (_key) {
      if (eval(_key)!= undefined) {
        h1Mapping[_key].innerHTML = eval(_key);
      }
    } else {
      for (const key in h1Mapping) {
        if (eval(key)!= undefined) {
          h1Mapping[key].innerHTML = eval(key);
        }
      }
    }
  }


  function changeValue(){
    for (const key in data) {
      data[key] = "被改变的值";
    }
  }
</script>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/862616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 文件编辑命令

一、三种模式介绍 命令模式 插入模式(编辑模式) 末行模式 二、模式切换 1.命令模式切换到插入模式 &#xff08;1&#xff09; a //进入到当前光标后开始编辑 &#xff08;2&#xff09; A //进入到当前光标所在行的行末开始编辑 &#xff08;3&#xff09;i //进入当前光…

P450进阶款无人机室内定位功能研测

在以往的Prometheus 450&#xff08;P450&#xff09;无人机上&#xff0c;我们搭载的是Intel Realsense T265定位模块&#xff0c;使用USB连接方式挂载到机载计算机allspark上&#xff0c;通过机载上SDK驱动T265运行并输出SLAM信息&#xff0c;以此来实现室内定位功能。 为进…

Grafana+Prometheus技术文档-进阶使用-监控spring-boot项目

阿丹&#xff1a; 之前已经实现了使用Prometheus来对服务器进行了监控和仪表盘的创建&#xff0c;现在就需要对这些监控方法使用在spring-boot中去。 实现思路&#xff1a; 1、集成Actuator 2、加入Prometheus的依赖 3、配置开放端口、以及开放监控 4、配置Prometheus中的配置…

Talk | ICCV‘23清华大学刘世隆:From Detection to Grounding-迈向更强的开集目标检测

本期为TechBeat人工智能社区第521期线上Talk&#xff01; 北京时间8月10日(周四)20:00&#xff0c;清华大学博士生—刘世隆的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “From Detection to Grounding-迈向更强的开集目标检测”&#xff0c;他分…

法规标准-ISO 17386标准解读(2010版)

ISO 17386是做什么的&#xff1f; ISO 17386全名为交通信息和控制系统-低速运行操纵辅助装置(MALSO)性能要求和试验程序&#xff0c;其中主要描述了低速运行操纵辅助装置的功能要求及试验方法 类别 低速运行操纵辅助装置根据其覆盖不同监测范围的能力进行分类。每个监测范围…

使用雅可比行列式方法求Henon映射的lyapunov exponent

雅可比行列式方法 计算Henon映射的Lyapunov exponent图谱,算法描述为: 0:初始化:初始化用到的值。参数a:[0,1.4],b:0.3,初始值x和y:1,迭代次数M:2000。 1:遍历参数a:计算不同a值所对应的Henon映射的Lyapunov exponent图谱。 2:迭代M次: 计算得到Henon映射的…

苍穹外卖系统07

哈喽&#xff01;大家好&#xff0c;我是旷世奇才李先生 文章持续更新&#xff0c;可以微信搜索【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】更有我为大家准备的福利哟&#xff0c;回复【项目】获取我为大家准备的项目 最近打算把我手里之前做的项目分享给大家&#…

【kubectl详解】

目录 一、陈述式资源管理方法二、基本信息查看1、查看 master 节点状态2、查看命名空间3、查看命名空间的所有资源4、创建命名空间app5、删除命名空间app6、在命名空间kube-public 创建副本控制器&#xff08;deployment&#xff09;来启动Pod&#xff08;nginx-dz&#xff09;…

用MariaDB创建数据库,SQL练习,MarialDB安装和使用

前言&#xff1a;MariaDB数据库管理系统是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可 MariaDB的目的是完全兼容MySQL&#xff0c;包括API和命令行&#xff0c;使之能轻松成为MySQL的代替品。在存储引擎方面&#xff0c;使用XtraDB来代替MySQ…

【Java 集合框架API接口】Collection,List,Set,Map,Queue,Deque

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从跨行业到跨平台 开发工具&#xff1a;IntelliJ IDEA 2021.1.3 Java集合框架 API接口 Collection接口List接口Set接口Map接口Queue接口Deque接口 Java集合API提供了一组功能强大的数据结构和算法, 具有以下作用…

React - useEffect函数的理解和使用

文章目录 一&#xff0c;useEffect描述二&#xff0c;它的执行时机三&#xff0c;useEffect分情况使用1&#xff0c;不写第二个参数 说明监测所有state&#xff0c;其中一个变化就会触发此函数2&#xff0c;第二个参数如果是[]空数组&#xff0c;说明谁也不监测3&#xff0c;第…

外贸路上那些哭笑不得的事情

前几天一个老顾客在软件上联系&#xff0c;说自己上次的订货体验很满意&#xff0c;货物的质量很好&#xff0c;而且服务和回复也很及时&#xff0c; 比起他之前的供货商要好很多&#xff0c;他之前的供货商虽然货物的质量也很好&#xff0c;但是每次询问问题都是要等好久才给…

C++内存管理(new与delete)

这篇文章的主要内容是new与delete的由来&#xff0c;使用new与delete对C堆内存进行管理&#xff0c;(malloc、free)与(new、delete)的区别。希望对C爱好者有所帮助&#xff0c;内容充实且干货&#xff0c;点赞收藏防止找不到&#xff01; 更多C优质内容跳转&#xff1a; 重生之…

问道管理:短线买入点看哪个指标?

在股市投资中&#xff0c;挑选适宜的买入点是至关重要的。短线投资者常常经过技能剖析来确认买入和卖出的时机。技能剖析中有许多目标可供挑选&#xff0c;但怎么挑选适合短线交易的买入点成为一个关键问题。本文将从多个视点剖析&#xff0c;讨论针对短线交易&#xff0c;应该…

C#/.NET/.NET Core优秀项目和框架每周精选开篇

前言 注意&#xff1a;排名不分先后&#xff0c;都是十分优秀的开源项目和框架&#xff0c;每周定期更新分享。 每周精选优秀的C#/.NET/.NET Core项目和框架&#xff0c;帮助开发者发现功能强大、性能优越、创新前沿、简单易用的项目和框架。无论你是寻找灵感、学习新技术、改进…

Redis复制

在Redis中&#xff0c;用户可以通过执行SLAVEOF命令或者设置slaveof选项&#xff0c;让一个服务器去复制(replicate) 另一个服务器&#xff0c;我们称呼被复制的服务器为主服务器(master)&#xff0c;而对主服务器进行复制的服务器则被称为从服务器(slave)&#xff0c;如下图所…

ROS学习--HelloWorld的实现(C++)

1.创建工作空间并初始化 mkdir -p 自定义空间名称/src cd 自定义空间名称 catkin_make上述命令&#xff0c;首先会创建一个工作空间以及一个 src 子目录&#xff0c;然后再进入工作空间调用 catkin_make命令编译。 2.进入 src 创建 ros 包并添加依赖 cd src catkin_create_pk…

面试热题(单词搜索)

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相邻或垂直相…

【软考】2023系统架构设计师考试

目录 1 软考资格设置 2 考试报名 3 考试准备 4 参加考试 5 考试感受 6 其他 1 软考资格设置 2 考试报名 报名网址&#xff1a;https://www.ruankao.org.cn/ 3 考试准备 4 参加考试 2023年下半年系统架构设计师考试时间为11月4、5日。 5 考试感受 6 其他 最近好像有地区…

粉碎文件夹怎么操作?简单4步,轻松完成!

“姐妹们&#xff0c;想问问大家如果想要粉碎文件夹应该怎么操作呀&#xff1f;电脑小白一枚&#xff01;真的很需要一个方法&#xff01;感谢&#xff01;” 在数字化的时代&#xff0c;隐私和数据安全变得尤为重要。当需要彻底删除敏感文件夹时&#xff0c;简单的删除操作可能…