【问题标题】:Can't print correct innerHTML message within a nested function无法在嵌套函数中打印正确的 innerHTML 消息
【发布时间】:2021-01-16 17:11:26
【问题描述】:

我正在开发一个食谱页面,其中有一系列相互关联的按钮和帖子。这些按钮具有食谱类别的名称,例如 Pie 和 Cake。当您单击“派”按钮时,您只会看到归类为“派”的帖子。按钮和帖子都具有数据属性,其中包含其配方类别。

我可以让它工作,但是,当您单击食谱类别按钮时,我遇到了问题,并且没有相应的帖子。为此,我创建了一个空的“#message”div,如果没有找到食谱帖子,它将输出一条消息,如果有食谱帖子,则输出一个空字符串。

当我点击有帖子的食谱按钮时,我会在消息中看到“没有食谱”文本。同样奇怪的是,它看起来只将正确的消息应用到最后一个按钮/帖子,在这个例子中是“蛋糕”。

有人可以解释为什么这不起作用吗?我知道这可能是范围/关闭问题,但我不确定发生了什么。

  //BUTTONS
  <section>
   <button class="recipe_button" data-btncategory="Pie">
      Pie
   </button>

   <button class="recipe_button" data-btncategory="Cake">
      Cake
   </button>
</section>

//POSTS
<div id="message"></div>

 <section class="recipe" data-postcategory="Pie">
     <h2>Pie Recipe</h2>
 </section>

 <section class="recipe" data-postcategory="Cake">
    <h2>Cake Recipe</h2>
  </section>


let posts = document.querySelectorAll(".recipe");
let postsArr = Array.from(posts);

let btn = document.querySelectorAll(".recipe_button");
let btnArray = Array.from(btn);

let message = document.getElementById("message");


btnArray.forEach((button) => {
    button.onclick = (el) => {
        let match = el.target.dataset.btncategory;
        postsArr.filter(function(post, i) {
            if (post.dataset.postcategory == match) {
                posts[i].style.display = "grid";
                  <-- message not working properly -->
                  message.innerHTML = "";
            } else {
                posts[i].style.display = "none";
                <-- message not working properly -->
                message.innerHTML = "Sorry No Recipes Available";
            }
        });
    }
});

【问题讨论】:

  • 看看你的过滤器是如何运行的。你总是会得到匹配的和不匹配的——所以 if 和 else 代码总是会运行——另外,如果你从不使用返回的(空)数组,为什么还要使用 .filter
  • 仅供参考:当您不使用包含任何 HTML 的字符串时,请勿使用 .innerHTML.innerHTML 具有安全性和性能影响。请改用.textContent
  • @JaromandaX 我使用过滤器是因为我想过滤帖子。有没有更好的方法来做到这一点?
  • 但是您根本没有过滤...过滤器返回过滤后的数组-您不对返回的结果做任何事情...注意:在我的回答中,我也使用了过滤器...这样你就可以得到过滤数组的长度来有条件地设置消息

标签: javascript function ecmascript-6 scope closures


【解决方案1】:

这是让您的想法发挥作用的简单方法。
它使用带有event delegation 的事件监听器。

请参阅代码内的 cmets 以获得进一步说明。

// Identifies DOM elements
const
  btnsDiv = document.getElementById("btns"),
  posts = [...document.getElementsByClassName("recipe")],
  message = document.getElementById("message");

// Calls `filterPosts` when btnsDiv is clicked
btnsDiv.addEventListener("click", filterPosts);


// Defines `filterPosts`
function filterPosts(event){

  // Ignores irrelevant clicks
  if(!event.target.classList.contains("btn")){ return; }

  // Shows message while there is no match
  let match = false;
  message.classList.remove("hidden");

  // Remembers category
  const category = event.target.dataset.category;
  
  // Iterates through recipes
  posts.forEach( (post) => {

  // Hides recipe until it matches
    post.classList.add("hidden");

   // If recipe matches, shows it and notes the match
   if(post.dataset.category == category) {
      post.classList.remove("hidden");
      match = true;
    }
  });

  // If any match occurred, hides message
  if(match == true){
    message.classList.add("hidden");
  }
}
.hidden{ display: none; }
<div id = "btns">
  <button class="btn" data-category="Pie">Pie </button>
  <button class="btn" data-category="Cake"> Cake </button>
  <button class="btn" data-category="Pasta"> Pasta </button>
</div>
<div id="message" class="hidden">Sorry No Recipes Available</div>

<div class="recipe hidden" data-category="Pie">
  <h2>Pie Recipe 1</h2>
</div>
<div class="recipe hidden" data-category="Cake">
  <h2>Cake Recipe 1</h2>
</div>
<div class="recipe hidden" data-category="Cake">
  <h2>Cake Recipe 2</h2>
</div>

【讨论】:

    【解决方案2】:

    看看你的过滤器是如何运行的。你总是会得到匹配的和不匹配的——所以 if 和 else 代码总是会运行

    您要做的是在过滤器中隐藏/显示帖子,显示时返回 true,隐藏时返回 false

    这样,如果没有匹配,结果数组长度将为 0,如果匹配,则为 1 或更大

    然后在确定是否有任何显示/隐藏消息后的另一个 if/else

    let posts = document.querySelectorAll(".recipe");
    let postsArr = Array.from(posts);
    
    let btn = document.querySelectorAll(".recipe_button");
    let btnArray = Array.from(btn);
    
    let message = document.getElementById("message");
    
    btnArray.forEach((button) => {
      button.onclick = (el) => {
        let match = el.target.dataset.btncategory;
        let found = postsArr.filter(function(post) {
          if (post.dataset.postcategory == match) {
            post.style.display = "grid";
            return true;
          } else {
            post.style.display = "none";
            return false;
          }
        }).length;
        message.innerHTML = found ? "" : "Sorry No Recipes Available";
      }
    });
    <section>
      <button class="recipe_button" data-btncategory="Pie">
          Pie
       </button>
    
      <button class="recipe_button" data-btncategory="Cake">
          Cake
       </button>
    </section>
    
    //POSTS
    <div id="message"></div>
    
    <section class="recipe" data-postcategory="Pie">
      <h2>Pie Recipe</h2>
    </section>
    
    <section class="recipe" data-postcategory="Cake">
      <h2>Cake Recipe</h2>
    </section>

    说了这么多,消息永远不会显示Sorry No Recipes Available,因为你的按钮保证会显示一个

    【讨论】:

    • 这对我有用!谢谢你的解释:)
    猜你喜欢
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多