在不同的函数中多次获取 DOM 元素是不好的做法吗?

时间:2021-01-22 00:21:55

标签: javascript html dom

我有一些 javascript 代码,当用户在其中输入文本时,它会计算文本区域中剩余的字符。

window.onload = function () {
    captureTextArea();
    showRemainingCharacters();
}

function showRemainingCharacters() {
    let textareaBox = document.getElementById('postBody');

    let insertedCharacters = textareaBox.value.length;
    let counter = 1000 - insertedCharacters;
    let countRemaining = document.getElementById('charactersRemaining');
    countRemaining.innerHTML = "Characters left: " + counter;

}

function captureTextArea() {
    let textareaBox = document.getElementById('postBody');

    textareaBox.addEventListener('keyup', showRemainingCharacters, false);
    textareaBox.addEventListener('keydown', showRemainingCharacters, false);

}

现在,我了解了为什么应该避免对基本上任何事情使用全局范围,但是在我需要在 2 个不同的函数中多次(在本例中为两次)获取 DOM 元素的情况下,这是:

let textareaBox = document.getElementById('postBody');

我想知道这是否是不好的做法和/或是否有任何其他方法可以重构此代码以避免使用全局范围以便两个函数都可以访问此元素。

2 个答案:

答案 0 :(得分:1)

我真的没有看到在全局范围内声明 DOM 元素有任何错误。有一个简单的规则,DRY,不要重复你自己。所以我会在这里这样做,尤其是当我知道我将在多个地方使用它时,并使用唯一名称重命名元素以便在需要时轻松找到它们。我认为代码以这种方式看起来也更干净。这也可以在以后需要更改名称或其他内容时为您提供帮助,您只需在一处更改即可。

const postBodyTextArea = document.getElementById('postBody');

window.onload = function () {
    captureTextArea();
    showRemainingCharacters();
}

function showRemainingCharacters() {
   
    let insertedCharacters = postBodyTextArea.value.length;
    let counter = 1000 - insertedCharacters;
    let countRemaining = document.getElementById('charactersRemaining');
    countRemaining.innerHTML = "Characters left: " + counter;
    
}

function captureTextArea() {

    postBodyTextArea.addEventListener('keyup', showRemainingCharacters, false);
    postBodyTextArea.addEventListener('keydown', showRemainingCharacters, false);
    
}

答案 1 :(得分:0)

它没有任何问题,但最好只做一次,您可以制作一个 IIFE 模块或使用一个类,该类在构造时为该特定功能的功能进行设置。

还有一点需要注意的是,您可能希望页面上有多个 textarea,如果是这样,您最终会重复代码,所以用选择器查找 textarea 一次,然后附加功能,限制和剩余文本可能是一个选项。

window.onload = function() {
  document.querySelectorAll('textarea').forEach(elm => new textareaLimit(elm, {
    maxChars: elm.getAttribute('maxlength'),
    hideRemaining: elm.hasAttribute('data-hide-remaining') || false
  }))
}

class textareaLimit {
  constructor(elm, options = {}) {
    this.options = {
      maxChars: 1000,
      hideRemaining: false
    }
    if (options.maxChars) this.options.maxChars = parseInt(options.maxChars, 10)
    if (options.hideRemaining) this.options.hideRemaining = true

    this.elm = elm
    this.remainingCharacters()
    this.events()
  }
  remainingCharacters() {
    if (!this.options.hideRemaining && !this.charactersRemaining) {
      this.charactersRemaining = this.elm.parentNode.querySelector('span.charactersRemaining')
      if (!this.charactersRemaining) {
        this.charactersRemaining = document.createElement("span")
        this.charactersRemaining.className = 'charactersRemaining'
        this.elm.parentNode.appendChild(this.charactersRemaining)
      }
    }

    if (this.elm.value.length > this.options.maxChars) {
      this.elm.value = this.elm.value.substr(0, this.options.maxChars)
    }

    if (!this.options.hideRemaining) this.charactersRemaining.innerText = "Characters left: " + (this.options.maxChars - this.elm.value.length)
  }
  events() {
    this.elm.addEventListener('keyup', () => this.remainingCharacters(), false);
  }
}
<div>
  <textarea></textarea>
</div>

<div>
  <textarea data-hide-remaining></textarea>
</div>

<div>
  <textarea maxlength="10"></textarea>
</div>