[django]magic grid, articleapp

Hyeseong·2020년 12월 17일
0

django

목록 보기
13/35

magic grid

게시물의 표현을 입체적이고 개성있게 표현하기 위해 자바스크립트 라이브러리 중 하나인 magic grid를 사용하게 됩니다.

즉, 우리가 아는 핀터레스트 레이아웃을 만들기 위한 도구에요.

github에서 magicgird repository로 가서 JSFIDDLE이라는 링크를 클릭하세요.


예시가 우측 하단에서 역동적으로 보여주고 나머지 위, 왼쪽 아래는 html, css, js 각종 소스코드들이 있는데 artilceapp에서 html파일을 만들고 list.html 파일에 넣어 활용하고 js 소스코드는 static 디렉토리 안에 js/magicgrid.js파일을 만들어서 활용할 거에요.


추가 앱 생성 및 작업

artilceapp을 생성 할 건데요. 역할은 게시물을 pinterest 사진 목록처럼 보여 줄거에요.

Steps

1. startapp명령어로 articleapp생성

2. settings.py에 앱이름 INSTALLED_APPS 변수에 추가

3. 프로젝트 urls.py에 path추가

path('articles/', include('articleapp.urls') ),

4. articleapp안에 urls 맵핑

path('list/', TemplateView.as_view(template_name='articleapp/list.html'), name='list'),

5. template 작업

템플릿 작업은 위의 JSFIDDLE안의 HTML 소스코드를 복붙할거에요.
우선 최종 소스코드는 아래와 같이 되는것부터 먼저 보세요.

  • base.html 파일을 상속 받고 필요한 jinja 태그를 만들어줘요.
  • load static, block content등
  • css는 html 안에서 간단하게 사용할 거라 style태그 안에 복붙합니다.
    • 하지만 height 삭제, border-radius는 1rem으로 둥글게(이미지 테두리) 만들어요
  • 그리고 아래 script 태그안의 src속성은 static을 이용해서 js/magicgrid.js 파일을 호출하여 사용할거에요.(이 파일이 magicgrid 알짜배기!)

articleapp/templates/articleapp/list.html

{% extends 'base.html' %}
{% load static %}

{% block content %}
<style>

.container div {
  width: 250px;
  background-color: antiquewhite;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 1rem;
}

  .container img {
  width: 100%;
  }


</style>

    <div class="container">
      <div>
        <img src="https://picsum.photos/200/300">
      </div>
      <div>
        <img src="https://picsum.photos/200/340">
      </div>
      <div>
        <img src="https://picsum.photos/200/280">
      </div>
      <div>
        <img src="https://picsum.photos/200/390">
      </div>
      <div>
        <img src="https://picsum.photos/200/200">
      </div>
      <div>
        <img src="https://picsum.photos/200/500">
      </div>
      <div>
        <img src="https://picsum.photos/200/100">
      </div>
      <div>
        <img src="https://picsum.photos/200/250">
      </div>
      <div>
        <img src="https://picsum.photos/200/320">
      </div>
      <div>
        <img src="https://picsum.photos/200/300">
      </div>
      <div>
        <img src="https://picsum.photos/200/300">
      </div>
      <div>
        <img src="https://picsum.photos/200/270">
      </div>
      <div>
        <img src="https://picsum.photos/200/330">
      </div>

    </div>

    <script src="{% static 'js/magicgrid.js' %}"></script>
{% endblock %}

중요!

magicgrid 레포지토리의 dist 폴더 안에서 magicgrid.cjs.js 파일안의 소스코드 전부를 복사하여 우리가 만들려는 아래 js파일에 붙여넣어주세요.

그리고 맨 마지막 소스코드 한줄 module.exports = MagicGrid; 이거는 지워주세요.

그럼 magicGrid.listen(); 이녀석이 가장 아래에 배치되는데 그 바로 위에
즉 바로 아래 소스코드 조각이 아래아래 메인 js파일안에 포함되어야해요.

추가 작성을 하는 이유는 사진을 웹에서 불러올 때 jsfiddle이 먼저 실행되고 나서 다른 웹사이트의 picsum.photos라는 파일에서 늦게 로딩되서 버그가 발생되요 이를 방지하기 위한 조치에요.

var masonrys = document.getElementsByTagName("img");

for (let i = 0; i < masonrys.length; i++){
    masonrys[i].addEventListener('load', function(){
        magicGrid.positionItems();
    }

static/js/magicgrid.js

'use strict';

/**
 * @author emmanuelolaojo
 * @since 11/11/18
 */

/**
 * Validates the configuration object.
 *
 * @param config - configuration object
 */
var checkParams = function (config) {
  var DEFAULT_GUTTER = 25;
  var booleanProps = ["useTransform", "center"];


  if (!config) {
    throw new Error("No config object has been provided.");
  }

  for(var prop of booleanProps){
    if(typeof config[prop] !== "boolean"){
      config[prop] = true;
    }
  }


  if(typeof config.gutter !== "number"){
    config.gutter = DEFAULT_GUTTER;
  }

  if (!config.container) { error("container"); }
  if (!config.items && !config.static) { error("items or static"); }
};


/**
 * Handles invalid configuration object
 * errors.
 *
 * @param prop - a property with a missing value
 */
var error = function (prop) {
  throw new Error(("Missing property '" + prop + "' in MagicGrid config"));
};

/**
 * Finds the shortest column in
 * a column list.
 *
 * @param cols - list of columns
 *
 * @return shortest column
 */
var getMin = function (cols) {
  var min = cols[0];

  for (var col of cols) {
    if (col.height < min.height) { min = col; }
  }

  return min;
};

/**
 * @author emmanuelolaojo
 * @since 11/10/18
 *
 * The MagicGrid class is an
 * implementation of a flexible
 * grid layout.
 */

var MagicGrid = function MagicGrid (config) {
  checkParams(config);

  if (config.container instanceof HTMLElement) {
    this.container = config.container;
    this.containerClass = config.container.className;
  }
  else {
    this.containerClass = config.container;
    this.container = document.querySelector(config.container);
  }

  this.items = this.container.children;
  this.static = config.static || false;
  this.size = config.items;
  this.gutter = config.gutter;
  this.maxColumns = config.maxColumns || false;
  this.useMin = config.useMin || false;
  this.useTransform = config.useTransform;
  this.animate = config.animate || false;
  this.started = false;
  this.center = config.center;

  this.init();
};

/**
 * Initializes styles
 *
 * @private
 */
MagicGrid.prototype.init = function init () {
  if (!this.ready() || this.started) { return; }

  this.container.style.position = "relative";

  for (var i = 0; i < this.items.length; i++) {
    var style = this.items[i].style;

    style.position = "absolute";

    if (this.animate) {
      style.transition = (this.useTransform ? "transform" : "top, left") + " 0.2s ease";
    }
  }

  this.started = true;
};

/**
 * Calculates the width of a column.
 *
 * @return width of a column in the grid
 * @private
 */
MagicGrid.prototype.colWidth = function colWidth () {
  return this.items[0].getBoundingClientRect().width + this.gutter;
};

/**
 * Initializes an array of empty columns
 * and calculates the leftover whitespace.
 *
 * @return {{cols: Array, wSpace: number}}
 * @private
 */
MagicGrid.prototype.setup = function setup () {
  var width = this.container.getBoundingClientRect().width;
  var colWidth = this.colWidth();
  var numCols = Math.floor(width/colWidth) || 1;
  var cols = [];

  if (this.maxColumns && numCols > this.maxColumns) {
    numCols = this.maxColumns;
  }

  for (var i = 0; i < numCols; i++) {
    cols[i] = {height: 0, index: i};
  }

  var wSpace = width - numCols * colWidth + this.gutter;

  return {cols: cols, wSpace: wSpace};
};

/**
 * Gets the next available column.
 *
 * @param cols list of columns
 * @param i index of dom element
 *
 * @return {*} next available column
 * @private
 */
MagicGrid.prototype.nextCol = function nextCol (cols, i) {
  if (this.useMin) {
    return getMin(cols);
  }

  return cols[i % cols.length];
};

/**
 * Positions each item in the grid, based
 * on their corresponding column's height
 * and index then stretches the container to
 * the height of the grid.
 */
MagicGrid.prototype.positionItems = function positionItems () {
  var ref = this.setup();
    var cols = ref.cols;
    var wSpace = ref.wSpace;
  var maxHeight = 0;
  var colWidth = this.colWidth();

  wSpace = this.center ? Math.floor(wSpace / 2) : 0;

  for (var i = 0; i < this.items.length; i++) {
    var col = this.nextCol(cols, i);
    var item = this.items[i];
    var topGutter = col.height ? this.gutter : 0;
    var left = col.index * colWidth + wSpace + "px";
    var top = col.height + topGutter + "px";

    if(this.useTransform){
      item.style.transform = "translate(" + left + ", " + top + ")";
    }
    else{
      item.style.top = top;
      item.style.left = left;
    }

    col.height += item.getBoundingClientRect().height + topGutter;

    if(col.height > maxHeight){
      maxHeight = col.height;
    }
  }

  this.container.style.height = maxHeight + this.gutter + "px";
};

/**
 * Checks if every item has been loaded
 * in the dom.
 *
 * @return {Boolean} true if every item is present
 */
MagicGrid.prototype.ready = function ready () {
  if (this.static) { return true; }
  return this.items.length >= this.size;
};

/**
 * Periodically checks that all items
 * have been loaded in the dom. Calls
 * this.listen() once all the items are
 * present.
 *
 * @private
 */
MagicGrid.prototype.getReady = function getReady () {
    var this$1 = this;

  var interval = setInterval(function () {
    this$1.container = document.querySelector(this$1.containerClass);
    this$1.items = this$1.container.children;

    if (this$1.ready()) {
      clearInterval(interval);

      this$1.init();
      this$1.listen();
    }
  }, 100);
};

/**
 * Positions all the items and
 * repositions them whenever the
 * window size changes.
 */
MagicGrid.prototype.listen = function listen () {
    var this$1 = this;

  if (this.ready()) {
    var timeout;

    window.addEventListener("resize", function () {
      if (!timeout){
        timeout = setTimeout(function () {
          this$1.positionItems();
          timeout = null;
        }, 200);
      }
    });

    this.positionItems();
  }
  else { this.getReady(); }
};

let magicGrid = new MagicGrid({
container: '.container',
animate: true,
gutter: 30,
static: true,
useMin: true
});

var masonrys = document.getElementsByTagName("img");

for (let i = 0; i < masonrys.length; i++){
    masonrys[i].addEventListener('load', function(){
        magicGrid.positionItems();
    }, false);
}

magicGrid.listen();


lorem picsum 무료 랜덤 사진 배포 사이트

아래 웹 사이트에서 제공하는사진 제공 소스코드를 list.html 파일안의 div>img 태그의 src속성에 넣어주면되요.


점검 화면

profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글