为了账号安全,请及时绑定邮箱和手机立即绑定

更改数组元素值的样式

更改数组元素值的样式

慕标5832272 2023-09-28 10:20:23
我正在构建一个待办事项列表,但无法弄清楚如何保留具有直通装饰的数组值。调用 render 方法时,数组就会从头开始构建。意味着如果我删除一个 li,则所有其他已由复选框标记为直通的 li,都会丢失装饰。我该怎么做才能保持线路畅通?到目前为止,我尝试在 markTask 方法中将原始值替换为带有直通线的值,但它不起作用。基本上,我试图完成的是通过插入带有直通式的值,以便能够检查该值是否具有直通式样式,并且在渲染之后能够将选中的复选框保持为选中状态。到目前为止我的代码:class Todo {  constructor() {    this.input = document.getElementById("input");    this.ul = document.getElementById("ul");    this.form = document.getElementById("form");    this.tasks = [];    this.registerEvent();  }  registerEvent() {    this.form.addEventListener("submit", (event) => {      event.preventDefault();      this.createTask(this.input.value);      this.form.reset();    });  }  createTask(task) {    if (task.trim().length === 0) {      return;    }    this.tasks.push(task);    this.render();  }  deleteTask(task) {    const myTask = task.target;    const parent = myTask.parentNode;    const taskToRemove = parent.childNodes[1].textContent;    const index = this.tasks.indexOf(taskToRemove);    this.tasks.splice(index, 1);    this.render();  }  markTask(task) {    const myTask = task.target;    const parent = myTask.parentNode;        if (myTask.checked) {      parent.style.textDecoration = "line-through";    } else {      parent.style.textDecoration = "none";    }  }  render() {    this.ul.innerHTML = "";    this.tasks.forEach((task) => {      const li = document.createElement("li");      const cb = document.createElement("input");      cb.type = "checkbox";      cb.addEventListener("click", (e) => {        this.markTask(e);      });      li.appendChild(cb);      li.append(document.createTextNode(task));      const btn = document.createElement("button");      li.appendChild(btn);      btn.textContent = "Delete";      btn.classList.add("remove");      btn.addEventListener("click", (e) => {        this.deleteTask(e);      });      this.ul.appendChild(li);    });  }}new Todo();<form id="form">  <input id="input" />  <button id="add">Add</button></form><ul id="ul">  </ul>
查看完整描述

3 回答

?
子衿沉夜

TA贡献1828条经验 获得超3个赞

这是因为你没有跟踪哪些任务已完成,而只是在推动字符串。对于您的createTask方法,您需要推送一个具有完成属性的对象来指示哪些任务已完成,如下所示


 createTask(task) {

 if (task.trim().length === 0) {

  return;

 }

 this.tasks.push({title: task, done: false});

 this.render();

 }

更新渲染以考虑已完成的任务


render() {

this.ul.innerHTML = "";

this.tasks.forEach((task) => {

  const li = document.createElement("li");

  const cb = document.createElement("input");

  cb.type = "checkbox";

  cb.addEventListener("click", (e) => {

    this.markTask(e);

  });

  li.appendChild(cb);


  li.append(document.createTextNode(task.title));


  const btn = document.createElement("button");

  li.appendChild(btn);

  btn.textContent = "Delete";

  btn.classList.add("remove");

  btn.addEventListener("click", (e) => {

    this.deleteTask(e);

  });

  this.ul.appendChild(li);


   if (task.done) {

    cb.checked = true;

    li.style.textDecoration = "line-through";

   } else {

    cb.checked = false;

    li.style.textDecoration = "none";

   }

 });

}

在你的构造函数中更新你的任务变量以查看其效果


constructor() {

this.input = document.getElementById("input");

this.ul = document.getElementById("ul");

this.form = document.getElementById("form");

this.tasks = [{title: 'mill', done: true}, {title: 'jus', done: false}];

this.registerEvent();

}

希望您能了解总体思路。我不会完成整个实现,markTask因为这应该足以让您了解解决方案应该是什么。祝你好运。


查看完整回答
反对 回复 2023-09-28
?
临摹微笑

TA贡献1982条经验 获得超2个赞

如果可以的话,我对你的代码做了一些修改。


您需要的技术是事件委托:对子元素的任何单击也是对其父元素的单击。我们在父元素上放置事件侦听器,然后查看它发生在哪个子元素上。就您而言,这只会为您的所有“删除”按钮创建一个事件侦听器。


另一个想法是不要忽略 DOM,它还保留任务列表,您不需要将它们保存在内存中的表中,这是多余的。


这是代码:css也是有帮助的


class Todo 

  {

  constructor()

    {

    this.form  = document.getElementById('todo-form')

    this.liste = document.getElementById('todo-list')

    this.form.onsubmit = e => this.addTask(e)

    this.liste.onclick = e => this.delTask(e)

    }

  addTask(e)

    {

    e.preventDefault()

    if (this.form.task.value.trim() === '') return


    let li = document.createElement('li')

      , cb = document.createElement('input')

      , sp = document.createElement('span')

      , bt = document.createElement('button')

      ;

    cb.type        = 'checkbox'

    sp.textContent = this.form.task.value

    bt.textContent = 'Delete'

    bt.className   = 'remove'


    li.appendChild(cb)

    li.appendChild(sp)

    li.appendChild(bt)

    this.liste.appendChild(li)

    this.form.reset()

    }

  delTask(e)

    {

    if (!e.target.matches('button.remove')) return // reject others clicks

    e.target.closest('li').remove()

    }

  }


new Todo();

#todo-list li > span {

  display          : inline-block;

  background-color : whitesmoke;

  width            : 20em;

  }

#todo-list li input[type=checkbox]:checked + span {

  text-decoration : line-through;

  }

#todo-list li button.remove {

  font-size: .6em;

  }

<form id="todo-form">

  <input name="task">

  <button type="submit">Add</button>

</form>

<ul id="todo-list"></ul>

正如您所看到的,这段代码更短。您还可以使用 IIFE 而不是类,如下所示:

(function() // IIFE

  {

  let form  = document.getElementById('todo-form')

    , liste = document.getElementById('todo-list')

    ;

  form.onsubmit = e =>  // addTask

    {

    e.preventDefault()

    if (form.task.value.trim() === '') return


    let li = document.createElement('li')

      , cb = document.createElement('input')

      , sp = document.createElement('span')

      , bt = document.createElement('button')

      ;

    cb.type        = 'checkbox'

    sp.textContent = form.task.value

    bt.textContent = 'Delete'

    bt.className   = 'remove'


    li.appendChild(cb)

    li.appendChild(sp)

    li.appendChild(bt)

    liste.appendChild(li)

    form.reset()

    }

  liste.onclick = e =>  // delTask

    {

    if (!e.target.matches('button.remove')) return // reject others clicks

    e.target.closest('li').remove()

    }

  }

)()



btTaskList.onclick = e =>

  {

  let tasks = [...document.querySelectorAll('#todo-list li')].map(li=> 

    {

    let val = li.querySelector('span').textContent

      , chk = li.querySelector('input[type=checkbox]').checked

      ;

    return {val,chk}

    })

  console.clear()

  console.log( tasks )

  }

#todo-list li > span {

  display          : inline-block;

  background-color : whitesmoke;

  width            : 20em;

  }

#todo-list li input[type=checkbox]:checked + span {

  text-decoration : line-through;

  }

#todo-list li button.remove {

  font-size: .6em;

  }

<form id="todo-form">

  <input name="task">

  <button type="submit">Add</button>

</form>

<ul id="todo-list"></ul>


  

<button id="btTaskList">get task list</button>

我还添加了一个get task list按钮...



查看完整回答
反对 回复 2023-09-28
?
慕森王

TA贡献1777条经验 获得超3个赞

标记元素后,您仅更改元素的 Stayle 和属性。但是删除后,您会使用render整个列表重新创建,并且render您不会渲染checked参数。


你的渲染应该是:


  render() {

    this.ul.innerHTML = "";

    this.tasks.forEach((task) => {

      const li = document.createElement("li");

      const cb = document.createElement("input");

      cb.type = "checkbox";

      cb.addEventListener("click", (e) => {

        this.markTask(e);

      });

      li.appendChild(cb);


      // missed rendering checked

      if (task.checked) {

        li.style.textDecoration = "line-through";

        cb.checked = 'checked';

      }


      li.append(document.createTextNode(task));


      const btn = document.createElement("button");

      li.appendChild(btn);

      btn.textContent = "Delete";

      btn.classList.add("remove");

      btn.addEventListener("click", (e) => {

        this.deleteTask(e);

      });


      this.ul.appendChild(li);

    });

  }


查看完整回答
反对 回复 2023-09-28
  • 3 回答
  • 0 关注
  • 76 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信