2021.04.08

😊 2021.04.08

1. Vue slot을 활용한 컴포넌트 재활용

: https://kr.vuejs.org/v2/guide/components-slots.html#%EC%9D%B4%EB%A6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EC%8A%AC%EB%A1%AF-Named-Slots

2. 뷰 컴포넌트 props 타입이 배열이나 객체인 경우

팩토리 패턴으로 작성해야함.

3. 슬롯에 데이터바인딩

: https://beomy.tistory.com/58

4. hsla?

border-color: hsla(0, 0%, 100%, 0.5);

5. bin-packing algorithm 알고리즘

6. javascript json 파싱 에러 처리

if (typeof positions == "string") {
  try {
    // 성공
    positions = JSON.parse(positions);
    onSuccess(positions);
  } catch (error) {
    // 실패
    console.error("JSON parse error: " + error);
    onError();
    return;
  }
}

7. Packery 라이브러리 자동 빈 공간 채우기 방지

  • 참고
  1. https://github.com/metafizzy/packery/issues/337
  2. https://packery.metafizzy.co/#initialize-with-vanilla-javascript
  3. https://jeonghwan-kim.github.io/2018/05/12/extended-component.html
  • HTML
// html
<div class="grid" id="grid">insert html</div>
  • CSS
/*css*/
* {
  box-sizing: border-box;
}

body {
  font-family: sans-serif;
}

/* ---- grid ---- */

.grid {
  background: #ddd;
  width: 100%;
  max-width: 800px;
  min-width: 400px;
  min-height: 400px;
}

/* clear fix */
.grid:after {
  content: "";
  display: block;
  clear: both;
}

/* ---- .grid-item ---- */

.grid-item {
  float: left;
  width: 25%;
  height: 100px;
  background: #c09;
  border: 2px solid hsla(0, 0%, 0%, 0.5);
}

.grid-item.col-1 {
  width: 100%;
}

.grid-item.col-2 {
  width: 50%;
}

.grid-item.col-3 {
  width: 25%;
}

.grid-item:hover {
  border-color: hsla(0, 0%, 100%, 0.5);
  cursor: move;
}

.grid-item.is-dragging,
.grid-item.is-positioning-post-drag {
  background: #c90;
  z-index: 2;
}

.packery-drop-placeholder {
  outline: 3px dashed hsla(0, 0%, 0%, 0.5);
  outline-offset: -6px;
  -webkit-transition: -webkit-transform 0.2s;
  transition: transform 0.2s;
}
  • Javascript
// javascript
const $ = (selector) => document.querySelector(selector);

const gridView = {
  init(el) {
    console.log("[gridView init]");
    const self = this;

    this.el = el;
    this.data = [];

    // 패커리 실행
    this.packery = initPackery(this.el);

    // 이벤트 설정
    this.packery.on("dragItemPositioned", function (draggedItem) {
      self.onDragEnd(draggedItem);
    });

    window.packery = this.packery;

    return this;
  },

  setData(data) {
    console.log("[gridView setData]");
    this.data = data;
    return this;
  },

  render() {
    console.log("[gridView render]");
    this.el.innerHTML = "";

    this.data.forEach((item) => {
      const div = document.createElement("div");

      div.setAttribute("data-id", item.id);
      div.setAttribute("data-sort", item.sort);
      div.className = item.className;

      div.setAttribute("data-top", item.top);
      div.setAttribute("data-left", item.left);
      div.innerText = item.title;

      this.el.appendChild(div);
    });

    this.initLayout();

    return this;
  },

  //   레이아웃 그리기
  initLayout() {
    const self = this;

    // 렌더링 후 다시 패커리 세팅
    this.packery.reloadItems();

    this.setItemDraggable();

    this.packery._resetLayout();

    const elements = this.packery.getItemElements();

    try {
      elements.forEach(function (element) {
        const packeryItem = self.packery.getItem(element);

        console.log(packeryItem);

        try {
          const left = element.getAttribute("data-left");
          const top = element.getAttribute("data-top");

          if (isNaN(left) || isNaN(top)) {
            throw new Error("position error");
          }

          packeryItem.rect.x = +left * self.packery.packer.width;
          //   packeryItem.rect.y = +top * self.packery.packer.width;
          packeryItem.rect.y = +top;

          packeryItem.element.style.top = packeryItem.rect.y + "px";
          packeryItem.element.style.left = packeryItem.rect.x + "px";
        } catch (error) {
          throw error;
        }
      });

      //   self.packery.shiftLayout();
    } catch (error) {
      console.log(error.message);
      self.packery.layout();
    }
  },

  //   드래그 앤 드롭 설정
  setItemDraggable() {
    this.packery.getItemElements().forEach(function (itemElem) {
      var draggie = new Draggabilly(itemElem);
      this.packery.bindDraggabillyEvents(draggie);
    });
  },

  onDragEnd(draggedItem) {
    const self = this;
    const items = draggedItem.layout.items;

    const gridWidth = self.packery.packer.width;

    const newData = items.map(function (item) {
      const rect = item.rect;
      const element = item.element;

      return {
        left: rect.x / gridWidth,
        // top: rect.y / gridWidth,
        top: rect.y,
        className: element.className,
        sort: element.getAttribute("data-sort"),
        id: element.getAttribute("data-id"),
        title: element.innerText,
      };
    });

    console.log(newData);

    localStorage.setItem("initData", JSON.stringify(newData));

    // 서버에 데이터 전송
    // this.data = newData;
  },
};

document.addEventListener("DOMContentLoaded", function (e) {
  init();
});

function init() {
  console.log("[init]");

  gridView.init($("#grid"));

  window.gridView = gridView;

  list().then((data) => {
    gridView.setData(data).render();
  });
}

function list() {
  console.log("[list]");

  const data = [
    {
      id: "card-2",
      title: "카드2",
      className: "grid-item col-2",
      sort: 2,
      position: {},
    },
    {
      id: "card-1",
      title: "카드1",
      className: "grid-item col-1",
      sort: 1,
      position: {},
    },
    {
      id: "card-3",
      title: "카드3",
      className: "grid-item col-3",
      sort: 3,
      position: {},
    },
    {
      id: "card-4",
      title: "카드4",
      className: "grid-item col-3",
      sort: 3,
      position: {},
    },
  ];

  const initData = localStorage.getItem("initData");

  if (typeof initData === "string") {
    try {
      console.log(initData);
      return Promise.resolve(JSON.parse(initData));
    } catch (error) {
      return Promise.resolve(data);
    }
  } else {
    return Promise.resolve(data);
  }
}

// 패커리 실행
function initPackery(el) {
  console.log("[initPackery]");

  const pckry = new Packery(el, {
    itemSelector: ".grid-item",
    columnWidth: 100,
    initLayout: false,
  });

  return pckry;
}

좋은 웹페이지 즐겨찾기