<div class="fileUpload-container">
<div class="fileUpload">
<label for="fileElem_1" class="btn-m btn-point marginR10">파일 선택</label>
<input type="file" id="fileElem_1" class="fileUpload__input visually-hidden"
accept=".gif" onchange="handleFile(this, this.files)">
<span class="fileUpload__title">선택된 파일이 없습니다.</span>
</div>
<p class="fileUpload__message">
gif/1mb 이하 등록 허용
</p>
</div>
: 파일 인풋 태그를 그대로 사용하면 미관상 안좋아서 버튼을 따로 생성하고, <input type="file">
에 .click()을 통해 파일 업로드 창을 띄우는게 일반적이다.
: 하지만 더 쉬운 방법으로, label 태그를 사용해서 click 이벤트 없이 업로드 창을 띄울 수 있다.(label의 for 속성과, input 태그의 id값을 일치시켜준다.)
: 이때, input 태그가 display : none, 이거나 visibility : hidden; 이면 동작을 안하기 때문에(왜인지 잘모름) 아래와 같이 "visually-hidden"이라는 클래스를 적용해서 안보이게 만들어준다.
: 여기서 accept="" 속성을 통해서, 선택가능한 파일의 확장자를 제한할 수 있다. 하지만, 초기에 파일업로드창에서 해당하는 확장자로 필터링하여 보여줄 뿐, 실제로 모든 파일 선택하기를 통해 다른 확장자를 추가할 수 있다.
=> 따라서 Js 코드를 통해 처리를 해줘야한다.
: onchange 이벤트 바인딩을 통해서, 선택된 파일이 변경될 경우(파일이 선택될 경우) 이벤트를 핸들링한다.
=> handleFile()의 인자로 넘어가는 this : input 태그, this.files : input 태그를 통해 접근가능한 fileList가 된다.
: multiple 속성을 주면 여러개의 파일을 선택할 수 있다.
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
}
// 파일 선택 함수
function handleFile(self, files) {
self = $(self);
const $title = self.parent().find(".fileUpload__title");
if (!$title.length) return false;
//1.
if (!files.length) {
$title[0].innerHTML = "선택된 파일이 없습니다.";
return false;
}
//2.
if (!checkFileExt(self, files)) {
alert("확장자를 확인해주세요");
self[0].value = "";
$title[0].innerHTML = "선택된 파일이 없습니다.";
return false;
};
const _file = files[0];
//3.
$title[0].innerHTML = _file.name.trim();
}
- 전달받은 인자 files의 length 프로퍼티를 통해서 선택된 파일이 있는지 여부를 체크한다. 선택된 파일이 없으면, $title태그의 텍스트를 변경하고, 함수를 종료한다
- checkFilExt()함수를 통해서 추가된 파일의 확장자가 accept 속성에 정의된 파일의 확장자와 일치하는지 여부를 판단한다.
// 파일 확장자 체크 함수
function checkFileExt(el, files) {
//1.
let accepts = el[0].accept; //".jpg .png .jpeg"
if (!accepts) return true;
//2.
accepts = accepts.split(",").map(function (ext) {
return ext.replace(".", "").trim();
}) //["jpg", "png", "jpeg"]
//3.
var ext = files[0].name.match(/\.([^\.]+)$/)[1]; //png, jpg..
//4.
if (!accepts.includes(ext)) return false;
//5.
return true;
}
- 인자로 전달받은 el(input 태그)의 accept 속성에 정의된 값을 문자열 형태로 전달받는다.
- Array의 메소드를 통해서, accept 문자열을 배열 형태로 변환한다.
- 정규식을 통해서 전달받은 files의 name 프로퍼티중 확장자에 해당하는 부분을 추출한다.
- Array.includes() 메소드를 통해서 ext가 accepts 배열안에 포함되어 있지 않으면(허용되지 않은 확장자) false를 리턴하고 함수를 종료한다.
- 올바른 확장자가 들어갔으면, true를 리턴한다.
: 영문 대소문자, 특수문자(-), 숫자만 입력 가능하도록 처리
var regExp = /[^(a-zA-Z0-9-)]/gi;
=> "-" (하이픈)의 경우 특수문자이기때문에, (역슬래시)로 문자임을 표시한다.
const REG_EXP = {
onlyNum: /[^0-9]/g, //숫자만 입력가능 === 숫자가 아닌 문자들 체크
onlyEng: /[^a-zA-Z]/g, //영문 대소문자만 입력 가능 === 영어가 아닌 문자들 체크
includeSymbol: /[^0-9a-zA-Z\-]/gi, //숫자, 영어대소문자, 특수문자 - 만 입력가능
}
[^] 는 not의 의미 => 따라서 영어 소문자/대문자 숫자, 특수문자 - 이 아닌 문자를 찾는다.
특수문자 앞에는 \를 포함해야한다.
string.match() => 정규식에 해당하는 문자들 배열 형태로 반환
string.replace(regExr, "") => 정규식에 해당하는 문자들 공백으로 변환
regExp.test(string) => 정규식에 해당하는 문자열이 있는지 여부를 boolean 값으로 반환
/regexr/i
// => 시작 종료 기호
regexr => 패턴
i => 플래그 라고한다.
2.1 exec => 찾은 문자열의 인덱스까지 반환? ===> string.match(RegExp)와 비슷
2.2 test => true/false 반환
3.1 i => 대소문자 구별 없이 검색
3.2 g => 문자열 내의 모든 패턴 검색
3.3 m => 문자열의 행이 바뀌더라도 계속 검색
4.1 예제
const regexr = / ... /;
여기서 .은 임의의 문자 한개를 의미한다.
const targetStr = 'AA BB Aa Bb'
targetStr.match(regexr) => "AA "가 검색됨.
+ : 앞선 패턴 반복
| : Or 의미
// 'A' 또는 'B'가 한번 이상 반복되는 문자열을 반복 검색
// 'A', 'AA', 'AAA', ... 또는 'B', 'BB', 'BBB', ...
const regexr = /A+|B+/g;
// 'html'로 끝나는지 검사
// $ : 문자열의 끝을 의미한다.
const regexr = /html$/;
function bindKeyupEvents() {
const REG_EXP = {
onlyNum: /[^0-9]/g,
onlyEng: /[^a-zA-Z]/g,
includeSymbol: /[^0-9a-zA-Z\-]/gi,
}
$(".lengthCheck").on("keyup", function (e) {
const $titleLength = $(this).parent().find(".currentInput-length")[0];
const dataReg = $(this).data("regExp");
//길이 제한, 입력 제한이 있는지 확인한다.
const MAX_LENGTH = !!this.maxLength ? this.maxLength : null;
const regExp = dataReg ? REG_EXP[dataReg] : null;
let _value = $(this).val();
//regExp.test(string) => 정규식에 해당하는 문자가 있으면 true, 없으면 false를 반환한다.
//따라서 정규식에 해당하는(입력 제한되는 문자)가 있으면 빈 공백으로 변경한다.
if (regExp && regExp.test(_value)) {
_value = _value.replace(regExp, "");
}
//문자열이 입력 최대 길이보다 커지면, String.slice() 메소드를 이용해서 최대 길이까지 문자를 자른다.
if (MAX_LENGTH && MAX_LENGTH < _value.length) {
_value = _value.slice(0, MAX_LENGTH);
}
$(this).val(_value);
if ($titleLength) {
$titleLength.innerHTML = $(this).val().length;
}
})
}
https://dragoner.tistory.com/18