从数组javascript中删除项目时重新呈现列表的问题

Posted

技术标签:

【中文标题】从数组javascript中删除项目时重新呈现列表的问题【英文标题】:Issue on re-render list when removing an item from an array javascript 【发布时间】:2021-11-18 08:34:13 【问题描述】:

我正在尝试为用户可以删除和编辑的文本创建一个列表。但是我在尝试实现它时遇到了一个问题,这就是我目前的发展。

为了创建列表,我通过使用这个函数映射对象来渲染元素

function textContainer(e, color) 
    var textForm = `
        <form onsubmit="return false" class="form-inline my-2 text-form row" style="display:flex; justify-content:space-around;">
            <input class="col-9 form-control mr-sm-2" type="text" id="newText"
                placeholder="Name, Number etc">
            <button class="col-2 btn btn-outline-primary my-2 my-sm-0" type="button"
                onclick="addText(newText.value)">Add Text</button>
        </form>
    `;
    var textLayer = '';
    var id = 0;
    var iconColor = 'black';
    if (color != null) 
        iconColor = color
    
    canvas._objects.map(object => 
        if (object.text != undefined) 
            console.log(object.fill)
            id += 1;
            textLayer = `
            <ul class="listTexts" style="padding :0;">
                <li id="text-`+ id + `" class="buttonLists">
                    <span>`+ id + `. ` + object.text + `</span>
                    <div>
                        <i class="fas fa-trash-alt" style="margin:0px 5px;" onclick="removeTextById(`+ id + `)"></i>
                    </div>
                </li>
            </ul>
            `;
        
    );
    if (canvas._objects.length == 1) 
        $('.textContainer').append(textForm).html();
     else if (e == 'removed') 
        $('.textContainer').append(textForm + textLayer).html();
     else if (e == 'changed') 
        $('.listTexts').empty();
        $('.listTexts').append(textLayer).html();
     else 
        $('.textContainer').append(textLayer).html();
    

并像这样根据他们的 id 删除项目

function removeTextById(id) 
    var array = canvas._objects.filter(function (el) 
        return el.text != null
    )
    canvas.remove(array[id - 1]);
    $('.textContainer').empty();
    textContainer('removed');
    canvas.renderAll();

这很好用,如果它只包含列表中的 1 或 2 个项目,我可以删除任何项目。但是当它包含超过 2 个时,例如 3,它将删除 2 个li 标签,如果它是 4,它将删除 3 个 li 标签。我不知道会发生什么,但我的对象是正确的,它只删除了一项。您可以在 https://natestudio.my.id/3d-configurator 的文本选项卡上看到它的实际效果。

有人知道为什么会这样吗?

编辑

canvas 在我的应用程序中是 fabricjs 画布,canvas._objects 返回该画布内的对象列表。我将尝试在一分钟内创建一个简单的重现

编辑 2

这是一个最小的复制https://jsfiddle.net/2758bskq/6/

【问题讨论】:

问题内部缺少信息。例如,我们不知道canvas.remove 会做什么,以及它是否没有错误(我们不应该为此查看外部站点)。请在问题中提供足够的信息/代码,以便我们重现问题。 感谢您的想法,我会尝试在一分钟内创建一个最小复制 我创建了一个最小复制 【参考方案1】:

在删除操作中,列表显示在此处:

else if (e == 'removed') 
    $('.textContainer').append(textForm + textLayer).html();

在此执行之前,$('.textContainer') 为空。由于textLayer 仅包含一个 项(参见上面的循环),删除后最多显示一项。

所以一个问题是textLayer 的集合:它应该收集所有相关的项目,而不仅仅是最后一个。所以替换:

textLayer =

与:

textLayer +=

但这会对其他场景(添加,...等)产生不良后果。为避免这种情况,只需重建列表总是

因此,将if (canvas._objects.length == 1) 和其后的整个if..else 结构替换为:

$('.textContainer').empty().append(textForm + textLayer);

这将解决您提到的问题。

片段(画布尺寸缩小,因此专注于列表):

var canvas = this.__canvas = new fabric.Canvas('canvas', 
  backgroundColor: 'white',
  centeredScaling: true,
);

function addText(text) 
  if (text != '') 
    jerseyName = new fabric.IText(text, 
      fontSize: 25,
      textAlign: 'center',
      fontWeight: 'bold',
      left: 100,
      top: 280,
      originX: 'center',
      originY: 'center',
      selectable: true
    );
    canvas.add(jerseyName);
    canvas.setActiveObject(jerseyName);
    textContainer();
    $('.text-form').each(function() 
      this.reset();
    );
  


function textContainer() 
  var textForm = `
    <form onsubmit="return false" class="form-inline my-2 text-form row" style="display:flex; justify-content:space-around;">
      <input class="col-9 form-control mr-sm-2" type="text" id="newText"
        placeholder="Name, Number etc">
      <button class="col-2 btn btn-outline-primary my-2 my-sm-0" type="button"
        onclick="addText(newText.value)">Add Text</button>
    </form>
  `;
  var textLayer = '';
  var id = 0;
  canvas._objects.map(object => 
    if (object.text != undefined) 
      id += 1;
      textLayer += `
      <ul class="listTexts" style="padding :0;">
        <li id="text-` + id + `" class="buttonLists">
          <span>` + id + `. ` + object.text + `</span>
          <div>
            <button  onclick="removeTextById(` + id + `)">Remove</button>
          </div>
        </li>
      </ul>
      `;
    
  );
  $('.textContainer').empty().append(textForm + textLayer);


function removeTextById(id) 
  var array = canvas._objects.filter(function(el) 
    return el.text != null
  )
  canvas.remove(array[id - 1]);
  textContainer();
  canvas.renderAll();


textContainer();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<canvas id="canvas"  ></canvas>

<div class="tab-pane p-3 textContainer" id="tabs-2" role="tabpanel" aria-labelledby="two-tab">
</div>

【讨论】:

我尝试过使用textLayer +=,但没有给我想要的结果,$('.textContainer').empty().append(textForm + textLayer); 是我真正需要的,谢谢! 好的,如果它适合你,那很重要。我真的不明白如果没有+= 它将如何工作,因为如果您的列表有 3 个或更多元素,然后您删除了一项,那么您将在删除后得到一个元素(由 textLayer 表示)。我在答案中添加了一个 sn-p。 我补充说,但我只是说我已经尝试过但它不起作用,所以我现在需要的是$('.textContainer').empty().append(textForm + textLayer);。谢谢,这将对将来的某人有所帮助

以上是关于从数组javascript中删除项目时重新呈现列表的问题的主要内容,如果未能解决你的问题,请参考以下文章

Javascript/jQuery - 将项目推送到数组并从数组中删除

在 JavaScript 中从数组中删除一个项目

从列表中删除项目时索引不更新

接收到 websocket 消息后,如何从组件 **ts** 文件中重新呈现角度组件视图?

使用Javascript删除从不同页面呈现的整个表

Swiftui listRowInsets 在添加到空数组时会发生意外更改