【问题标题】:How to delete and element that is rendered in a Web Component如何删除 Web 组件中呈现的元素
【发布时间】:2023-02-22 03:30:42
【问题描述】:

在代码 sn-p 中,如果您单击选择按钮,它会呈现一个带有按钮的 div 我试图在单击按钮时删除该 div。

这就是代码的流程。在 SelectedBtn 组件 handleSelect 中,一个对象被创建并被推送到 window.selectedItems.items。

对所选产品调用下一次渲染。然后在 DeleteButton 组件 render 中调用 forEach over this.items 存储在构造函数中。

然后将 innerHTML 设置为带有嵌套删除按钮的 div 与数据一起呈现(我想删除整个 div 并重新呈现)

用户单击删除按钮并触发 handleDelete,它从事件中获取 id 并存储在 let 中。接下来,我在 this.items 上调用过滤器。

如果您查看日志,它会将其从数组 this.items 中删除,但不会重新呈现。

class DeleteButton extends HTMLElement {
  constructor() {
    super();
    this.items = window.selectedItems.items;
    this.selectedProducts = document.querySelector('selected-products');
    this.querySelectorAll('button').forEach((button) => button.addEventListener('click',            this.handleDelete.bind(this)));
  }
 // This is what I have tried
  handleDelete(e) {
    e.preventDefault();
    let productId = e.currentTarget.dataset.id;
    console.log( productId )
    // This is removing the item
    this.items.filter((item) => item.id !== productId);
    console.log('Before', this.items);
    console.log('After filter', this.items.filter((item) => item.id !== productId));
    
    // If I call render below just 
   this.selectedProducts.render()
  }
}
customElements.define('delete-button', DeleteButton);

class SelectedProducts extends HTMLElement {
  constructor() {
    super();
    this.items = window.selectedItems.items
  }

  render() {
    this.items.forEach((item, index) => {
      this.innerHTML = `
      <div style="display:flex; align-items: center; background-color:white; padding:15px; ">
        <delete-button>
          <button data-id="${item.id}" class="delete-btn">
            Delete me
          </button>
        </delete-button>
      </div>
      `;
    });
  }
}
customElements.define('selected-products', SelectedProducts);

class ProductCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({
      mode: 'open',
    });

    this.shadowRoot.innerHTML =
      `<style>
      ::slotted(div){
        color: #4B5563; 
        font-weight: 900; 
        text-align: center; 
        font-size: 20px; 
      }
      </style>
      ` +
      ` <div style="background: white; margin-right: 15px;">
          <slot name="button"></slot>
          <slot name="img"></slot>
        </div>
      `;
  }
}

customElements.define('product-card', ProductCard);

class SelectBtn extends HTMLElement {
  constructor() {
    super();
    // This is called with render below
    this.itemsPicked = document.querySelector('selected-products');
    this.attachShadow({
      mode: 'open',
    });
    this.shadowRoot.innerHTML = `
    <button
    aria-label="Select"
    type="button"
    class="pressed"
    data-addbtn="add-btn"
  >
   +
  </button>
    
    `;

    // this.id = this.getAttribute('id');
    // this.name = this.getAttribute('name');
    this.shadowRoot
      .querySelectorAll('button')
      .forEach((button) => button.addEventListener('click', this.handleSelect.bind(this)));
  }
  // Get data from attributes & store object in
  // an array on window object
    handleSelect(e) {
    e.preventDefault();
    const itemObj = {
      id: '1',
      name: name,
      qty: 1,
    };

    const item_stored = window.selectedItems.items.find((item) => item.id == itemObj.id);

    if (item_stored) {
      item_stored.qty++;
    } else {
      window.selectedItems.items.push(itemObj);
    }
    this.itemsPicked.render();
  }
}

customElements.define('select-button', SelectBtn);
<body>
    <div style="display: flex; justify-content: center; align-items: center; background: lightblue; padding: 10px">
      <product-card>
        <div slot="button">
          <select-button id="1" name="product name"></select-button>
        </div>
        <div slot="img">
          <div style="height: 100px; width: 100px">Select Button</div>
        </div>
      </product-card>
      <div>
        <selected-products></selected-products>
      </div>
    </div>
    <script src="app.js"></script>
    <script>
      window.selectedItems = {
        items: []
      };
    </script>
  </body>

【问题讨论】:

    标签: javascript native-web-component


    【解决方案1】:

    我看到你在很多概念上苦苦挣扎,就像我们所有人一样,学习这个……这将需要几个月的时间。

    1. 不要在全局范围内存储数据。应该有一个 main &lt;order-form&gt; 来保持它的状态
    2. 通信是通过直接调用&lt;order-form&gt; 和/或(自定义)事件的方法来完成的

      遍历 DOM

      • 学习使用 (标准) closest 或使用 closestElement 递归调用在 DOM 上查找元素,穿越shadowRoot 边界
      closestElement(selector, el = this) {
          return (
            (el && el != document && el != window && el.closest(selector)) ||
            this.closestElement(selector, el.getRootNode().host)
          );
        }
      
      • 并使用递归向下移动 DOM影子潜水:
       const shadowDive = (
                el, 
                selector, 
                match = (m, r) => console.warn('match', m, r)
        ) => {
          let root = el.shadowRoot || el;
          root.querySelector(selector) && match(root.querySelector(selector), root);
          [...root.children].map(el => shadowDive(el, selector, match));
        }
      

      事件

      对于松散耦合,您可以将事件发送到 DOM 树。并让组件监听 DOM 中的共同祖先

      &lt;poker-table&gt;上思考卡片; &lt;playing-card&gt;元素根据游戏的指示。

      我回答了很多事件问题:https://stackoverflow.com/search?q=user%3A2520800+events

      绑定(这个)

      bind 是完全有效的代码,但有点过时。
      年轻的团队成员不会知道发生了什么。

      button.addEventListener('click', this.handleSelect.bind(this));

      可以写成:

      button.addEventListener('click', (evt) =&gt; this.handleSelect(evt));

      哪个让你词法范围免费;团队中的每个人都明白发生了什么。

      不要告诉任何人!我从我们的培训数据库中提取了一些代码,使用您的行话,并将其放到网上 here 剖析它,阅读 cmets,学习,并永远记住有不同的方法可以给这只猫剥皮。 (哦,它有错误......)

    【讨论】:

    • 需要注意的是,虽然这修复了事件侦听器中的范围问题,但它永远无法被删除(这可能无关紧要,但应该注意)。
    猜你喜欢
    • 1970-01-01
    • 2018-08-30
    • 2021-07-20
    • 2020-12-22
    • 2020-06-26
    • 2019-09-03
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    相关资源
    最近更新 更多