캘린더 만들기 및 사진 띄우기
인스타그램의 스토리 보관함(아래 사진)과 비슷한 장고 게시물 보관 캘린더 만들기
: 인스타그램 스토리 보관함(왼), 완성된 게시물 보관 캘린더(오)
초기화
//기존 달력 구현에 필요한 초기화 코드 부분 생략(전체 코드 참고)
//달력의 날짜마다 헤드 이미지를 포함한 포스트에 대한 정보가 필요
//동적으로 장고 데이터 불러오기 위해 장고 템플릿 기능 사용( {%, {{ )
posts: [
{% for post in postall %}
{
post_date: "{{ post.created_at|date:"Ymd" }}",
title: "{{ post.title }}",
url: "{{ post.get_absolute_url }}",
{% if post.head_image %}
head_image: "{{ post.head_image.url }}"
{% else %}
#헤드이미지 없을 시 picsum으로 자동 이미지 지정
head_image: "https://picsum.photos/seed/{{ post.id }}/139/139"
{% endif %}
},
{% endfor %}
],
날짜 클릭 시 반응 설정
$calBody.addEventListener('click', (e) => {
if (e.target.classList.contains('day')) {
if (init.activeDTag) {
init.activeDTag.classList.remove('day-active');
}
let day = Number(e.target.textContent); //클릭한 날짜의 day 받아오는 코드
if (day<10){
seDate[2]="0"+String(day);
}
else{
seDate[2]=String(day);
}
e.target.classList.add('day-active'); //해당 날짜를 클릭했음을 하얀 동그라미로 표시
loadDate(day, e.target.cellIndex);
open(); //모달 창 open ('hidden'을 지우는 방식으로)
document.querySelector("#bg").addEventListener("click", close);//배경클릭하면 모달 close
init.activeDTag = e.target;
init.activeDate.setDate(day);
}
}
load YY/MM
//달력 main 구성
loadYYMM(init.today); //호출
$btnNext.addEventListener('click', () => loadYYMM(init.nextMonth()));//다음
$btnPrev.addEventListener('click', () => loadYYMM(init.prevMonth()));//이전
//일부 내용 생략
//inner html을 통한 캘린더에 포스트 헤더 이미지 삽입
let trtd = '';
let startCount;
let countDay = 0;
for (let i = 0; i < 6; i++) {
trtd += '<tr>';
for (let j = 0; j < 7; j++) {
if (i === 0 && !startCount && j === firstDay.getDay()) {
startCount = 1;
}
if (!startCount) {
trtd += '<td>'
} else {
let fullDate = seDate[0]+seDate[1] + String(init.addZero(countDay + 1));
var flag=true;
trtd += '<td ';
for(var p=0;p<init.posts.length;p++){
if(init.posts[p].post_date=== fullDate){//post작성 날과 같은 날짜 생성시 이미지 삽입
flag=false;
//head_image 불러오기
trtd += `style="background-image:url(${init.posts[p].head_image});background-size:cover;" class="day day-img`;
break;
}
}
if(flag){
trtd+='class="day'
}
trtd += (markToday && markToday === countDay + 1) ? ' today" ' : '"';
trtd += ` data-date="${countDay + 1}" data-fdate="${fullDate}">`;
}
trtd += (startCount) ? ++countDay : '';
if (countDay === lastDay.getDate()) {
startCount = 0;
}
trtd += '</td>';
}
trtd += '</tr>';
}
$calBody.innerHTML = trtd;
load Day
//inner html을 통한 모달창에 포스트 url 및 제목 정보 삽입
function loadDate (date, dayIn) {
document.querySelector('.url-body').innerHTML="";
for (var i = 0; i < init.posts.length; i++) {
var what_day=seDate[0] + seDate[1]+seDate[2]; //클릭한 날짜의 fullDate
if (init.posts[i].post_date == what_day) {
//객체에 innerHTML을 통해 href 속성 추가
document.querySelector('.url-body').innerHTML+= `<a href=${init.posts[i].url} style="font-size:6px; color:black;"><i class="fas fa-heart"></i> ${init.posts[i].title}</a><br>`;
console.log(document.querySelector('.url-body'));
}
}
document.querySelector('.cal-date').textContent = date;
document.querySelector('.cal-day').textContent = init.dayList[dayIn];
}
const init = {
monList: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
dayList: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
today: new Date(),
monForChange: new Date().getMonth(),
posts: [
{% for post in postall %}
{
post_date: "{{ post.created_at|date:"Ymd" }}",
title: "{{ post.title }}",
url: "{{ post.get_absolute_url }}",
{% if post.head_image %}
head_image: "{{ post.head_image.url }}"
{% else %}
head_image: "https://picsum.photos/seed/{{ post.id }}/139/139"
{% endif %}
},
{% endfor %}
],
activeDate: new Date(),
getFirstDay: (yy, mm) => new Date(yy, mm, 1),
getLastDay: (yy, mm) => new Date(yy, mm + 1, 0),
nextMonth: function () {
let d = new Date();
d.setDate(1);
d.setMonth(++this.monForChange);
this.activeDate = d;
return d;
},
prevMonth: function () {
let d = new Date();
d.setDate(1);
d.setMonth(--this.monForChange);
this.activeDate = d;
return d;
},
addZero: (num) => (num < 10) ? '0' + num : num,
activeDTag: null,
getIndex: function (node) {
let index = 0;
while (node = node.previousElementSibling) {
index++;
}
return index;
}
};
const $calBody = document.querySelector('.cal-body');
const $btnNext = document.querySelector('.btn-cal.next');
const $btnPrev = document.querySelector('.btn-cal.prev');
const seDate=[] //현재 클릭한 날짜에 대한 정보
function loadDate (date, dayIn) {
document.querySelector('.url-body').innerHTML="";
for (var i = 0; i < init.posts.length; i++) {
var what_day=seDate[0] + seDate[1]+seDate[2];
if (init.posts[i].post_date == what_day) {
document.querySelector('.url-body').innerHTML+= `<a href=${init.posts[i].url} style="font-size:6px; color:black;"><i class="fas fa-heart"></i> ${init.posts[i].title}</a><br>`;
console.log(document.querySelector('.url-body'));
}
}
document.querySelector('.cal-date').textContent = date;
document.querySelector('.cal-day').textContent = init.dayList[dayIn];
}
function loadYYMM (fullDate) {
let yy = fullDate.getFullYear();
let mm = fullDate.getMonth();
let firstDay = init.getFirstDay(yy, mm);
let lastDay = init.getLastDay(yy, mm);
let markToday;
if (mm === init.today.getMonth() && yy === init.today.getFullYear()) {
markToday = init.today.getDate();
}
document.querySelector('.cal-month').textContent = init.monList[mm];
document.querySelector('.cal-year').textContent = yy;
seDate[0]=String(yy);
if(mm+1<10){
seDate[1]='0'+String(mm+1); }
else{
seDate[1]=String(mm+1);
}
let trtd = '';
let startCount;
let countDay = 0;
for (let i = 0; i < 6; i++) {
trtd += '<tr>';
for (let j = 0; j < 7; j++) {
if (i === 0 && !startCount && j === firstDay.getDay()) {
startCount = 1;
}
if (!startCount) {
trtd += '<td>'
} else {
let fullDate = seDate[0]+seDate[1] + String(init.addZero(countDay + 1));
var flag=true;
trtd += '<td ';
for(var p=0;p<init.posts.length;p++){
if(init.posts[p].post_date=== fullDate){
flag=false;
trtd += `style="background-image:url(${init.posts[p].head_image});background-size:cover;" class="day day-img`;
break;
}
}
if(flag){
trtd+='class="day'
}
trtd += (markToday && markToday === countDay + 1) ? ' today" ' : '"';
trtd += ` data-date="${countDay + 1}" data-fdate="${fullDate}">`;
}
trtd += (startCount) ? ++countDay : '';
if (countDay === lastDay.getDate()) {
startCount = 0;
}
trtd += '</td>';
}
trtd += '</tr>';
}
$calBody.innerHTML = trtd;
}
loadYYMM(init.today);
$btnNext.addEventListener('click', () => loadYYMM(init.nextMonth()));
$btnPrev.addEventListener('click', () => loadYYMM(init.prevMonth()));
var open = () =>{
document.getElementById("todo").classList.remove("hidden");
}
var close = () =>{
document.getElementById("todo").classList.add("hidden");
}
$calBody.addEventListener('click', (e) => {
if (e.target.classList.contains('day')) {
if (init.activeDTag) {
init.activeDTag.classList.remove('day-active');
}
let day = Number(e.target.textContent);
if (day<10){
seDate[2]="0"+String(day);
}
else{
seDate[2]=String(day);
}
e.target.classList.add('day-active');
loadDate(day, e.target.cellIndex);
open();
document.querySelector("#bg").addEventListener("click", close);
init.activeDTag = e.target;
init.activeDate.setDate(day);
}
});
참고
https://songsong.dev/11
https://wonpaper.tistory.com/223
https://gurtn.tistory.com/54
https://zenna9.tistory.com/36
https://im-developer.tistory.com/115