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

参考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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序的api使用 以及一些weui组件实列获取头像 扫码等

今日目标 响应式单位rpx小程序的生命周期 【重点】20%小程序框架 weui 【重点】 50%内置API 【重点】30%综合练习 1. 响应式rpx 1.1 rpx单位 rpx是微信小程序提出的一个尺寸单位&#xff0c;将整个手机屏幕宽度分为750份&#xff0c;1rpx 就是 1/750&#xff0c;避免不同手…

方案展示 | RK3588开发板Android12双摄方案

iTOP-RK3588开发板使用手册更新&#xff0c;后续资料会不断更新&#xff0c;不断完善&#xff0c;帮助用户快速入门&#xff0c;大大提升研发速度。 ​RK3588开发板载4路MIPI CAMERA摄像头接口、MIPI CSI DPHY的4.5Gbps、2.5Gops的MIPI CSI CPHY&#xff0c;四路同时输入&#…

爬虫018_urllib库_cookie反爬_post请求百度翻译获取百分翻译内容_以及详细翻译内容---python工作笔记037

然后我们来看如何用urllib发送post请求,这里我们 用百度翻译为例 我们翻译一个spider,然后我们看请求,可以看到有很多 找到sug这个 可以看到这里的form data,就是post请求体中的内容 然后我们点击preview其实就是 返回的实际内容 然后请求方式用的post 然后我们把上面的信息…

Java 常用编辑器 IntelliJ IDEA

文章目录 IDEA 概述IDEA 下载和安装IDEA 中的第一个代码IDEA 的项目和模块操作&#xff08;一&#xff09;类的操作&#xff08;二&#xff09;模块的操作&#xff08;三&#xff09;项目的操作 IDEA 概述 IntelliJ IDEA是一款由JetBrains开发的集成开发环境&#xff08;IDE&am…

东南亚海外跨境物流管理,移动支付、数据处理程序开发

境外虚拟物流跨境支付平台快速搭建、集成后台采集功能的步骤如下&#xff1a; 一、项目规划与需求分析 在开始搭建境外虚拟物流跨境支付平台之前&#xff0c;需要进行详细的规划和分析。这包括确定项目的目标、了解客户需求、分析市场环境、确定系统架构和技术选型等。通过深…

手机便签中可以打勾的圆圈或小方块怎么弄?

在日常的生活和工作中&#xff0c;很多网友除了使用手机便签来记录灵感想法、读书笔记、各种琐事、工作事项外&#xff0c;还会用它来记录一些清单&#xff0c;例如待办事项清单、读书清单、购物清单、旅行必备物品清单等。 在按照记录的清单内容来执行的时候&#xff0c;为了…

RabbitMQ 79b5ad38df29400fa52ef0085a14b02f

RabbitMQ 一、什么是消息队列 消息队列可以看作是一个存放消息的容器&#xff0c;其中&#xff0c;生产者负责生产数据到消息队列中&#xff0c;而消费者负责消费数据。消息队列是分布式系统中重要的组件&#xff0c;目前使用较多的消息队列有ActiveMQ&#xff0c;RabbitMQ&am…

http、https笔记

目录 HTTP 基本概念状态码&#xff1a;get和post的区别&#xff1a;http 常⻅字段&#xff1a;http的缺点&#xff1a; HTTP/1.1HTTP/3HTTPSHTTPS和HTTP区别对称加密和⾮对称加密⾮对称加密 HTTP 基本概念 状态码&#xff1a; 1xx 中间状态&#xff0c;比如post的continue 20…

【LeetCode】1572.矩阵对角线元素的和

题目 给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&#xff1a; 输入&#xff1a;mat [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;25 解释&#xff1a;对角线的和为&a…

3.4 网络安全管理设备

数据参考&#xff1a;CISP官方 目录 IDS (入侵检测系统)网络安全审计漏洞扫描系统VPN&#xff08;虚拟专网&#xff09;堡垒主机安全管理平台 一、IDS (入侵检测系统) 入侵检测系统&#xff08;IDS&#xff09;是一种网络安全设备&#xff0c;用于监测和检测网络中的入侵行…

nginx编译以及通过自定义生成证书配置https

1. 环境准备 1.1 软件安装 nginx安装编译安装以及配置https&#xff0c;需要gcc-c pcre-devel openssl openssl-devel软件。因此需要先安装相关软件。 yum -y install gcc-c pcre-devel openssl openssl-devel wgetopenssl/openssl-devel&#xff1a;主要用于nginx编译的htt…

Docker安装Hadoop分布式集群

一、准备环境 docker search hadoop docker pull sequenceiq/hadoop-docker docker images二、Hadoop集群搭建 1. 运行hadoop102容器 docker run --name hadoop102 -d -h hadoop102 -p 9870:9870 -p 19888:19888 -v /opt/data/hadoop:/opt/data/hadoop sequenceiq/hadoop-do…

windows环境下编译OpenJDK12

环境&#xff1a;Windows11 目录&#xff1a; 1、下载OpenJDK12源码 下载地址&#xff1a; https://hg.openjdk.org/jdk/jdk12 点击zip下载到本地。 解压到本地。 Tip&#xff1a;注意本地路径中最好不要包含中文或空格。 2、阅读一遍doc/building.html 如果只是想构建J…

数组对象去重的几种方法

场景&#xff1a; let arrObj [{ name: "小红", id: 1 },{ name: "小橙", id: 1 },{ name: "小黄", id: 4 },{ name: "小绿", id: 3 },{ name: "小青", id: 1 },{ name: "小蓝", id: 4 } ]; 方法一&#xff1a;…

2023年第2季社区Task挑战赛升级新玩法,等你来战!

第1季都有哪些有趣的作品&#xff1f; 在大家的共建下&#xff0c;FISCO BCOS开源生态不断丰富完善&#xff0c;涌现了众多实用技术教程和代码&#xff1a;基于数字身份凭证的业务逻辑设计&#xff0c;贡献了发放数字身份凭证的参考实现&#xff1b;提供企业碳排放、慈善公益等…

【基础类】—原型链系统性知识

一、创建对象有几种方法 字面量创建对象 1-1. 什么是字面量 字面量就是所见即所&#xff0c;指的是常量&#xff1b;用来为变量赋值时的常数量 代码例子&#xff1a;123&#xff1b;‘ABC’, {name: ‘张三’}, undefined &#xff0c; true 生活例子&#xff1a;门店的招牌&a…

[C++项目] Boost文档 站内搜索引擎(4): 搜索的相关接口的实现、线程安全的单例index接口、cppjieba分词库的使用、综合调试...

有关Boost文档搜索引擎的项目的前三篇文章, 已经分别介绍分析了: 项目背景: &#x1fae6;[C项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍…文档解析、处理模块parser的实现: &#x1fae6;[C项目] Boost文档 站内搜索引擎(2): 文档文本解析模块…

CDN(内容分发网络)

CDN的全称是 Content Delivery Network, 即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发、调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c;降低网络拥塞&a…

CentOS7 安装 MongoDB5

MongoDB是一种NoSQL数据库&#xff0c;它存储数据的方式与传统的关系型数据库不同。MongoDB使用文档数据库模型&#xff0c;将数据存储在自包含的、可扩展的BSON文档中。MongoDB具有高可用性、自动分片、动态查询能力、灵活性等优点&#xff0c;适合于许多不同的应用场景。 下…