Open HyeonJin-Jang opened 3 years ago
function getDateTimeInfo(dt) {
const nowDt = new Date();
const targetDt = new Date(dt);
const nowDtSec = parseInt(nowDt.getTime() / 1000);
const targetDtSec = parseInt(targetDt.getTime() / 1000);
const diffSec = nowDtSec - targetDtSec;
if(diffSec < 120) {
return '1분 전';
} else if(diffSec < 3600) { //분 단위
return `${parseInt(diffSec / 60)}분 전`;
} else if(diffSec < 86400) { //시간 단위
return `${parseInt(diffSec / 3600)}시간 전`;
} else if(diffSec < 604800) { //일 단위
return `${parseInt(diffSec / 86400)}일 전`;
}
return targetDt.toLocaleString();
} // --> common.js
feed_id
, contents_img[0]
, isFav
, favCnt
, CmtCnt
, isCmt
userForFav
, userForCmt
설정 필요 html
bootstrap
- grid
, image
, spinners
mypage.html
<div id="mypageFeed">
<!---
<div id="mypageFeedContainer" th:attr="data-fid=${feed_id}"> 🔸 🔄* 반복 출력
<img src="/pic/feed/{feed_id}/{contents_img}" class="img-thumbnail"
onerror="this.src=/img/feed/error.png">
</div>
-->
</div>
- 이미지
- `th:attr` , `/pic/feed/{feed_id}/{contents_img}` , `onerror="this.src=/img/feed/error.png"`
## `js`
- `mypageFeed.js`
- `feedElem`
- `loadingElem`
- `mypage_id` 👉🟦`getFeedList`🟦
- `limit` 👉🟦`getFeedList`🟦
- `itemLength` 👉🟦`getFeedList , scrollInfinity`🟦
- `getFeedList`
- `makeFeedList`
- `scrollInfinity`
- `hideLoading`
- `showLoading`
```js
FeedObj = {
feedElem : document.querySelector('#mypageFeed'),
loadingElem : document.querySelector('#loading'),
mypageList : mypageConstElem.dataset.pid,
limit : 12,
itemLength : 0,
getFeedList : function(page) {
this.showLoading();
fetch(`/profile/mypageList?mypage_id=${this.users_id} 👉🟦users_id , limit🟦
&page=${page}&limit=${this.limit}`)
.then(res => res.json())
.then(myJson => {
console.log(myJson);
this.itemLength = myJson.length; 👉🟦itemLength (인피니티스크롤에서 쓰임)🟦
this.makeFeedList(myJson);
}).catch(err => {
console.log(err);
feedElem.innerHTML(`<img src="/img/feed/error.png" class="img-thumbnail wh400">`)
}).then(() => {
this.hideLoading();
});
},
makeFeedList: function(data) {
if(data.length == 0) { return; }
for(let i=0; i<data.length; i++) {
const item = data[i];
}
},
setScrollInfinity: function(target) {
target.addEventListener('scroll', () => {
const {
scrollTop,
scrollHeight,
clientHeight
} = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 5 && this.itemLength === this.limit) {
this.itemLength = 0;
this.getFeedList(++this.currentPage);
}
}, { passive: true });
},
hideLoading: function() { this.loadingElem.classList.add('hide');},
showLoading: function() { this.loadingElem.classList.remove('hide'); }
}
java , sql
FeedDTO
int mypage_id
int page
int limit
int user4FavCmt
public int getStartIdx( )
FeedDomain
int feed_id
)int isFav
int isCmt
int favCnt
int cmtCnt
ContentsEntity contents
(contents_id , contents_img
) - resultMap
FeedMapper
feed
테이블의 feed_id
에 대해 특정한 게시물에 대한 정보(대표사진과 사진의 기본키, 좋아요 개수와 댓글 개수, 로그인 유저의 좋아요 여부와 댓글 여부)를 얻기 위한 SQL
List<FeedDomain> selMypageList(FeedDTO param)
hover
<i class="bi bi-heart-fill"></i>
검정 하트<i class="bi bi-heart"></i>
빈 하트<i class="bi bi-chat-left-quote-fill"></i>
검정 말풍선<i class="bi bi-chat-left-quote"></i>
빈 말풍선const mementos = [];
mementos.push(feedElem.innerHTML);
mementos.push(`
<div class="wh70 blurImg"></div>
`);
mypage.html.id
: mypageDetailModal
mypageDetail.js
: showMypageDetail(feed_id, mypage_id, isFav, isCmt)
getMypageDetail(feed_id, mypage_id, isFav, isCmt)
/profile/mypageDetail?feed_id=${feed_id}&mypage_id=${mypageId}&isFav=${isFav}&isCmt=${isCmt}
setMypageDetail(data)
set Profile
- users_img, users_nickname, getDateTimeInfo(users_regdt)
setImgSlide
- contents
, bootstrap
setFav
- feed_fav
, isFav
setCmt
- cmt
, cmt_fav
, isCmt
FeedDTO
FeedDomain
ProfileController
@ResponseBody , @GetMapping(/mypageDetail)
FeedDomain mypageDetail(FeedDTO)
ProfileService
: FeedDomain selMypageDetail(FeedDTO param)
ProfileMapeer
: FeedDomain selMypageDetail(FeedDTO param)
MODAL
<div class="modal fade" tabindex="-1" id="12345678">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle">12345678</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="modalList">
<p>12345678</p>
</div>
</div>
</div>
</div>
<div class="modal" id="mypageDetailModal" tabindex="-1">
이랑data-bs-toggle="modal" data-bs-target="#mypageDetailModal"
mypageFeedElem.dataset.bsToggle = "modal";
mypageFeedElem.dataset.bsTarget = '#mypageDetailModal';
grid
+ overflow
+ table
+ floating lables
<div class="modal fade" tabindex="-1" id="mypageDetailModal">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content container">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body row row-cols-2 " id="modalList">
<!---1. 이미지 --->
<div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators" id="imgBtnDiv">
<!--- 이미지 밑 버튼 반복
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
--->
</div>
<div class="carousel-inner" id="imgDiv">
<!--- 이미지 반복
<div class="carousel-item active">
<img src="ㄲㄲㄲㄲ" class="d-block w-100">
</div>
--->
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<!--- 2. 댓글 + 좋아요 --->
<div id="favCmtDiv">
<!-- 2-1.댓글리스트 -->
<div class="overflow-auto table-responsive">
<table class="table align-middle table-borderless table-hover" id="cmtDiv">
<!---댓글 (프로필,닉네임,내용,좋아요,좋아요 수) 반복
<tr>
<th scope="row">ㄲㄲㄲㄲ</th>
<td>ㄲㄲㄲㄲ</td>
<td>ㄲㄲㄲㄲ</td>
<td>ㄲㄲㄲㄲ</td>
</tr>
--->
</table>
</div>
<!--- 2-2. 아이콘 --->
<div id="icnDiv"></div>
<!---댓글 쓰기--->
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="내 생각은....">
<label for="floatingInput">댓글 쓰기</label>
<button type="button" class="btn btn-primary" id="cntBtn"><i class="bi bi-vector-pen"></i></button>
</div>
</div>
</div>
</div>
</div>
</div>
UNDO
memento
형식 https://stackoverflow.com/questions/54416318/how-to-make-a-undo-redo-function
const mementos = []
const input = document.querySelector('input')
function saveMemento() {
mementos.push(input.value)
}
function undo() {
const lastMemento = mementos.pop()
input.value = lastMemento ? lastMemento : input.value
}
<h4> Type some characters and hit Undo </h4>
<input onkeydown="saveMemento()" value="Hello World"/>
<button onclick="undo()">Undo</button>
js
배열의 push()
, pop()
함수push
: 배열의 끝에 아이템을 추가한다. pop
: 배열의 마지막 아이템을 제거한다. elem.classList.add()
elem.append() + elem.lastElementChild.remove()
addEvent : function (elem) {
const imgElem = elem.firstElementChild;
elem.addEventListener('mouseover', () => {
imgElem.classList.add('blurImg');
this.showIcn(elem);
});
elem.addEventListener('mouseout', () => {
imgElem.classList.remove('blurImg');
this.hideIcn(elem);
});
},
showIcn : function (elem) {
const favIcn = this.favIcn(elem.dataset.isfav);
const cmtIcn = this.cmtIcn(elem.dataset.iscmt);
const icnElem = document.createElement('div');
icnElem.id = 'icn';
icnElem.append(favIcn);
icnElem.append(cmtIcn);
icnElem.style.position = 'absolute';
elem.append(icnElem);
},
hideIcn : function (elem) {
if(elem.childElementCount>1) {
elem.lastElementChild.remove();
}
}
display: none
visually-hidden
을 써야한다.elem.classList.add('visually-hidden')
flex
취소하기style
속성을 설정해야 한다.display
의 속성은 block
이다.<div class="modal-footer" style="display: block">
max-height
이 있어야 한다. 안그럼 작동하지 않는다
<div class="overflow-auto" style="max-height: 500px">
fecth CATCH 오작동
throw new Error(`${res.status}`);
return res.text().then(text => {throw new Error(text)})
res.status === 200
fetch(URL)
.then(res => {
if (res.statusCode === 200) {
return res.json();
}
return res.text().then(text => {throw new Error(text)})
}).then(myJson => {
console.log(myJson);
if (myJson.length) {
this.itemLength = myJson.length;
this.makeFeedList(myJson);
} else {
console.log('게시물 없음');
feedElem.innerHTML = '<img src="/img/feed/empty.jpg" class="img-thumbnail wh400">';
}
}).catch(err => {
console.log('에러 : ' + err);
feedElem.innerHTML = '<img src="/img/feed/error.png" class="img-thumbnail wh400">';
}).then(() => {
this.hideLoading();
});
res.ok
fetch(URL)
.then(res => {
if (res.ok) {
return res.json();
}
return res.text().then(text => {throw new Error(text)})
}).then(myJson => {
console.log(myJson);
if (myJson.length) {
this.itemLength = myJson.length;
this.makeFeedList(myJson);
} else {
console.log('게시물 없음');
feedElem.innerHTML = '<img src="/img/feed/empty.jpg" class="img-thumbnail wh400">';
}
}).catch(err => {
console.log('에러 : ' + err);
feedElem.innerHTML = '<img src="/img/feed/error.png" class="img-thumbnail wh400">';
}).then(() => {
this.hideLoading();
});
img.onerror
onerror="this.src="
height:100% 또는 width:100%
가 없어야 한다.object-fit: contain;
mypage
리스트, 하나의 게시물의 댓글과 좋아요 수만큼 중복되어 나타나는 버그SQL
에 GROUP BY
안해서 생긴 문제 SELECT
A.feed_id, IFNULL(B.cnt, 0) AS favCnt, IFNULL(D.cnt, 0) AS cmtCnt
, CASE WHEN E.feed_id IS NULL THEN 0 ELSE 1 END AS isFav
, CASE WHEN F.feed_id IS NULL THEN 0 ELSE 1 END AS isCmt
FROM feed A
LEFT JOIN (
SELECT feed_id, COUNT(feed_id) AS cnt
FROM feed_fav
GROUP BY feed_id
) B
ON A.feed_id = B.feed_id
LEFT JOIN (
SELECT feed_id, COUNT(feed_id) AS cnt
FROM cmt
GROUP BY feed_id
) D
ON A.feed_id = D.feed_id
LEFT JOIN feed_fav E 👈 🔺GROUP BY하지 않아서🔺
ON E.users_id = 2 AND A.feed_id = E.feed_id
LEFT JOIN cmt F
ON F.users_id = 2 AND A.feed_id = F.feed_id
WHERE A.users_id = 2 👈 🔺GROUP BY하지 않아서🔺
ORDER BY A.feed_id DESC
👇 올바른 SQL
SELECT
A.feed_id, IFNULL(B.cnt, 0) AS favCnt, IFNULL(D.cnt, 0) AS cmtCnt
, CASE WHEN E.feed_id IS NULL THEN 0 ELSE 1 END AS isFav
, CASE WHEN F.feed_id IS NULL THEN 0 ELSE 1 END AS isCmt
FROM feed A
LEFT JOIN (
SELECT feed_id, COUNT(feed_id) AS cnt
FROM feed_fav
GROUP BY feed_id
) B
ON A.feed_id = B.feed_id
LEFT JOIN (
SELECT feed_id, COUNT(feed_id) AS cnt
FROM cmt
GROUP BY feed_id
) D
ON A.feed_id = D.feed_id
LEFT JOIN ( 👈 🔺GROUP BY🔺
SELECT users_id, feed_id
FROM feed_fav
GROUP BY feed_id
) E
ON E.users_id = 2 AND A.feed_id = E.feed_id
LEFT JOIN ( 👈 🔺GROUP BY🔺
SELECT users_id, feed_id
FROM cmt
GROUP BY feed_id
) F
ON F.users_id = 2 AND A.feed_id = F.feed_id
WHERE A.users_id = 2
ORDER BY A.feed_id DESC
img.onerror
, 이미지 맞추기https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-894680719
전체구조 , :
https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-890378516
마이페이지 리스트 구조,
hover
:https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-890393224
마이페이지 디테일 구조 , 부트스트랩
MODAL
:https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-893211214
undo
기능 :https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-894040980
부트스트랩 숨기기-
display: none
, 가로영역 다 차지하기(flex
취소하기) , 스크롤 :https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-894067055
fecth CATCH
오작동 :https://github.com/WHYGRAM/DONELISTS-ERRORS/issues/48#issuecomment-894091653
mypage
리스트 버그 :