【问题标题】:SortableJS isn't saving my sorted todo list in localStorageSortableJS 没有将我的排序待办事项列表保存在 localStorage
【发布时间】:2020-06-20 21:16:55
【问题描述】:

我有一个使用 localStorage 和 SortableJS 的 todo 项目。我在对待办事项列表进行排序时遇到问题,它不会更新 localStorage。有人可以帮我找出保存排序列表的方法吗?代码如下,但最好访问 sn-p 下的 codepen 链接。

const clear = document.querySelector(".clear");
const dateElement = document.getElementById("date");
const list = document.getElementById("list");
const input = document.getElementById("input");

// Class names
const CHECK = "fa-check-circle";
const UNCHECK = "fa-circle-thin";
const LINE_THROUGH = "lineThrough";

// Variables
let LIST, id;

// Get item from localStorage
let data = localStorage.getItem("TODO");

// Check if data is not empty
if (data) {
  LIST = JSON.parse(data);
  id = LIST.length;
  loadList(LIST);
} else {
  LIST = [];
  id = 0;
}

// Load items to the user's interface
function loadList(array) {
  array.forEach(function(item) {
    addToDo(item.name, item.id, item.done, item.trash);
  });
}

// Clear the localStorage
clear.addEventListener("click", function() {
  localStorage.clear();
  location.reload();
})

// Show today's date
const options = {
  weekday: "long",
  month: "short",
  day: "numeric"
};
const today = new Date();

dateElement.innerHTML = today.toLocaleDateString("en-US", options);

// Add to do function
function addToDo(toDo, id, done, trash) {

  if (trash) {
    return;
  }

  const DONE = done ? CHECK : UNCHECK;
  const LINE = done ? LINE_THROUGH : "";

  const item = `<li class="item">
                  <i class="fa ${DONE}" job="complete" id="${id}"></i>
                  <p class="text ${LINE}">${toDo}</p>
                  <i class="fa fa-trash-o de" job="delete" id="${id}"></i>
                </li>
                `;
  const position = "beforeend";

  list.insertAdjacentHTML(position, item);
}

// Add an item to the list when the user cick the enter key
document.addEventListener("keyup", function(event) {
  if (event.keyCode == 13) {
    const toDo = input.value;

    // If the input isn't empty
    if (toDo) {
      addToDo(toDo);

      LIST.push({
        name: toDo,
        id: id,
        done: false,
        trash: false
      });
      // Add item to localStorage
      localStorage.setItem("TODO", JSON.stringify(LIST));

      id++;
    }
    input.value = ""
  }
});


// complete to do
function completeToDo(element) {
  element.classList.toggle(CHECK);
  element.classList.toggle(UNCHECK);
  element.parentNode.querySelector(".text").classList.toggle(LINE_THROUGH);

  LIST[element.id].done = LIST[element.id].done ? false : true;
}

// Remove to do
function removeToDo(element) {
  element.parentNode.parentNode.removeChild(element.parentNode);

  LIST[element.id].trash = true;
  // Add item to localStorage
  localStorage.setItem("TODO", JSON.stringify(LIST));
}

// Target the items created dynamically
list.addEventListener("click", function(event) {
  const element = event.target;
  const elementJob = element.attributes.job.value;

  if (elementJob == "complete") {
    completeToDo(element);
  } else if (elementJob == "delete") {
    removeToDo(element);
  }
  // Add item to localStorage
  localStorage.setItem("TODO", JSON.stringify(LIST));
});


// For sorting the list
Sortable.create(list, {
  animation: 100,
  group: 'list-1',
  draggable: '#list li',
  handle: '#list li',
  sort: true,
  filter: '.sortable-disabled',
  chosenClass: 'active'
});
/* ------------ youtube.com/CodeExplained ------------ */

body {
  padding: 0;
  margin: 0;
  background-color: rgba(0, 0, 0, 0.1);
  font-family: 'Titillium Web', sans-serif;
}


/* ------------ container ------------ */

.container {
  padding: 10px;
  width: 380px;
  margin: 0 auto;
}


/* ------------ header ------------ */

.header {
  width: 380px;
  height: 200px;
  background-image: url('');
  background-size: 100% 200%;
  background-repeat: no-repeat;
  border-radius: 15px 15px 0 0;
  position: relative;
}

.clear {
  width: 30px;
  height: 30px;
  position: absolute;
  right: 20px;
  top: 20px;
}

.clear i {
  font-size: 30px;
  color: #FFF;
}

.clear i:hover {
  cursor: pointer;
  text-shadow: 1px 3px 5px #000;
  transform: rotate(45deg);
}

#date {
  position: absolute;
  bottom: 10px;
  left: 10px;
  color: #FFF;
  font-size: 25px;
  font-family: 'Titillium Web', sans-serif;
}


/* ------------ content ------------ */

.content {
  width: 380px;
  height: 350px;
  max-height: 350px;
  background-color: #FFF;
  overflow: auto;
}

.content::-webkit-scrollbar {
  display: none;
}

.content ul {
  padding: 0;
  margin: 0;
}

.item {
  width: 380px;
  height: 45px;
  min-height: 45px;
  position: relative;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  list-style: none;
  padding: 0;
  margin: 0;
}

.item i.co {
  position: absolute;
  font-size: 25px;
  padding-left: 5px;
  left: 15px;
  top: 10px;
}

.item i.co:hover {
  cursor: pointer;
}

.fa-check-circle {
  color: #6eb200;
}

.item p.text {
  position: absolute;
  padding: 0;
  margin: 0;
  font-size: 20px;
  left: 50px;
  top: 5px;
  background-color: #FFF;
  max-width: 285px;
}

.lineThrough {
  text-decoration: line-through;
  color: #ccc;
}

.item i.de {
  position: absolute;
  font-size: 25px;
  right: 15px;
  top: 10px;
}

.item i.de:hover {
  color: #af0000;
  cursor: pointer;
}


/* ------------ add item ------------ */

.add-to-do {
  position: relative;
  width: 360px;
  height: 40px;
  background-color: #FFF;
  padding: 10px;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.add-to-do i {
  position: absolute;
  font-size: 40px;
  color: #4162f6;
}

.add-to-do input {
  position: absolute;
  left: 50px;
  height: 35px;
  width: 310px;
  background-color: transparent;
  border: none;
  font-size: 20px;
  padding-left: 10px;
}

.add-to-do input::-webkit-input-placeholder {
  /* Chrome/Opera/Safari */
  color: #4162f6;
  font-family: 'Titillium Web', sans-serif;
  font-size: 20px;
}

.add-to-do input::-moz-placeholder {
  /* Firefox 19+ */
  color: #4162f6;
  font-family: 'Titillium Web', sans-serif;
  font-size: 20px;
}

.add-to-do input:-ms-input-placeholder {
  /* IE 10+ */
  color: #4162f6;
  font-family: 'Titillium Web', sans-serif;
  font-size: 20px;
}

.add-to-do input:-moz-placeholder {
  /* Firefox 18- */
  color: #4162f6;
  font-family: 'Titillium Web', sans-serif;
  font-size: 20px;
}
<script src="https://kit.fontawesome.com/ed2e310181.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/RubaXa/Sortable/Sortable.min.js"></script>
<div class="container">
  <div class="header">
    <div class="clear">
      <i class="fa fa-refresh"></i>
    </div>
    <div id="date"></div>
  </div>
  <div class="content">
    <ul id="list">
      <!-- <li class="item">
                  
                  <i class="fa fa-circle-thin co" job="complete" id="0"></i>
                  <p class="text"></p>
                  <i class="fa fa-trash-o" job="delete" id="1"></i>
                  
                </li> -->
    </ul>
  </div>
  <div class="add-to-do">
    <i class="fa fa-plus-circle"></i>
    <input type="text" id="input" placeholder="Add a to-do">
  </div>
</div>

请访问我的 codepen 以获取工作项目。 尝试添加 2 个或更多待办事项然后排序,刷新时希望保留已排序的列表。

https://codepen.io/Foxseiz/pen/ZEGadWZ

【问题讨论】:

    标签: javascript html sortablejs


    【解决方案1】:
    Sortable.create(list, {
            group: "TODO2",
            options: {
              animation: 100,
              draggable: "#list li",
              handle: "#list li",
              sort: true,
              filter: ".sortable-disabled",
              chosenClass: "active"
            },
            store: {
              /**
               * Get the order of elements. Called once during initialization.
               * @param   {Sortable}  sortable
               * @returns {Array}
               */
              get: function(sortable) {
                var order = localStorage.getItem(sortable.options.group.name);
                return order ? order.split("|") : [];
              },
    
              /**
               * Save the order of elements. Called onEnd (when the item is dropped).
               * @param {Sortable}  sortable
               */
              set: function(sortable) {
                var order = sortable.toArray();
                localStorage.setItem(sortable.options.group.name, order.join("|"));
              }
            }
          });
    

    这对你的情况有效

    【讨论】:

      【解决方案2】:

      对于您的Sortable.create 选项,您可以执行以下操作:

      // For sorting the list
      Sortable.create(list, {
                  animation: 100,
                  group: 'list-1',
                  draggable: '#list li',
                  handle: '#list li',
                  sort: true,
                  filter: '.sortable-disabled',
                  chosenClass: 'active',
                  onSort: function(e) {
                      var items = e.to.children;
                      var result = [];
                      for (var i = 0; i < items.length; i++) {
                          result.push(items[i].id);
                      }
                      var lsBefore = JSON.parse(localStorage.getItem("TODO"));
                      var lsAfter = [];
                      for (var i = 0; i < result.length; i++) {
                          var found = false;
                          for (var j = 0; j < lsBefore.length && !found; j++) {
                              if (lsBefore[j].id == result[i]) {
                                  lsAfter.push(lsBefore[j]);
                                  lsBefore.splice(j, 1);
                                  found = true;
                              }
                          }
                      }
                      localStorage.setItem("TODO", JSON.stringify(lsAfter));
                      console.log(result);
                      console.log(lsBefore);
                      console.log(lsAfter);
                  }
      

      lsAfter 是您重新排序的一组对象,您可以在本地存储中存储/更新这些对象。

      我的解决方案还要求您的 const 项看起来像这样(我将 id 属性添加到 &lt;li&gt; 元素:

        const item = `<li class="item" id="${id}">
                        <i class="fa ${DONE}" job="complete" id="${id}"></i>
                        <p class="text ${LINE}">${toDo}</p>
                        <i class="fa fa-trash-o de" job="delete" id="${id}"></i>
                      </li>
                      `;
      

      【讨论】:

      • 我尝试了代码,显然它没有更新排序顺序。
      • 我已经更新了我的 sn-p 以直接更新 localStorage。
      【解决方案3】:

      您需要使用 onSort 回调。 示例代码:

      const clear = document.querySelector(".clear");
      const dateElement = document.getElementById("date");
      const list = document.getElementById("list");
      const input = document.getElementById("input");
      
      // Class names
      const CHECK = "fa-check-circle";
      const UNCHECK = "fa-circle-thin";
      const LINE_THROUGH = "lineThrough";
      
      // Variables
      let LIST, id;
      
      // Get item from localStorage
      let data = localStorage.getItem("TODO");
      
      // Check if data is not empty
      if(data) {
        LIST = JSON.parse(data);
        id = LIST.length;
        loadList(LIST);
      }else{
        LIST =[];
        id = 0;
      }
      
      // Load items to the user's interface
      function loadList(array) {
        array.forEach(function(item){
            addToDo(item.name, item.id, item.done, item.trash);
        });
      }
      
      // Clear the localStorage
      clear.addEventListener("click", function() {
        localStorage.clear();
        location.reload();
      })
      
      // Show today's date
      const options = {weekday : "long", month : "short", day : "numeric"};
      const today = new Date();
      
      dateElement.innerHTML = today.toLocaleDateString("en-US", options);
      
      // Add to do function
      function addToDo(toDo, id, done, trash) {
      
        if(trash) { return; }
      
        const DONE = done ? CHECK : UNCHECK;
        const LINE = done ? LINE_THROUGH : "";
      
        const item = `<li class="item">
                        <i class="fa ${DONE}" job="complete" id="${id}"></i>
                        <p class="text ${LINE}">${toDo}</p>
                        <i class="fa fa-trash-o de" job="delete" id="${id}"></i>
                      </li>
                      `;
        const position = "beforeend";
      
        list.insertAdjacentHTML(position, item);
      }
      
      // Add an item to the list when the user cick the enter key
      document.addEventListener("keyup", function(event) {
        if(event.keyCode == 13) {
          const toDo = input.value;
      
          // If the input isn't empty
          if(toDo) {
            addToDo(toDo);
      
            LIST.push({
              name : toDo,
              id : id,
              done : false,
              trash : false
            });
            // Add item to localStorage
            localStorage.setItem("TODO", JSON.stringify(LIST));
      
            id++;
          }
          input.value = ""
        }
      });
      
      
      // complete to do
      function completeToDo(element) {
        element.classList.toggle(CHECK);
        element.classList.toggle(UNCHECK);
        element.parentNode.querySelector(".text").classList.toggle(LINE_THROUGH);
      
        LIST[element.id].done = LIST[element.id].done ? false : true;
      }
      
      // Remove to do
      function removeToDo(element) {
        element.parentNode.parentNode.removeChild(element.parentNode);
      
        LIST[element.id].trash = true;
        // Add item to localStorage
        localStorage.setItem("TODO", JSON.stringify(LIST));
      }
      
      // Target the items created dynamically
      list.addEventListener("click", function(event) {
        const element = event.target;
        const elementJob = element.attributes.job.value;
      
        if(elementJob == "complete") {
          completeToDo(element);
        }else if(elementJob == "delete"){
          removeToDo(element);
        }
        // Add item to localStorage
        localStorage.setItem("TODO", JSON.stringify(LIST));
      });
      
      function swapArrayElements(arr, indexA, indexB) {
        var temp = arr[indexA];
        arr[indexA] = arr[indexB];
        arr[indexB] = temp;
      };
      
      function orderList(oldIndex, newIndex) {
        swapArrayElements(LIST, oldIndex, newIndex)
      
        localStorage.setItem("TODO", JSON.stringify(LIST));
      }
      
      
      // For sorting the list
      Sortable.create(list, {
          animation: 100,
          group: 'list-1',
          draggable: '#list li',
          handle: '#list li',
          sort: true,
          filter: '.sortable-disabled',
          chosenClass: 'active',
          onSort: function (/**Event*/evt) {
            orderList(evt.oldIndex, evt.newIndex);
          },
      });
      

      【讨论】:

        【解决方案4】:

        当你打电话时

        Sortable.create(list, {
          animation: 100,
          group: 'list-1',
          draggable: '#list li',
          handle: '#list li',
          sort: true,
          filter: '.sortable-disabled',
          chosenClass: 'active'
        });
        

        实际上您可以添加一个 store 选项。像这样:

        Sortable.create(list, {
            store: {
                //Get the order of elements. Called once during initialization.
                // @param   {Sortable}  sortable
                // @returns {Array}
                get: function (sortable) {
                    var order = localStorage.getItem(sortable.options.group.name);
                    return order ? order.split('|') : [];
                },
                // Save the order of elements.
                // @param {Sortable}  sortable
                set: function (sortable) {
                    var order = sortable.toArray();
                    localStorage.setItem(sortable.options.group.name, order.join('|'));
                }
            },
            ...rest of your options    
        });
        

        另外Sortable.create 为您的列表返回一个“可排序”对象,因此基于您上面的代码构建您现在可以访问可排序对象

        var mySortable = Sortable.create(list, {...your options});
        

        现在您可以在任何事件之后调用mySortable.Save(),您的store 的 set 函数将被调用。例如把 mysortable.Save() 放在你的 document.addEventListener("keyup") 函数中

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-07
          • 1970-01-01
          • 1970-01-01
          • 2021-06-09
          相关资源
          最近更新 更多