[JS] 헤더 고정 스크롤 구현
2020. 11. 7. 18:03ㆍ프론트엔드/JAVASCRIPT
728x90
[헤더고정스크롤 구현]
요건 : JSP내에서 엑셀다운로드를 할 수 있는 테이블 만들어야 하는데, 화면에 보여질 때 헤더는 고정이 된 상태에서 스크롤시 동적으로 리스트를 생성해야함
방법1 . 임시테이블 하나 더 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="asset/js/viewer/jQuery/jquery-1.12.4.min.js"></script>
<style>
table{ border:1px solid black; border-collapse: collapse;}
th, tr, td{border:1px solid black;}
#resultTable{width:100%;}
#resultWrap {overflow-y:auto; height:200px;}
</style>
</head>
<body>
<script>
$('document').ready(function(){
//실제보여지는 테이블의 'td' width를 받아와서 fixedTable(고정헤더) 'th' width 재설정
var $table = $('#resultTable'),
$bodyCells = $table.find('tbody tr:first').children(),
colWidth;
colWidth = $bodyCells.map(function(){
console.log('tr width : '+ $(this).width());
return $(this).width();
}).get();
//$table.find('thead tr').children().each(function(i,v){
$("#fixedTable").find('thead tr').children().each(function(i,v){
//var colWidth = colWidth[i];
$(v).width(colWidth[i]);
})
});
</script>
<div class="modal-body">
<div id="searchWrap" class="innerWrap">
<input type="text" name="searchWord" id="searchWord" value=""/>
<button type="button" id="searchBtn" class="btn btn-default">검색</button>
<table id="fixedTable" class="table">
<thead>
<tr id="">
<th>KEY</th>
<th>파일이름</th>
<th>생성일자</th>
</tr>
</thead>
</table>
</div>
<div id="resultWrap" class="innerWrap list-group" id="">
<table id="resultTable" class="table">
<thead>
<tr id="reultTitle" style="display:none;'">
<th>KEY</th>
<th>파일이름</th>
<th>생성일자</th>
</tr>
</thead>
<tbody id="resultTableBody">
<tr id="hiddienTr">
<td>내용0</td>
<td>내용0</td>
<td>내용0</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<button type="button" onclick="fnExcelReport('table','title');">Excel Download</button>
</div>
</div>
</body>
</html>
구현내용:
- 화면에 리스트로 보여줄 테이블(resultTable) 과 헤더만 보여질 테이블(fixedtable) 을 생성
- 화면에 리스트로 보여줄 테이블(resultTable) thead를 'display:none;'으로 설정해줌
- 스크롤 영역은 resultTable(table태그)을 감싸고 있는 div에 설정(overflow-y:auto;) -> tbody 영역에 스크롤을 줄 수도 있었지만, 나의 경우 스크롤시에 동적으로 리스트를 불러와야 하기 때문에 바닥에 스크롤이 닿는 시점을 알아야 해서 div에 스크롤을 설정(tbody에 스크롤을 설정할 경우 내부 컨텐츠 높이를 받아와야하는데 동적으로 리스트를 불러와야 해서 애매함)
- 테이블 width:100%로 설정된 상태에서 화면을 확인하면 헤더와 리스트의 width가 제각각이기 때문에 script로 resultTable의 td 각각의 width를 받아와서 fixedTable의 th에 width를 재설정해줌
문제점 : 위와 같이 정확하게 width 설정하기가 어려움 -> th각각에 width주면 되긴됨
방법2. thead에 position:fixed;를 설정하고 보이지 않는 tr태그를 추가( 'position:fixed;'만 줄 경우 첫번째 행이 보이지 않는 문제 발생 )
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="asset/js/viewer/jQuery/jquery-1.12.4.min.js"></script>
<style>
table{ border:1px solid black; border-collapse: collapse;}
th, tr, td{border:1px solid black;}
#resultWrap {overflow-y:auto; height:200px; }
#resultTable{width:100%;}
thead{position:fixed; background-color: #fff;}
</style>
</head>
<body>
<script>
$('document').ready(function(){
var $table = $('#resultTable'),
$bodyCells = $table.find('tbody tr:first').children(),
colWidth;
colWidth = $bodyCells.map(function(){
console.log('tr width : '+ $(this).width());
return $(this).width();
}).get();
$table.find('thead tr').children().each(function(i,v){
//var colWidth = colWidth[i];
$(v).width(colWidth[i]);
})
});
//엑셀다운로드시 호출함수
function fnExcelReport(id, title) {
var tab_text = '<html xmlns:x="urn:schemas-microsoft-com:office:excel">';
tab_text = tab_text + '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">';
tab_text = tab_text + '<xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>'
tab_text = tab_text + '<x:Name>Test Sheet</x:Name>';
tab_text = tab_text + '<x:WorksheetOptions><x:Panes></x:Panes></x:WorksheetOptions></x:ExcelWorksheet>';
tab_text = tab_text + '</x:ExcelWorksheets></x:ExcelWorkbook></xml></head><body>';
tab_text = tab_text + "<table border='1px'>";
var exportTable = $('#resultTable').clone();
exportTable.find('input').each(function (index, elem) { $(elem).remove(); });
exportTable.find('tbody').children('#hiddienTr').remove(); //임의의 첫번째 tr태그 제거 후 엑셀테이블 다운로드
tab_text = tab_text + exportTable.html();
tab_text = tab_text + '</table></body></html>';
var data_type = 'data:application/vnd.ms-excel';
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
var fileName = title + '.xls';
//Explorer 환경에서 다운로드
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) {
if (window.navigator.msSaveBlob) {
var blob = new Blob([tab_text], {
type: "application/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, fileName);
}
} else {
var blob2 = new Blob([tab_text], {
type: "application/csv;charset=utf-8;"
});
var filename = fileName;
var elem = window.document.createElement('a');
elem.href = window.URL.createObjectURL(blob2);
elem.download = filename;
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
}
}
</script>
<div class="modal-body">
<div id="searchWrap" class="innerWrap">
<input type="text" name="searchWord" id="searchWord" value=""/>
<button type="button" id="searchBtn" class="btn btn-default">검색</button>
</div>
<div id="resultWrap" class="innerWrap list-group" id="">
<table id="resultTable" class="table">
<thead>
<tr id="reultTitle" >
<th>KEY</th>
<th>파일이름</th>
<th>생성일자</th>
</tr>
</thead>
<tbody id="resultTableBody">
<tr id="hiddienTr">
<td>내용0</td>
<td>내용0</td>
<td>내용0</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
<tr>
<td>내용1</td>
<td>내용1</td>
<td>내용1</td>
</tr>
<tr>
<td>내용2</td>
<td>내용2</td>
<td>내용2</td>
</tr>
<tr>
<td>내용3</td>
<td>내용3</td>
<td>내용3</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<button type="button" onclick="fnExcelReport('table','title');">Excel Download</button>
</div>
</div>
</body>
</html>
구현방법
- table한 개 생성
- thead에 'position:fixed;'
- tbody에 첫번째 tr('#hiddenTr')을 임의로 추가 -> 첫번째 행이 가려지는 현상을 보안
- thead가 width가 설정이 따로 안됨 -> script로 테이블의 td 각각의 width를 받아와서 th에 width 재설정
- 엑셀다운로드함수 호출시 첫번째 tr('#hiddenTr')을 제거
방법3. thead에 position:fixed;를 설정하고 tbody에 'position:absolute;' 설정하기 -> 목적은 '방법2'로 구현할 경우 필요없는 행을 추가해야해서 tbody만의 top 위치를 설정해주려한 의도인데, 이렇게 할 경우 스크롤바가 사라짐..
728x90
'프론트엔드 > JAVASCRIPT' 카테고리의 다른 글
[JS] 반복문 (0) | 2020.11.11 |
---|---|
[JS] excel 다운로드 (0) | 2020.11.08 |
[JS 객체(Object) (0) | 2020.06.18 |
[JS] javascript:void(0) 과 # (0) | 2020.06.08 |
[JS] 클래스(Class) (0) | 2020.06.04 |