[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