基于proxy实现最简单的双向绑定(代码量贼少.jpg

483 阅读1分钟

起因

在我开心摸鱼上班的日子里, phper突然找到我, 问我能不能在标签上写{{}}去渲染字符串, 我当时以为用的字符串模板+动态渲染, 就理所当然的说了句可以, 然后第二天, 找到我, 说不行, 我看了看, emmmmm 好家伙, 原生环境下执行的, 于是我花了半小时一小时, 写了个最简单的demo给他,

PS: 不要问我为什么要phper写页面,

正文:

首先, 我们先new一个proxy, 用于去监听数据改动, 具体文档页面详见:mdn proxy

const data = new Proxy(target, handler)

然后, 在body里新建么几个标签, 同时为了配合proxy, 我们自定义几个attr, 去保证获取的元素的正确性(确定), input为bindvalue, 别问为什么不用bind:value, 绝对不是因为我不知道这么写怎么匹配元素 显示的就用v-text吧

<input bindvalue="name" value="" placeholder="请输入姓名">
<input bindvalue="age" value="" placeholder="请输入年龄">
<div><span>name: </span> <span v-text='name'></span> </div>
<div><span>age</span><span v-text='age'></span></div>

然后, 开始在proxy里写具体代码逻辑,

{
  set: (obj, key, value) => {
    document.querySelectorAll(`*[v-text=${key}]`).forEach(e => {
      e.innerText = value
    })
    return obj[key] = value
  }
}

这里拿取到所有匹配条件的标签, 去动态渲染dom的content, 当然你也可以在这里多做一些骚操作, 具体自己发挥哦, 接下来咱们去新建关于input的事件,

const changeInput = ({target}) => {
  data[target.getAttribute('bindvalue')] = target.value
}

然后在onload里进行一些针对input的处理

window.onload = () => {
 for(let i of document.querySelectorAll('input[bindvalue]')){
   i.oninput = e => changeInput(e)
 }
}

匹配所有input标签上含有bindvalue的attr, 绑定他的oninput事件为刚刚写的changeInput, (都tm2022年了 能不能麻烦某些公司面试的时候再问作用域了啊, nmd看到过最离谱的就是一大串this.a window.a var a = 1 ??? 还有人声明变量还在用var么?)

接下来, 针对input输入框进行一些样式优化,代码嘛就不贴了

总代码大概么也就40行不到,

<!DOCTYPE html>
<header>
  <style>
    input{
      width: 100vw;
      height: 50px;
      color: #f2f2f2;
      border: 1px solid #ccc;
      outline: none;
      color: #999;
      padding:0 20px;
    }
  </style>
</header>
<body>
  
  <input bindvalue="name" value="" placeholder="请输入姓名">
  <input bindvalue="age" value="" placeholder="请输入年龄">
  <div><span>name: </span> <span v-text='name'></span> </div>
  <div><span>age</span><span v-text='age'></span></div>
  <script>
    const data = new Proxy({
      name: ''
    }, {
      set: (obj, key, value) => {
        document.querySelectorAll(`*[v-text=${key}]`).forEach(e => {
          e.innerText = value
        })
        return obj[key] = value
      }
    })
   

    window.onload = () => {
      for(let i of document.querySelectorAll('input[bindvalue]')){
        i.oninput = e => changeInput(e)
      }
    }
    const changeInput = ({target}) => {
      data[target.getAttribute('bindvalue')] = target.value
    }
  </script>
</body>

效果图:

111222.gif

啊哈哈哈哈哈哈。不要问我为什么控制台值改了但是绑定的input没渲染, 当时没想到这一块 绝对不是因为我懒