按键事件后输入值未改变

3
我正在构建/尝试构建自己的小型框架。
最终,我将元素的值传递给keypress方法,它可以工作,但问题是我始终拥有我的初始值“test”。
那么为什么console.log没有显示我更新后的文本?

let initialProps = {
   change(text) {
      console.log(text);
   }
}

document.querySelectorAll("[keypress]").forEach(element => {
  this.keyHandler(element);
});
function keyHandler(element) {
  let handler = element.attributes.keypress.nodeValue;

  element.addEventListener(
    "keypress",
    initialProps[handler].bind(
      null,
      element.nodeName === "INPUT" ? element.value : undefined
    )
  );
}
<input keypress="change" value="test" type="text" />

以下是完整的代码

setTimeout(()=>{
  new Tinyflow({
    name: "Max",
    age: 21,
    state: true,
    text: "",
    myTrans: "slide",
    increaseAge() {
      this.age++
    },
    toggle() {
      this.state = !this.state
    },
    changedText(text){
      this.text = text;
    },
    observers: {
      age(oldVal) {   
      }
    }
  });
})








class Tinyflow {
  constructor(properties) {
    console.time();
    this.reactivityHandler = {
      get: function(obj, prop) {
        return obj[prop];
      }.bind(this),
      set: function(obj, prop, newVal) {
        let oldVal = obj[prop];
        obj[prop] = newVal;
        if (prop in this.reactiveProps["observers"]) {
          this.reactiveProps["observers"][prop].call(
            this.reactiveProps,
            oldVal
          );
        }

        let i = this.reactiveElements.findIndex(el => el.var === "$" + prop);
        if (i !== -1) {
          this.renderSingleNode(i, newVal);
        }

        if (prop in this.showElements) {
          this.updateVisibility(this.showElements[prop], newVal);
        }
      }.bind(this)
    };
    if ("observers" in properties) {
      if (typeof properties["observers"] !== "object")
        throw Error("Observers needs to be an Object");
      for (let prop in properties["observers"]) {
        if (typeof properties["observers"][prop] !== "function")
          throw Error("An property inside observers is not an method: " + prop);
        if (!(prop in properties))
          throw Error(
            "Observer " +
              prop +
              " has nothing to observer. Add an property to observe"
          );
      }
    }
    this.initialProps = properties;
    this.reactiveProps = new Proxy(this.initialProps, this.reactivityHandler);
    this.reactiveElements = [];
    this.showElements = {};
    this.listenerRemover = null;
    this.collectHandlers();
    this.collectVariables();
    this.renderAllNodes();
    this.collectShowElements();
    console.timeEnd();
  }
  updateVisibility(elements, state) {
    if (state) {
      elements.forEach(elementProperties => {
        let { displayProperty, element } = elementProperties;
        let cssClassAvailable = element.attributes.trans;

        if (cssClassAvailable) {
          element.removeEventListener("transitionend", this.listenerRemover);
          let cssClass = this.reactiveProps[cssClassAvailable.nodeValue];
          setTimeout(() => {
            element.classList.remove(cssClass);
          });
          element.style.setProperty("display", displayProperty);
        } else {
          element.style.setProperty("display", displayProperty);
        }
      });
    } else {
      elements.forEach(elementProperties => {
        let { element } = elementProperties;
        let cssClassAvailable = element.attributes.trans;

        if (cssClassAvailable) {
          let cssClass = this.reactiveProps[cssClassAvailable.nodeValue];

          element.classList.add(cssClass);
          function removeListener() {
            element.style.setProperty("display", "none");
            element.removeEventListener("transitionend", this.listenerRemover);
          }
          this.listenerRemover = removeListener;
          element.addEventListener("transitionend", this.listenerRemover);
        } else {
          element.style.setProperty("display", "none");
        }
      });
    }
  }
  collectShowElements() {
    document.querySelectorAll("[show]").forEach(element => {
      let attributes = element.attributes;
      let stateVar = attributes.show.nodeValue;

      let displayProperty =
        window.getComputedStyle(element).getPropertyValue("display") === "none"
          ? "block"
          : window.getComputedStyle(element).getPropertyValue("display");

      if (this.showElements[stateVar]) {
        this.showElements[stateVar].push({
          element,
          displayProperty
        });
        if (!this.initialProps[stateVar]) {
          element.style.setProperty("display", "none");
        }
        return;
      }
      this.showElements[stateVar] = [
        {
          element,
          displayProperty
        }
      ];
      if (!this.initialProps[stateVar]) {
        element.style.setProperty("display", "none");
      }
    });
  }
  renderSingleNode(index, newVal) {
    let elements = this.reactiveElements;
    let value = elements[index].varValue;
    if (value === newVal) return;
    elements[index].varValue = newVal;

    elements[index].reference.forEach(ref => {
      let original = ref.originalText;
      ref.vars.forEach(vari => {
        let varWithoutDollar = vari.replace("$", "");
        let regex = new RegExp("\\" + vari, "g");
        if (varWithoutDollar === newVal) {
          original = original.replace(regex, newVal);
          return;
        }

        original = original.replace(regex, this.initialProps[varWithoutDollar]);
      });
      ref.element.innerHTML = original;
    });
  }
  renderAllNodes() {
    this.reactiveElements.forEach(element => {
      let variable = element.var;
      let varWithoutDollar = element.var.replace("$", "");

      element.reference.forEach(ref => {
        let regex = new RegExp("\\" + variable, "g");
        ref.element.innerHTML = ref.element.innerHTML.replace(
          regex,
          this.initialProps[varWithoutDollar]
        );
      });
    });
  }
  collectVariables() {
    document.querySelectorAll("[reactive]").forEach(element => {
      let vars = element.innerHTML.match(/(\$\w+)/g).reduce((a, v) => {
        if (!a.includes(v)) {
          a.push(v);
        }
        return a;
      }, []);

      vars.forEach(variable => {
        let i = this.reactiveElements.findIndex(el => el.var === variable);
        if (i === -1) {
          this.reactiveElements.push({
            reference: [{ element, originalText: element.innerHTML, vars }],
            var: variable,
            varValue: null
          });
          return;
        }
        this.reactiveElements[i].reference.push({
          element,
          originalText: element.innerHTML,
          vars
        });
      });
    });
  }

  clickHandler(element) {
    let handler = element.attributes.click.nodeValue;
    if (!this.initialProps[handler]) return;
    element.addEventListener(
      "click",
      this.initialProps[handler].bind(this.reactiveProps)
    );
  }
  changeHandler(element) {
    let handler = element.attributes.change.nodeValue;
    if (!this.initialProps[handler]) return;
    element.addEventListener(
      "change",
      this.initialProps[handler].bind(this.reactiveProps)
    );
  }
  //problem down here ------------------------------------------
  keyHandler(element) {
    let handler = element.attributes.keypress.nodeValue;
    if (!this.initialProps[handler]) return;

    element.addEventListener(
      "keypress",
      this.initialProps[handler].bind(
        this.reactiveProps,
        element.nodeName === "INPUT" ? element.value : undefined
      )
    );
  }

  collectHandlers() {
    document.querySelectorAll("[click]").forEach(element => {
      this.clickHandler(element);
    });
    document.querySelectorAll("[change]").forEach(element => {
      this.changeHandler(element);
    });
    document.querySelectorAll("[keypress]").forEach(element => {
      this.keyHandler(element);
    });
  }
}
#testapp {
    height: 200px;
    width: 200px;
    background: red;

  }

  .box {
    height: 300px;
    width: 200px;
    position: fixed;
    background: green;
    transition: left 500ms;
    transform: translateY(-50%);
    top: 50%;
    left: 0;
    height: 20vh;
  }

  .slide {
    left: -200px;
  }
<body>
  <div id="box">
    <p reactive>Hello. My name is: $name. I am $age old</p>
    <p reactive>my text: $text </p>
    <button click="increaseAge">Increase Age</button>
    <button click="toggle">Toggle</button>
    <input value="sdf" keypress="changedText" type="text">
    <div show="state" trans="myTrans" class="box"></div>
  </div>
</body>

更新:谢谢大家,这是可用的代码:

setTimeout(()=>{
  new Tinyflow({
    name: "Max",
    age: 21,
    state: true,
    text: "",
    myTrans: "slide",
    increaseAge() {
      this.age++
    },
    toggle() {
      this.state = !this.state
    },
    changedText(text){
      this.text = text;
    },
    observers: {
      age(oldVal) {   
      }
    }
  });
})








class Tinyflow {
  constructor(properties) {
    console.time();
    this.reactivityHandler = {
      get: function(obj, prop) {
        return obj[prop];
      }.bind(this),
      set: function(obj, prop, newVal) {
        let oldVal = obj[prop];
        obj[prop] = newVal;
        if (prop in this.reactiveProps["observers"]) {
          this.reactiveProps["observers"][prop].call(
            this.reactiveProps,
            oldVal
          );
        }

        let i = this.reactiveElements.findIndex(el => el.var === "$" + prop);
        if (i !== -1) {
          this.renderSingleNode(i, newVal);
        }

        if (prop in this.showElements) {
          this.updateVisibility(this.showElements[prop], newVal);
        }
      }.bind(this)
    };
    if ("observers" in properties) {
      if (typeof properties["observers"] !== "object")
        throw Error("Observers needs to be an Object");
      for (let prop in properties["observers"]) {
        if (typeof properties["observers"][prop] !== "function")
          throw Error("An property inside observers is not an method: " + prop);
        if (!(prop in properties))
          throw Error(
            "Observer " +
              prop +
              " has nothing to observer. Add an property to observe"
          );
      }
    }
    this.initialProps = properties;
    this.reactiveProps = new Proxy(this.initialProps, this.reactivityHandler);
    this.reactiveElements = [];
    this.showElements = {};
    this.listenerRemover = null;
    this.collectHandlers();
    this.collectVariables();
    this.renderAllNodes();
    this.collectShowElements();
    console.timeEnd();
  }
  updateVisibility(elements, state) {
    if (state) {
      elements.forEach(elementProperties => {
        let { displayProperty, element } = elementProperties;
        let cssClassAvailable = element.attributes.trans;

        if (cssClassAvailable) {
          element.removeEventListener("transitionend", this.listenerRemover);
          let cssClass = this.reactiveProps[cssClassAvailable.nodeValue];
          setTimeout(() => {
            element.classList.remove(cssClass);
          });
          element.style.setProperty("display", displayProperty);
        } else {
          element.style.setProperty("display", displayProperty);
        }
      });
    } else {
      elements.forEach(elementProperties => {
        let { element } = elementProperties;
        let cssClassAvailable = element.attributes.trans;

        if (cssClassAvailable) {
          let cssClass = this.reactiveProps[cssClassAvailable.nodeValue];

          element.classList.add(cssClass);
          function removeListener() {
            element.style.setProperty("display", "none");
            element.removeEventListener("transitionend", this.listenerRemover);
          }
          this.listenerRemover = removeListener;
          element.addEventListener("transitionend", this.listenerRemover);
        } else {
          element.style.setProperty("display", "none");
        }
      });
    }
  }
  collectShowElements() {
    document.querySelectorAll("[show]").forEach(element => {
      let attributes = element.attributes;
      let stateVar = attributes.show.nodeValue;

      let displayProperty =
        window.getComputedStyle(element).getPropertyValue("display") === "none"
          ? "block"
          : window.getComputedStyle(element).getPropertyValue("display");

      if (this.showElements[stateVar]) {
        this.showElements[stateVar].push({
          element,
          displayProperty
        });
        if (!this.initialProps[stateVar]) {
          element.style.setProperty("display", "none");
        }
        return;
      }
      this.showElements[stateVar] = [
        {
          element,
          displayProperty
        }
      ];
      if (!this.initialProps[stateVar]) {
        element.style.setProperty("display", "none");
      }
    });
  }
  renderSingleNode(index, newVal) {
    let elements = this.reactiveElements;
    let value = elements[index].varValue;
    if (value === newVal) return;
    elements[index].varValue = newVal;

    elements[index].reference.forEach(ref => {
      let original = ref.originalText;
      ref.vars.forEach(vari => {
        let varWithoutDollar = vari.replace("$", "");
        let regex = new RegExp("\\" + vari, "g");
        if (varWithoutDollar === newVal) {
          original = original.replace(regex, newVal);
          return;
        }

        original = original.replace(regex, this.initialProps[varWithoutDollar]);
      });
      ref.element.innerHTML = original;
    });
  }
  renderAllNodes() {
    this.reactiveElements.forEach(element => {
      let variable = element.var;
      let varWithoutDollar = element.var.replace("$", "");

      element.reference.forEach(ref => {
        let regex = new RegExp("\\" + variable, "g");
        ref.element.innerHTML = ref.element.innerHTML.replace(
          regex,
          this.initialProps[varWithoutDollar]
        );
      });
    });
  }
  collectVariables() {
    document.querySelectorAll("[reactive]").forEach(element => {
      let vars = element.innerHTML.match(/(\$\w+)/g).reduce((a, v) => {
        if (!a.includes(v)) {
          a.push(v);
        }
        return a;
      }, []);

      vars.forEach(variable => {
        let i = this.reactiveElements.findIndex(el => el.var === variable);
        if (i === -1) {
          this.reactiveElements.push({
            reference: [{ element, originalText: element.innerHTML, vars }],
            var: variable,
            varValue: null
          });
          return;
        }
        this.reactiveElements[i].reference.push({
          element,
          originalText: element.innerHTML,
          vars
        });
      });
    });
  }

  clickHandler(element) {
    let handler = element.attributes.click.nodeValue;
    if (!this.initialProps[handler]) return;
    element.addEventListener(
      "click",
      this.initialProps[handler].bind(this.reactiveProps)
    );
  }
  changeHandler(element) {
    let handler = element.attributes.change.nodeValue;
    if (!this.initialProps[handler]) return;
    element.addEventListener(
      "change",
      this.initialProps[handler].bind(this.reactiveProps)
    );
  }
  //problem down here ------------------------------------------
  keyHandler(element) {
    let handler = element.attributes.keypress.nodeValue;
    if (!this.initialProps[handler]) return;

    element.addEventListener(
      "keyup",(event) =>
      this.initialProps[handler].call(
        this.reactiveProps,
        element.nodeName === "INPUT" ? event.target.value : undefined
      )
    );
  }

  collectHandlers() {
    document.querySelectorAll("[click]").forEach(element => {
      this.clickHandler(element);
    });
    document.querySelectorAll("[change]").forEach(element => {
      this.changeHandler(element);
    });
    document.querySelectorAll("[keypress]").forEach(element => {
      this.keyHandler(element);
    });
  }
}
#testapp {
    height: 200px;
    width: 200px;
    background: red;

  }

  .box {
    height: 100px;
    width: 100px;
    position: fixed;
    background: green;
    transition: left 500ms;
    transform: translateY(-50%);
    top: 70%;
    left: 0;
    height: 20vh;
  }

  .slide {
    left: -200px;
  }
<body>
  <div id="box">
    <p reactive>Hello. My name is: $name. I am $age old</p>
    <p reactive>my text: $text </p>
    <button click="increaseAge">Increase Age</button>
    <button click="toggle">Toggle</button>
    <input value="sdf" keypress="changedText" type="text">
    <div show="state" trans="myTrans" class="box"></div>
  </div>
</body>

3个回答

3
您可以尝试类似这样的内容。
基本上,捕获输入事件并获取该事件之后的值。我更喜欢使用“input”事件,因为它还会更新剪切、撤消、重做等操作的值。

document.getElementById("ip").addEventListener('input', function(e) {
  console.log(e.target.value);
});
<input type="text" id="ip">


2

为什么它不起作用?

因为element.value将始终返回在html代码中初始化的值

解决方案

  • 将event.target.value传递给函数。
  • 不要绑定,调用事件处理程序

额外奖励

订阅“keyup”事件而不是“keypress”以获得更好的状态同步

let initialProps = {
   change(text) {
      console.log(text);
   }
}

document.querySelectorAll("[keypress]").forEach(element => {
  this.keyHandler(element);
});
function keyHandler(element) {
  let handler = element.attributes.keypress.nodeValue;

  element.addEventListener(
    "keyup",
    (event) => {
      initialProps[handler].call(
      null,
      element.nodeName === "INPUT" ? event.target.value : undefined
      )
    }
  );
}
<input keypress="change" value="test" type="text" />


你说得对,@bravemaster。点赞了。几乎是相同的思路,只是采用了不同的方法。 - undefined
谢谢,它有效。我的响应性仍然正常运作。 - undefined

0

只有在监听 keypress 事件时,才能完成此操作。当你监听 event 时,将获得最新的更新值。在你的代码中,由于没有获取目标元素的更新值,所以没有捕获事件。

function keyHandler(element) {
  let handler = element.attributes.keypress.nodeValue;
  console.log(handler);
  element.addEventListener(
    "keypress",
    function(event) {
      console.log(event.target.value);
    })
  }

let initialProps = {
  change(text) {
    console.log(text);
  }
}

document.querySelectorAll("[keypress]").forEach(element => {
  console.log(element);
  this.keyHandler(element);
});

function keyHandler(element) {
  let handler = element.attributes.keypress.nodeValue;
  console.log(handler);
  element.addEventListener(
    "keypress",
    function(event) {
      console.log(event.target.value);
    })
  }
<input keypress="change" value="test" type="text" />


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接