(71)

자바스크립트로 계산기를 만들어보자

내 33년평생 이거보다 (삐-) 언어는 없을것이다... 어떻게 중괄호 위치 하나 삐꾸났다고 버그가 아오 참고로 ㄹㅇ 사칙연산만 되고 일일이 AC를 눌러줘야 하는 매우 불편한 계산기입니다… 근데 솔직히 삼각함수 지수 로그 이딴거 계산할거면 여기를 찾을 게 아니고 울프램알파를 가셔야죠… Reference https://velog.io/@jhyun_k/js-calculator JS 로 계산기 만들기 자바스크립트 연습 겸 하여 사칙연산 계산기를 만들어보았다. 처음에는 간단할 거라 생각했지만 생각보다 고려해야할 점이 많았다. 복잡한 계산은 아니지만 사칙연산 기능은 문제없이 작동된 velog.io 일단 HTML이나 CSS는 그냥 계산기 구색만 맞추고 색깔 그렇게 신경 못 썼다. 왜? 분명 자바스크립트에서 뭔가 안될..

자바스크립트로 만나이를 구해보자 (후편)

https://koreanraichu.tistory.com/367 자바스크립트로 만나이를 구해보자 (전편)이게 왜 전후편이 나뉘었냐면 변수때문에 시간을 너무 잡아먹었고 나는 출근을 해야 하는 몸입니다... 그래서 자잘한 것들... 뭐 CSS 마진 패딩 이딴거라던가 날짜에 시작점 끝점 정하는 뭐 그런koreanraichu.tistory.com내 어제 만나이 구현하는걸 짜면서 몇가지 추가할 게 있는데 출근해야 해서 못했다고 한 게 있었다. 네가지 있었는데 오늘은 그걸 다 구현해볼거다. 근데 생각보다 자잘한 기능이라 금방 끝남둥.날짜 시작이랑 끝 정하기이거는 JS선에서 건들 게 아니라 HTML파일에 있는 인풋태그를 건드리면 된다. input type=date 속성 중에 min이랑 max가 있는데 말 그대로 최..

자바스크립트로 만나이를 구해보자 (전편)

이게 왜 전후편이 나뉘었냐면 변수때문에 시간을 너무 잡아먹었고 나는 출근을 해야 하는 몸입니다... 그래서 자잘한 것들... 뭐 CSS 마진 패딩 이딴거라던가 날짜에 시작점 끝점 정하는 뭐 그런거 있죠? 그런게 아직 안됐음... 그래서 깃헙에 올린 버전은 '일단 계산만 해 주는' 버전입니다. 아무튼 그럼. 사실 기본적인 로직은 파이썬하고 다를 게 없다. 그리고 자바스크립트에서도 날짜를 다룰 수 있지. const birthday = document.querySelector('input[type="date"]'); const calButton = document.querySelector('button'); const yourAge = document.createElement('p'); const yourAg..

눈 내리는 효과 만들기

Reference https://gurtn.tistory.com/195 [JS] 눈 내리는 효과 만들기 완성 코드 See the Pen Canvas Snow by hyukson (@hyukson) on CodePen. 전체코드(보기) 더보기 const $canvas = document.querySelector("canvas"); const ctx = $canvas.getContext("2d"); const getRandomRadius = () => Math.random() * 1 + 0.5; const getR gurtn.tistory.com 사실 여기서 HTML이랑 CSS는 별 거 없다. 진짜로 별 거 없다. 이게 HTML이고 html { margin:0; padding:0; } body { margi..

폰트어썸(Font awesome)

그 왜 가끔 사이트 보면 기깔나는 아이콘인데 텍스트처럼 선택이 되는 뭐 그런 아이콘이 있을 것이다. 그 있어... 뭐 햄버거 버튼 별 이런거 있는데 별의별게 다 있다. 그리고 개발자 도구를 봤더니... 폰트 패밀리에 FontAwesome? 이게 뭐시여? 폰트어썸은 아이콘 라이브러리이다. 당연한 소리지만, 내가 처음 네이버 마이홈을 쓸 때는 CSS라는 개념이 없어서 속성도 죄 인라인에 줬고, 아이콘? 아이콘은 이미지 파일을 서버에 직접 업로드해야 했다. 그러면 색깔 잘못 올리면 어떻게 되냐고요? 걍 주옥되는겁니다. 새로 작업해서 새로 올려야 하거든... 이 얼마나 힘듭니까... 그때 컴퓨터가 램 16기가면 쥰내 비쌌어요... 하지만 얘는 CSS로 제어가 가능하기때문에 그냥 CSS로 색깔을 바꾸면 된다. 즉..

리스트뷰-그리드뷰 전환하기

씽크패드 펑션키 밖으로 뺀 사람 찾아서 조사버리겠다... 아무튼... 포고 인벤토리 보고 생각났던건데 이제서야 함... 귀차니즘이 이렇게 무섭습니다 여러분. https://github.com/koreanraichu/Javascript/tree/main/List-grid 코드는 여기 가서 봅시다. HTML이나 CSS 관련 코멘터리는 안할거임. 발단 일단 발단이 뭐냐... 위가 리스트 뷰, 아래가 그리드 뷰이다. 포켓몬고의 인벤토리는 원래 위쪽만 있었다가, 아래쪽도 일부 계정에 시범적용 후 현재는 전 계정에서 해당 설정을 할 수 있게 되었다. 일단 두 방식은 각각 장/단점이 있는데 리스트 뷰는 위의 사진처럼 아이템의 설명을 확인할 수 있고, 버리기 아이콘도 줄의 끝에 있기 떄문에 아이템이랑 거리가 있어서 아..

[HTML 요소] 라디오 버튼

라디오 버튼이 뭐임? 그 왜 회원가입 받거나 구글폼으로 설문조사 할 때 동그란 버튼 있죠? 중복으로 선택 안 되고 하나만 선택 되는. 지금은 그게 뭔데요? 지만 아래 예시를 보면 아마 바로 아 이거! 할 것이다. See the Pen Radio button 1 by koreanraichu (@koreanraichu) on CodePen. 봐봐요 이 버튼 어디서 봤잖아. 이게 라디오 버튼이다. 해당 예시에 JS는 적용 안돼서 그냥 선택만 할 수 있는 정도다. 바깥은 위험하니 이 아이들을 데려가렴! 이상해씨 파이리 꼬부기 { if (node.checked && node.value == "meat") { selectDish = "T본스테이크"; } else if (node.checked && node.valu..

개발자 도구는 장식이 아니다

브라우저에서 F12를 누르면 개발자 도구가 나온다. 아, 오페라는 컨트롤 시프트 I 눌러야 나옴. 아무튼... 가끔 글쓰다가 열리면 어이 이거 뭐야 하게 되지만 사실 이거, 장식이 아니다. 자바스크립트에서 console.log()로 출력하게 되면 결과물 확인할 때 콘솔창을 들러야 한다...만 그거 말고 다른 쓸모가 또 있다. 예전에 고대에서 일할 때 도움 됐던 팁임. 오늘은 파폭으로 열었다. 파폭도 개발자 도구 오른쪽에 고정할 수 있는데... 보니까 뭔가 복잡하다 그죠? 검사기에 있는 것들은 지금 내가 보고 있는 이 사이트(네이버 메인)의 DOM이다. 뭐 네이버 검색창이라던가, 내 정보창(로그인 상태니까), 뉴스, 웹툰 이런거 말하는거다. 여기서 DOM을 선택해서 볼 수도 있고, 직접 보고자 하는 요소에..

자바스크립트는 출력을 어떻게 하나요?

자 생각해봅시다. 파이썬은 print문으로 출력하잖음? 근데 자바스크립트에는 그런게 없어요. 여기서 오해하시면 안되는 게, 출력이 안되는 게 아니라 파이썬이나 C언어처럼 print 어쩌고로 적는 출력문이 없다는 얘기다. 그럼 어떻게 출력하나요? 그걸 이제 알아볼거다. 자바스크립트는 프론트엔드 삼신기(HTML, CSS, JS) 중 유일한 프로그래밍 언어이다. 거기서 더 나가면 리액트 뷰 앵귤러 삼대장이 기다리고 있지만 아무튼... 삼대장의 삼대장 걔네는 뭐 확장팩같은거고 걍 자바스크립트도 있긴 있잖아요? 그런데 자바스크립트가 왜 프론트엔드 삼신기냐... 프론트엔드 개발자는 HTML로 뼈대를 만들어서 CSS로 살을 붙이고 자바스크립트로 동작하게 하기 때문이다. 하아니 그런데 출력문이 없다고요? 그럼 어떻게 ..

자바스크립트에도 정규식이 있다고???

https://koreanraichu.tistory.com/118 정규식(Regular Expression)-기호와 메타문자 문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕 koreanraichu.tistory.com 여기서 정규식이 대충 와일드카드 같은거고(글은 분량상 두개로 나눴음) 파이썬에서는 re모듈을 쓴다고 했는데, 사실 파이썬 뿐 아니라 자바스크립트에서도 정규식을 쓸 수 있다. 정규표현식, 그러니까 정규식은 파이썬만의 전유물이 아니기때문에 다른 언어에서도 사용하는 방법이 다를 뿐이지 일단 쓸 수는 있다. 정규식에 대해 설명하면서 대충 '와일드카드 같은 것'이..

for, for in, for of, forEach

Python에는 for와 while이라는 반복문이 있고, 이 둘은 범위냐 조건이냐의 차이만 빼면 반복문이라는 기본 골자는 같은데, 이런 게 자바스크립트에도 당연히 있다. 라디오버튼 뺑뺑이 돌면서 얘가 뭘 체크했나 보는 것도 반복문의 일이기 때문. 그런데 이 반복문... Python처럼 심플하지 않아요... for, for in, for of See the Pen for, for in, for of by koreanraichu (@koreanraichu) on CodePen. 얘네들은 Pyhlogenic tree로 치자면 그 트리가 막 갈라지는 와중에도 진화적으로 매우 유사한 homolog이기 때문에 또이또이 쌤쌤임을 인정받은 애들... 맞는 비유인지는 모르겠지만, 자매나 형제같은 느낌이다. 그래서 형식 ..

매우 간단한 스크롤 이벤트를 해보자

addEventListener에 대해 설명하면서 스크롤 이벤트도 '있다'고 했는데, 이건 말 그대로 마우스를 스크롤했을 때 일어나는 이벤트이다. 그게 다다. Reference https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8 Javascript 스크롤 이벤트 web에서 발생하는 스크롤 이벤트를 이용해 다루는 방법을 써보았습니다. velog.io https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8 Javascript 스크롤 이벤트 web에서 발생하는 스크롤 이벤트를 이용해 다루는 방법을..

DOM 선택하는 방법 (부제: 너로 정했다?)

DOM은 Document Object Model의 약어로, XML이나 HTML에 접근하기 위한 일종의 인터페이스이다. 자바스크립트는 프론트엔드에서 많이 사용하는 언어의 특성인지는 모르겠지만 아무튼 이 DOM들을 지지고 볶는 게 가능하다. 이벤트 추가는 기본이고 생성 삭제 CSS 클래스 부여까지 다 된다. 남자친구 못 만드는 것만 빼면 만능... 어차피 여욱이도 못 구함 질량이 0이라 document.querySelector() 얘는 같이 다니는(?) 친구가 하나 있는데 바로 querySelectorAll()이다. 그럼 같은 역할인가요? 기본적으로는 그렇다. 기본적으로는 그런데 친구인 쿼리셀렉터올은 해당하는 요소를 죄다 가져온다. 예를 들어서 어떤 문서에 p태그가 6개 있다 그러면 쿼리셀렉터는 맨 위에꺼 ..

addEventListener()로 고급진 이벤트 추가하기

근데 생각해보니까 이거 전에 픽하는게 먼저 와야 하지 않나... 뭐 아무튼. 뭔가 기깔나는 것을 구현하기 위해 이 블로그 혹은 다른 블로그를 보다 보면 그런 게 있다. 어? HTML에서 온클릭도 안 줬는데 작동하네? 어? 이거 더블클릭 하니까 작동하네? 어? 스크롤 내리니까 작동하네? 를 알아보자. 굳이 버튼에 온클릭을 안 줘도 작동하는 비결이 바로 addEventListener()이다. getElementByID나 querySelector같은 걸로 DOM(쉽게 말하자면 문서의 어떤 요소)을 가져와서 addEventListener()로 이벤트를 추가할 수 있다. 이 추가라는 게 단순히 알림이나 콘솔 이런걸 떠나서 뭐 모달 소환 곱하기 이런 함수까지 된다. See the Pen Eventlistner by..

다크모드 간단하게 토글로 구현해보기

근데 말이 간단이지 헐 나 이것도 못해 개발자 하면 안되나봐 ㅠㅠ 이럴 정도는 아닙니다… Reference https://blogpack.tistory.com/1117 다크모드 토글 기능 구현과 다크모드 토글 디자인 구현 웹페이지, 또는 사이트에 적용하는 다크 모드는 구현하는 방법이 여러 가지 있습니다. CSS 속성을 기준으로 구분하면 사용된 배경색과 전경(글자) 색들을 바꾸기만 하는 간단한 구현이기 때문에 blogpack.tistory.com https://www.w3schools.com/howto/howto_css_switch.asp How To Create a Toggle Switch W3Schools offers free online tutorials, references and exercises..

자바스크립트로 계산기를 만들어보자

Coding/JavaScript 2024. 1. 30. 00:44
반응형

내 33년평생 이거보다 (삐-) 언어는 없을것이다... 어떻게 중괄호 위치 하나 삐꾸났다고 버그가 아오

 

참고로 ㄹㅇ 사칙연산만 되고 일일이 AC를 눌러줘야 하는 매우 불편한 계산기입니다… 근데 솔직히 삼각함수 지수 로그 이딴거 계산할거면 여기를 찾을 게 아니고 울프램알파를 가셔야죠…


Reference

https://velog.io/@jhyun_k/js-calculator

 

JS 로 계산기 만들기

자바스크립트 연습 겸 하여 사칙연산 계산기를 만들어보았다. 처음에는 간단할 거라 생각했지만 생각보다 고려해야할 점이 많았다. 복잡한 계산은 아니지만 사칙연산 기능은 문제없이 작동된

velog.io


일단 HTML이나 CSS는 그냥 계산기 구색만 맞추고 색깔 그렇게 신경 못 썼다. 왜? 분명 자바스크립트에서 뭔가 안될거같아서... 그리고 진짜 뭐가 안돼서 고생함 ㅠ

 

<html>
    <head>
        <title>사칙연산 계산기</title>
        <link href="style.css" rel="stylesheet">
    </head>
    <body>
        <h1>이다 이것 계산기</h1>
        <div class="wrap">
            <div class="resultDisplay">
                <div class="display"></div>
            </div>
            <div class="keypad">
                <button class="ac">AC</button>
                <button class="operator" id="plus"">+</button>
                <button class="operator" id="minus">-</button>
                <button class="operator" id="multiple">X</button>
                <button class="numBtn">7</button>
                <button class="numBtn">8</button>
                <button class="numBtn">9</button>
                <button class="operator" id="divide">/</button>
                <button class="numBtn">4</button>
                <button class="numBtn">5</button>
                <button class="numBtn">6</button>
                <button class="result" id="result">=</button>
                <button class="numBtn">1</button>
                <button class="numBtn">2</button>
                <button class="numBtn">3</button>
                <button class="numBtn">0</button>
            </div>
        </div>
        <script src="script.js"></script>
    </body>
</html>

상여자는 클래스 외에는 붙이지 않는다. 어차피 ID는 JS에서 갖고오지도 않음 나 편하라고 붙인거지… 아무튼 버튼은 하나하나 정성스럽게… 만들어줍니다. …놋북이 작아서 그런지 오래돼서 그런지 키 안눌려서 오타남… 아무튼 만들어주세요.

 

@font-face {
    font-family: 'DungGeunMo';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_six@1.2/DungGeunMo.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

:root {
    --main-color: #331B3F;
    --sub-color: #ACC7B4;
    --white: #ffffff;
    --black: #000000;
}

html {
    margin: 0;
    padding: 0;
}

body {
    font-family: 'DungGeunMo';
    font-weight: 700;
}

h1 {
    text-align: center;
    color: var(--main-color);
}

.wrap {
    width: 480px;
    margin: 0 auto;
    background-color: var(--sub-color);
    border: 1px solid transparent;
    border-radius: 10px;
}

.resultDisplay {
    display: flex;
    flex-direction: column;
    height: 50px;
    font-size: 30px;
    border-radius: 10px;
    background-color: var(--white);
    padding: 10px;
    margin: 10px 10px 0 10px;
    border: 1px solid var(--main-color);
}

.display {
    height: 20px;
    text-align: right;
}

.keypad {
    display: grid;
    padding: 10px;
    height: 480px;;
    gap: 15px;
    grid-template-columns: repeat(4, 1fr);
}

button {
    font-family: 'DungGeunMo';
    border: none;
    background-color: var(--main-color);
    color: var(--white);
    font-size: 24pt;
    border-radius: 10px;
}

.operator, .ac, .result {
    background-color: var(--black);
}

CSS도 사실 계산기 모양 만들려고 한거다. grid는 계산기 버튼이 네모네모 그리드이기 때문에 그리드 준 거다. 연산자랑 =, AC버튼은 색이 다른데 별로 차이는 안 난다. 그래도 눈뽕 오는 조합은 아니니까 넘어가자.

 

const buttons = document.querySelectorAll("button");
const operators = document.querySelectorAll(".operator");
const display = document.querySelector(".display");
const numBtn = document.querySelectorAll(".numBtn");
// 순서대로 1. 모든 버튼'들'. 2. 더하기 빼기 곱하기 나누기 =, 3. 결과창, 4. 숫자 버튼

자바스크립트는 DOM을 조작하기 위해서 일단 다 갖고오는 게 국룰이다.

 

let operatorOn = '';
let prevNum = '';
let nextNum = '';
//순서대로 연산자, 앞의 숫자, 뒤의 숫자

let calculate = (n1, operator, n2) => {
    let result = 0;
    switch (operator) {
        case '+':
            result = prevNum + nextNum;
            break;
        case '-':
            result = prevNum - nextNum;
            break;
        case 'X':
            result = prevNum * nextNum;
            break;
        case '/':
            result = prevNum / nextNum;
            break;
        default:
            break;
    }
    return String(result);
}
//입력받은 값을 연산자에 따라 계산한다

생각해봅시다. 계산이라는 건 연산자를 사이에 두고 앞에 숫자가 있고 뒤에 숫자가 있잖아요? 예를 들어서 2+2면 2 더하기 2 이런 식으로. 이거는 숫자 두 개(버튼 누르면 된다)랑 연산자가 정해지면 계산해서 결과 내놔라 이런 얘기다. 참고로 밑에서 한번 더 서술하겠지만 따로 0으로 나누는것에 대해 대비를 하지 않아도 된다.

 

let calculator = () => {
    let isFirstDigit = true;

    buttons.forEach((item) => {
        item.addEventListener('click', (e) => {
            let action = e.target.classList[0];
            let click = e.target.innerHTML;

            if (action === 'operator') {
                operatorOn = click;
                prevNum = display.textContent;
                display.textContent = '';
                isFirstDigit = true;
            }
            if (action === 'numBtn') {
                if (isFirstDigit && click === '0') {
                    return;
                }

                if (display.textContent === '' && operatorOn === '') {
                    display.textContent = click;
                    prevNum = display.textContent;
                } else if (display.textContent !== '' && operatorOn === '') {
                    display.textContent = display.textContent + click;
                    prevNum = display.textContent;
                } else if (display.textContent === '' && operatorOn !== '') {
                    display.textContent = click;
                    nextNum = display.textContent;
                } else if (display.textContent !== '' && operatorOn !== '') {
                    display.textContent = display.textContent + click;
                    nextNum = display.textContent;
                }
                isFirstDigit = false;
            }
            if (action === 'result') {
                display.textContent = calculate(prevNum, operatorOn, nextNum);
                isFirstDigit = true;
            }

            if (action === 'ac') {
                display.textContent = '';
                prevNum = '';
                operatorOn = '';
                nextNum = '';
                isFirstDigit = true;
            }
        });
    });
};

내 여기서 개고생한것이다… ㅡㅡ 여기가 바로 계산기 버튼을 누르는 것에 반응하는 부분이다. 그러니까 봐봐요? 2+2면 2 누르고, + 누르고, 2를 또 누를 거 아닙니까. 바로 그거다. 앞이랑 뒤를 어떻게 나누는지 컴퓨터한테 가르쳐주는거다.

 

buttons.forEach((item) => {
    item.addEventListener('click', (e) => {
        let action = e.target.classList[0];
        let click = e.target.innerHTML;

ForEach가 왜 있냐면 맨 위에서 가져올 때 숫자 표시할 창을 뺀 다른 요소들을 전부 document.querySelectorAll로 가져왔다. 그러면 이거 배열이라 반복문이 있어야 안에 있는 걸 꺼내올 수 있다. 오케이? 그니까 쉽게 말하자면 이 두 줄을 통해 당신이 누른 버튼의 클래스와 내용물을 가져오는거다.

 

if (action === 'operator') {
	operatorOn = click;
	prevNum = display.textContent;
	display.textContent = '';
	isFirstDigit = true;
}

정리하니까 탭이 가출했는데 아무튼… action에서 클래스를 가져왔는데 이게 operator, 그러니까 연산자면 앞에 숫자가 끝난거니까 끊고 뒤에꺼 가져와라 이 얘기. 여기 있는 isFirstDigit이라는 변수는 숫자가 0으로 시작할 때, 그러니까 0020, 003같은 애들을 20이랑 3으로 인식하게 해 준다. 뒤에 숫자를 입력할때도 저게 그대로 적용되기때문에 0이 아닌 다른 숫자로 시작할때까지 걍 입력중이라 0으로 나누는 것에 대해 굳이 처리할 필요가 없는 것.

 

if (action === 'numBtn') {
	if (isFirstDigit && click === '0') {
		return;
	}

	if (display.textContent === '' && operatorOn === '') {
		display.textContent = click;
		prevNum = display.textContent;
	} else if (display.textContent !== '' && operatorOn === '') {
		display.textContent = display.textContent + click;
		prevNum = display.textContent;
	} else if (display.textContent === '' && operatorOn !== '') {
		display.textContent = click;
		nextNum = display.textContent;
	} else if (display.textContent !== '' && operatorOn !== '') {
		display.textContent = display.textContent + click;
		nextNum = display.textContent;
	}
	isFirstDigit = false;
}

위에 설명했던 첫 자리수가 0이면 무시하는 기능, 그러니까 0001을 1로 인식하는 기능이 위에 네 줄이다. 아래는 쉽게 설명하자면 분기점에 따라 앞의 수인지 뒤에 수인지를 나누는거라고 보시면 된다. display는 버튼 입력하면 숫자가 보이는 부분을 의미한다. 일단 operatorOn이 공백이 아니라는 건 일단 연산자를 입력했다는 얘기이기 때문에 operatorOn이 공백인 상태에서는 앞의 숫자가 되고, operatorOn이 공백이 아닐 때는 뒤의 숫자가 된다. 왼쪽 조건은 말 그대로 이미 입력된 숫자가 있으면 거기에 갖다 붙이라는 얘기. 2를 누르고 5를 누르면 25로 입력된다.

 

if (action === 'result') {
	display.textContent = calculate(prevNum, operatorOn, nextNum);
	isFirstDigit = true;
}

if (action === 'ac') {
	display.textContent = '';
	prevNum = '';
	operatorOn = '';
	nextNum = '';
	isFirstDigit = true;
}

그러고보니 함수가 둘다 김람다씨네… 아무튼. 우리 여기서 한번 생각해봅시다. operator는 따로 가져왔고, 숫자도 따로 가져왔는데 결과 보는거랑 AC버튼은 왜 안 가져왔는지 궁금했던 사람 있을거다. 일단 내가 그랬음. 어차피 위에서 버튼 전체를 가져왔기때문에 굳이 변수로 따로 가져오지는 않았다. 그리고 버튼들에서 결과 보기를 누르면 위에 만들었던 앞에꺼 연산자 뒤에꺼 계산하는 기능과 AC를 누르면 초기화하는 기능이다.

 

const buttons = document.querySelectorAll("button");
const operators = document.querySelectorAll(".operator");
const display = document.querySelector(".display");
const numBtn = document.querySelectorAll(".numBtn");
// 순서대로 1. 모든 버튼'들'. 2. 더하기 빼기 곱하기 나누기 =, 3. 결과창, 4. 숫자 버튼

let operatorOn = '';
let prevNum = '';
let nextNum = '';
//순서대로 연산자, 앞의 숫자, 뒤의 숫자

let calculate = (n1, operator, n2) => {
    let result = 0;
    switch (operator) {
        case '+':
            result = prevNum + nextNum;
            break;
        case '-':
            result = prevNum - nextNum;
            break;
        case 'X':
            result = prevNum * nextNum;
            break;
        case '/':
            result = prevNum / nextNum;
            break;
        default:
            break;
    }
    return String(result);
}
//입력받은 값을 연산자에 따라 계산한다

let calculator = () => {
    let isFirstDigit = true;

    buttons.forEach((item) => {
        item.addEventListener('click', (e) => {
            let action = e.target.classList[0];
            let click = e.target.innerHTML;

            if (action === 'operator') {
                operatorOn = click;
                prevNum = display.textContent;
                display.textContent = '';
                isFirstDigit = true;
            }
            if (action === 'numBtn') {
                if (isFirstDigit && click === '0') {
                    return;
                }

                if (display.textContent === '' && operatorOn === '') {
                    display.textContent = click;
                    prevNum = display.textContent;
                } else if (display.textContent !== '' && operatorOn === '') {
                    display.textContent = display.textContent + click;
                    prevNum = display.textContent;
                } else if (display.textContent === '' && operatorOn !== '') {
                    display.textContent = click;
                    nextNum = display.textContent;
                } else if (display.textContent !== '' && operatorOn !== '') {
                    display.textContent = display.textContent + click;
                    nextNum = display.textContent;
                }
                isFirstDigit = false;
            }
            if (action === 'result') {
                display.textContent = calculate(prevNum, operatorOn, nextNum);
                isFirstDigit = true;
            }

            if (action === 'ac') {
                display.textContent = '';
                prevNum = '';
                operatorOn = '';
                nextNum = '';
                isFirstDigit = true;
            }
        });
    });
};

calculator();

사실 전체 코드에는 맨 밑에 한줄이 더 있는데 설명할 때 굳이 언급할 필요는 없어보여서 걍 언급 안했다. 그죠 함수 짰으면 불러야 일하죠.

 

그래서 조촐하지만 계산기 완성. 고급 기능 필요하시면 위에도 썼지만 울프램알파 쓰십쇼. 

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

자바스크립트로 만나이를 구해보자 (후편)

Coding/JavaScript 2024. 1. 16. 23:37
반응형

https://koreanraichu.tistory.com/367

자바스크립트로 만나이를 구해보자 (전편)

이게 왜 전후편이 나뉘었냐면 변수때문에 시간을 너무 잡아먹었고 나는 출근을 해야 하는 몸입니다... 그래서 자잘한 것들... 뭐 CSS 마진 패딩 이딴거라던가 날짜에 시작점 끝점 정하는 뭐 그런

koreanraichu.tistory.com

내 어제 만나이 구현하는걸 짜면서 몇가지 추가할 게 있는데 출근해야 해서 못했다고 한 게 있었다. 네가지 있었는데 오늘은 그걸 다 구현해볼거다. 근데 생각보다 자잘한 기능이라 금방 끝남둥.


날짜 시작이랑 끝 정하기

이거는 JS선에서 건들 게 아니라 HTML파일에 있는 인풋태그를 건드리면 된다. input type=date 속성 중에 min이랑 max가 있는데 말 그대로 최대최소.
 

<input type="date" required pattern="\d{4}-\d{2}-\d{2}" min="1900-01-01" max="2900-12-31">

미디움 이놈들 HTML 무시하네 ㅡㅡ 저 패턴은 입력한 연도를 yyyy-mm-dd로 넘기는건데 일단 패스. 그 오른쪽에 min이랑 max 보여요? 이게 날짜 입력을 1900년 1월 1일~2900년 12월 31일로 제한한다는 얘기다.
 

그래서 최소값 저기 있음.
 

CSS 조정

이건 별거 없고 걍 마진 패딩 배경색 이런거 조절한게 다다.
 

현재 날짜 표시하기

저 스크린샷에 텍스트 한 줄 추가된 게 보이는가? 바로 오늘 날짜다. 말 그대로 오늘 날짜이기때문에 다른 날 저거 실행해보면 날짜가 다르게 뜬다.
 
사실 추가하는 절차는 간단하다. 일단 h1 아래에 h2 하나를 만들어준 다음, 자바스크립트로 가져와서 내용을 오늘 날짜로 수정하면 된다. 그래서 HTML에 한 줄, 자바스크립트에는 두 줄(가져와서 내용 바꿔야 함) 추가한 게 다다.
 

now.innerText = `오늘은 ${todayYear}년 ${todayMonth}월 ${todayDate}일입니다. `;
//오늘 날짜 표시란

백틱 만쉐이
 

미래 날짜 처리하기

UI/UX 그리고 기능 하나 만들때는 정말 여러 경우의 수를 고려해야 한다. 내 팩토리얼 짠거 보면 양수 팩토리얼 나오지 0! 나오지 소수점(정확히는 정수가 아닌 유리수) 감마펑션 때렸지 음수는 응 못해~ 했잖음? 세상은 넓고 사람들은 다양하므로 급나 나노 반도체 단위로 고려해야 할 게 많다. 잔걱정 많은 성격이 이럴 때는 도움이 된다니까... 
 
아무튼. 미래 날짜라는 게 무슨 소리냐... 오늘이 2024년 1월 16일인데 생일이 2024년 1월 30일이면 아직 안 태어난거다 그죠? 무슨 백투더퓨처도 아니고. 막말로 내가 91년생이면 90년에는 엄마 반 아빠 반이거나 엄마 뱃속에 있거나 둘 중 하나였음.
 

calButton.addEventListener('click',function(event){
    if (todayMonth > new Date(birthday.value).getMonth() + 1) { //현재 날짜의 월이 생일보다 크다면
        //만나이 겟또 
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear()}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
    else if (todayMonth == new Date(birthday.value).getMonth() + 1 && todayDate >= new Date(birthday.value).getDate()) { //현재 날짜의 월이 생일과 같'고' 현재 날짜의 일이 생일보다 같거나 크다면
        //만나이 겟또
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear()}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
    else if (todayYear - new Date(birthday.value).getFullYear() -1 < 0) { //생년월일로 미래의 날짜를 입력한다면?
        alert('미래 날짜로 만 나이를 계산할 수 없습니다!') //응 계산 못해요 

    }
    else { //아녀?
        //응 멀었어
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear() - 1}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
})

탭 정리하기 귀찮아서 일괄로 넣었는데, 저기 세번째 else if를 보면 다른 if들과 달리 innerText가 아니고 alert가 들어가 있다. 위에도 썼지만 생일이 현재 날짜보다 미래라는 건 아직 태어나지 않았다는... 그니까 엄마 반 아빠 반이거나 아직 뱃속에 있을 시기니까 만 나이라는 개념이 있을 수가 없다.
 
사실 저거 if를 또 몇개나 들이 부어야 하나 했는데 미래 날짜로 하면 만나이 걍 음수되더라… 그래서 만나이 계산했는데 음수뜨면 알림창 ㄱㄱ하게 했다. 그거 말고 뭐 크게 수정된 건 없음.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

자바스크립트로 만나이를 구해보자 (전편)

Coding/JavaScript 2024. 1. 16. 00:37
반응형

이게 왜 전후편이 나뉘었냐면 변수때문에 시간을 너무 잡아먹었고 나는 출근을 해야 하는 몸입니다... 그래서 자잘한 것들... 뭐 CSS 마진 패딩 이딴거라던가 날짜에 시작점 끝점 정하는 뭐 그런거 있죠? 그런게 아직 안됐음... 그래서 깃헙에 올린 버전은 '일단 계산만 해 주는' 버전입니다. 아무튼 그럼.


사실 기본적인 로직은 파이썬하고 다를 게 없다. 그리고 자바스크립트에서도 날짜를 다룰 수 있지.

 

const birthday = document.querySelector('input[type="date"]');
const calButton = document.querySelector('button');
const yourAge = document.createElement('p');
const yourAge_div = document.querySelector('.yourage');

위에서부터 순서대로 입력창(날짜), 버튼, 만나이를 표시하기 위한 p태그와 갖다붙일 div이다. 여기까지는 순조로울 거 없죠? 죄다 const로 가져와서 재선언 재할당 안된다. ...근데 어떻게 내용물은 바꾸는겨?

 

// 현재 날짜
const today = new Date;
let todayYear = today.getFullYear();
let todayMonth = today.getMonth() + 1;
let todayDate = today.getDate();

이것도 어려울 거 없다. 만나이를 현재 나이 기준으로 계산할거니까 당연히 오늘 날짜를 가져와야 하는 게 맞다. 그래서 연월일 가져왔다. 시요? 에이 그런건 필요엄서. 뭐 내가 오후 8시 50분에 태어났다고 생일날 20시 50분 될때까지 만나이 안오르는거 아니다. 만나이는 0시 되면 칼같이 오른다.

 

calButton.addEventListener('click',function(event){
    if (todayMonth > new Date(birthday.value).getMonth() + 1) { //현재 날짜의 월이 생일보다 크다면
        //만나이 겟또 
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear()}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
    else if (todayMonth == new Date(birthday.value).getMonth() + 1 && todayDate >= new Date(birthday.value).getDate()) { //현재 날짜의 월이 생일과 같'고' 현재 날짜의 일이 생일보다 같거나 크다면
        //만나이 겟또
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear()}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
    else { //아녀?
        //응 멀었어
        yourAge.innerText = `만 ${todayYear - new Date(birthday.value).getFullYear() - 1}세입니다. `;
        yourAge_div.appendChild(yourAge);
    }
})

긍꼐 문제가 어디다? 저기다.

 

일차적인 문제로, 저 인풋.value로 값을 가져오면 잘 되는데 인풋.value를 변수에 할당하면 object가 되고 Invalid Date가 뜨고 아주 난리 부르스를 추는데 해결방법이 없어 죄다 IE에서 에러터졌을 때 얘긴데 얘는 또 console.log로 확인해보면 yyyy-mm-dd로 월 일 다 두자리다. 근데 위에도 썼지만 내일 출근해야돼서 오래 잡지를 못하는거라. new Date(인풋.value)는 되니까 그냥 저기다 때려박았기 때문에 파이썬과 달리 전체 코드에서 생년월일 관련 변수만 없다.

 

그리고 거기서 오는 2차적인 문제가 바로 한눈에 알아보기 개같이 어려운 IF문이다. 파이썬이었으면 가로 스크롤따원 필요없었는데 쟤는 변수에 생년월일 갖고 온 게 할당이 안 돼서 IF문 조건이 저 꼬라지가 된 것. 저것때문에 로직짜면서 계산 이상하게 됐는데 당최 뭐가 뭔지 찾기가 힘들어서 골머리 앓았는데 알고보니 월 계산할 때 +1 안 붙여서 저렇게 된거였음... 여러분은 조심하십셔.

 

생일이 지난 경우(인데 1월이면 뭐...)

 

월은 같은데 아직 생일이 안 지난 경우

 

그냥 안 지났다.

 

후편에서 할 것은 크게

1. 현재 날짜 표시(현재 날짜는 0000년 00월 00일입니다!). 이거에 따라 출력하는 텍스트 역시 바뀔 예정.

2. 날짜 입력 제한 걸기(1900-1-1~2900-12-31)

3. 생년이 현재 날짜보다 뒤일때에 대한 처리. 아직 태어나지 않은 사람은 만 나이를 계산할 수 없기 떄문에 여기에 대한 처리도 해야 한다. 즉, 저 꼬라지 난 IF문에 일단 else if 하나가 더 추가될 예정. 아마 지금은 계산하면 음수가 나올 것이다.

4. CSS 조정(모양 잡기)

이정도... 내일도 밤샐듯.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

눈 내리는 효과 만들기

Coding/JavaScript 2023. 12. 10. 00:59
반응형

Reference

https://gurtn.tistory.com/195

 

[JS] 눈 내리는 효과 만들기

완성 코드 See the Pen Canvas Snow by hyukson (@hyukson) on CodePen. 전체코드(보기) 더보기 const $canvas = document.querySelector("canvas"); const ctx = $canvas.getContext("2d"); const getRandomRadius = () => Math.random() * 1 + 0.5; const getR

gurtn.tistory.com


사실 여기서 HTML이랑 CSS는 별 거 없다. 진짜로 별 거 없다.

 

<html>
    <head>
        <title>Let it snow</title>
        <link href="style.css" rel="stylesheet">
    </head>
    <body>
        <canvas width="1920" height='1080' />
    </body>
    <script src="script.js"></script>
</html>

이게 HTML이고

 

html {
    margin:0;
    padding:0;
}

body {
    margin:0;
    padding:0;
    overflow:hidden;
}

이게 CSS다. 진짜로 이게 다다.

 

그렇다는건 뭐다? 그죠 자바스크립트가 본론입니다. 일단 차근차근 따라가보면 어렵지 않은데 코드가 길어서 아 안돼 할 수는 있음... 근데 부분부분 뜯어보면 대충 이게 뭐 하는 함수인지 이해는 갈 것이다.


const $canvas = document.querySelector("canvas");
const ctx = $canvas.getContext("2d");

const getRandomRadius = () => Math.random() * 2 + 0.5;
const getRandomspeed = () => Math.random() * 0.3 + 0.5;
const getRandomDir = () => [-1, 1][Math.floor(Math.random() * 2)];

여기서 위의 두 줄은 캔버스(HTML에 캔버스가 또 있다... 뭔지는 모름)를 가져오는거고 아래 세 줄은 내릴 눈의 크기, 속도, 방향을 결정하는 함수다.

 

const Snow = {
    data: [],
    canvasWidth: $canvas.clientWidth,
    canvasHeight: $canvas.clientHeight,

    init() {
        Snow.make();
        Snow.loop();
    },

    loop() {
        Snow.move();
        Snow.draw();

        window.requestAnimationFrame(Snow.loop);
        //얘를 이용해서 재귀를 돌린다
    },

    make() {
        //눈 데이터를 만드는 함수
        const data = [];

        for (let i = 0; i < 250; i++) {
            const x = Math.random() * Snow.canvasWidth;
            const y = Math.random() * Snow.canvasHeight;

            const size = getRandomRadius();
            const speed = getRandomspeed();
            const dir = getRandomDir();

            data.push({ x, y, size, speed, dir });
        }

        Snow.data = data;
    },
    move() {
        //방향에 맞게 이동
        Snow.data = Snow.data.map((item) => {
            item.x += item.dir * item.speed;
            item.y += item.speed;

            //캔버스를 벗어났나요?
            const isMinOverPositionX = -item.size > item.x;
            const isMaxOverPositionX = item.x > Snow.canvasWidth;
            const isOverPositionY = item.y > Snow.canvasHeight;

            //벗어났다면 반대방향, 맨 위로
            if (isMinOverPositionX || isMaxOverPositionX) {
                item.dir *= -1;
            }
            if (isOverPositionY) {
                item.y = -item.size;
            }

            return item;
        });
    },
    draw() {
        //CSS에 배경색 설정이 따로 안됐던게 이것때문이었고만? 
        ctx.clearRect(0, 0, Snow.canvasWidth, Snow.canvasHeight);
        ctx.fillStyle = '#010101';
        ctx.fillRect(0, 0, Snow.canvasWidth, Snow.canvasHeight);

        Snow.data.forEach((item) => {
            ctx.beginPath();
            ctx.fillStyle = 'rgba(255,255,255,.6)';
            ctx.arc(item.x, item.y, item.size, 0, Math.PI * 2); //눈을 원형으로 만들어준다. 없으면 네모눈이 내리나? 
            ctx.fill();
            ctx.closePath();
        });
    },
};

이쪽이 메인디쉬인 Snow 함수. 여기에 눈을 뿌리기 위한 모든 요소가 들어간다. 일단 다섯개의 함수로 구성되어 있는데, 위쪽부터 순서대로 1) 눈을 만드는(init) 함수(얘는 뭐 하는건 없고 init() 호출하면 make랑 loop가 세트로 소환된다), 2) 재귀 돌리는 함수, 3) 눈 데이터를 만드는 함수(저기 for문 안에 250을 바꾸면 눈 갯수가 바뀐다), 4) 눈이 제대로 이동하게 해 주는 함수, 5) 배경 채우고 눈을 원형으로 만들어주는 함수 이렇게 다섯개가 있다.

 

보면 위에 두개는 단촐한데 밑에 세개는 어우... 뭐가 많다 그죠? 일단 make는 말 그대로 눈 데이터를 만드는 함수이다. 저기 for문에 있는 250을 다른 숫자로 바꾸면 눈 개수가 변화하는데 한 1000정도 넣어두면 저기 어디 시베리아 평원에서 흩날리는 눈폭풍을 볼 수 있다. 눈의 크기, 방향, 속도는 위에 짜 둔 함수가 랜덤으로 정해주는데 이 함수의 수치를 조절하면 눈의 크기, 속도, 방향도 제어가 가능하다.

 

move는 눈이 제대로 이동하게 해 주는 함수인데, 이게 뭔 소리냐면 눈이 내리다보면 화면 밖으로 나가게 된다. 그러면 그대로 빠이짜이찌엔 안녕히계세요 여러분 하는 게 아니라 방향을 잡아주는 역할을 하는 함수이다. 나도 처음에 보고 뭔소린가 했는데 코딩하면서 설명 보고 납득함.

 

draw에서 볼 것은 fillstyle와 arc이다. fillstyle은 배경색을 채워주는 것이고, 그래서 어두운 배경에 눈이 흩날리고 있음에도 CSS에는 아무것도 없이 오버플로우 숨기라는 것만 되어 있었다. arc은... 이게 있어야 눈이 둥글어진다.

 

window.onresize = () => {
    Snow.canvasWidth = $canvas.clientWidth;
    Snow.canvasHeight = $canvas.clientHeight;

    Snow.make();
};

이쪽은 창 크기가 바뀌면 그 크기에 맞춰서 눈 내리는 저기를 다시 정해주는 함수인 듯... 나도 모르것다.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

폰트어썸(Font awesome)

Coding/JavaScript 2023. 8. 11. 23:34
반응형

그 왜 가끔 사이트 보면 기깔나는 아이콘인데 텍스트처럼 선택이 되는 뭐 그런 아이콘이 있을 것이다. 그 있어... 뭐 햄버거 버튼 별 이런거 있는데 별의별게 다 있다. 그리고 개발자 도구를 봤더니... 폰트 패밀리에 FontAwesome? 이게 뭐시여?


폰트어썸은 아이콘 라이브러리이다. 당연한 소리지만, 내가 처음 네이버 마이홈을 쓸 때는 CSS라는 개념이 없어서 속성도 죄 인라인에 줬고, 아이콘? 아이콘은 이미지 파일을 서버에 직접 업로드해야 했다. 그러면 색깔 잘못 올리면 어떻게 되냐고요? 걍 주옥되는겁니다. 새로 작업해서 새로 올려야 하거든... 이 얼마나 힘듭니까... 그때 컴퓨터가 램 16기가면 쥰내 비쌌어요...

 

하지만 얘는 CSS로 제어가 가능하기때문에 그냥 CSS로 색깔을 바꾸면 된다. 즉, 이미지를 쌩으로 다시 작업하는 게 아니라 코드를 수정하면 된다. 이미지 작업보다 한결 간단하기도 하고, 굳이 컴퓨터에 뭘 깔 필요도 없으니 상당히 편하다.


일단 나는 계정을 미리 만들었고 키트도 무료 키트도 하나 받아놨다. 그래서 이전 설명글에 가끔 아이콘이 보였던 것...

 

kit에서는 내가 만든 키트들을 볼 수 있다. 저거 내 키트인데 이름이 kit인거다. 들어가면 세 가지 탭이 있는데 Set up을 보면

요로코롬 나 복사하슈~ 하는 코드가 있다. 코드는 혹시 몰라서 가렸음. 그걸 복사해서 HTML파일의 head태그 안에 붙여넣기 하면 끝이다. 그럼 아이콘은 어떻게 입력해요?

 

kits에서 아이콘 탭을 누르면 이 키트로 쓸 수 있는 아이콘 종류가 나온다. 나는 무료 키트라 저렇게 쓰는데 솔리드/레귤러로도 뽕 뽑고 남으니까 패스.

여기는 icons에서 solid를 눌러서 들어온 페이지이다. 여기서 본인이 원하는 아이콘을 찾을건데

free를 선택하면 무료 아이콘을 찾을 수 있다. 여기서 뭐 찾지... 메테오를 찾아보자.

여기서 맨 왼쪽 위에 있는거 쓸거다. 그러면 얘를 클릭하면 뭐가 뜨느냐...

요렇게 아이템 가져가기 전에 지지고 볶을 수 있습니다. 회전도 되고 사이즈 조절도 되고 색깔도 바꿀 수 있는데... 그거 말고 맡에 탭을 보면 HTML, React, Vue.js, SVG 이렇게 네 개가 있을 것이다. 저 아이콘을 당신이 써먹을 데에 맞게 가져가면 되는데 하아니 그럼 콘트롤씨 눌러야돼요? 아니 저거 클릭하면 복사 됩니다.

<i class="fa-solid fa-meteor"></i>

위 메테오를 HTML에 넣을거면 이걸 복사하면 된다. React랑 Vue.js는 뭐 또 분기가 있는데

React는 이렇고

Vue.js는 이렇고... 아니 이거 나 바이올렛 IGN인디... (IGN: 인 게임 네임)

<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M493.7 .9L299.4 75.6l2.3-29.3c1-12.8-12.8-21.5-24-15.1L101.3 133.4C38.6 169.7 0 236.6 0 309C0 421.1 90.9 512 203 512c72.4 0 139.4-38.6 175.7-101.3L480.8 234.3c6.5-11.1-2.2-25-15.1-24l-29.3 2.3L511.1 18.3c.6-1.5 .9-3.2 .9-4.8C512 6 506 0 498.5 0c-1.7 0-3.3 .3-4.8 .9zM192 192a128 128 0 1 1 0 256 128 128 0 1 1 0-256zm0 96a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm16 96a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"/></svg>

그... 뭔지는 모르겠는데 SVG 꼭 이렇게 넣어야되는거임...?

 

아무튼 이렇게만 하면 여러분도 HTML 페이지에 개 기깔나는 아이콘을 넣을 수 있습니다. 참 쉽죠?

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

리스트뷰-그리드뷰 전환하기

Coding/JavaScript 2023. 8. 9. 01:11
반응형

씽크패드 펑션키 밖으로 뺀 사람 찾아서 조사버리겠다... 아무튼... 포고 인벤토리 보고 생각났던건데 이제서야 함... 귀차니즘이 이렇게 무섭습니다 여러분.


https://github.com/koreanraichu/Javascript/tree/main/List-grid

 

코드는 여기 가서 봅시다. HTML이나 CSS 관련 코멘터리는 안할거임.

 

발단

일단 발단이 뭐냐...

위가 리스트 뷰, 아래가 그리드 뷰이다. 포켓몬고의 인벤토리는 원래 위쪽만 있었다가, 아래쪽도 일부 계정에 시범적용 후 현재는 전 계정에서 해당 설정을 할 수 있게 되었다.

 

일단 두 방식은 각각 장/단점이 있는데

리스트 뷰는 위의 사진처럼 아이템의 설명을 확인할 수 있고, 버리기 아이콘도 줄의 끝에 있기 떄문에 아이템이랑 거리가 있어서 아이템의 조작이 상대적으로 편하다. 하지만 도구가 많아질수록 표시하는 데 필요한 페이지 길이가 길어지기때문에 스크롤하기가 매우 귀찮고, 카테고리에 따라서는 가지고 있는 아이템의 종류와 수량을 한번에 파악하기가 어렵다는 단점이 있다. 위쪽은 도구이고 평소에는 일부 도구를 정리해서 저 정도지만, 저기에 상처약 두 종류만 추가돼도 리스트 뷰에서는 한번에 못 본다. 루어 모듈도 마찬가지.

 

그리드 뷰는 장단점이 리스트 뷰와 반대이다. 일단 한 눈에 아이템의 개수와 종류가 확 들어오고, 상대적으로 리스트 뷰에 비해 필요한 페이지 길이도 짧아서 스크롤 노가다를 덜 해도 된다. 하지만 아이템과 삭제버튼 간 간격이 좁기때문에 아이템을 버리려다가 다른 아이템을 선택하게 되는 사태가 자주 일어난다. 그리고 나야 본가 게임을 꽤 해봤지만 아예 포고로 처음 포켓몬을 접하거나, 아이템이 처음 보는 거라 설명이 필요할 때가 있는데, 이 때 그리드 뷰는 설명이 안보이기때문에 불편할 수도 있다.

 

만들어보자 

일단 네이버 글자 제한때문에 HTML 코드는 여기 다 못 올린다. 그러니 같이 보고 싶으면 깃헙으로 갑시다. 위에 주소 써뒀음.

 

<div class="button"> <!-- 전환 버튼이 위치할 곳 -->
    <label class="switch">
        <input type="checkbox">
        <span class="slider"></span>
    </label>
</div>

위에 이 부분은 슬라이드 버튼이다. w3school에서 긁어온건데 이번에는 네모네모 버튼으로 긁어봤음. 그리고 아래쪽이 본체다.

 

버튼과 아이템을 wrap이 싸고 있고, 버튼 밑에 아이템이 본체인데

대충 이런 구조... 길어서 아이템족은 또 접었는데 item-wrap 안에는 아이콘과 컨텐츠가 들어있다.

 

그래서 이런 식으로 리스트 뷰가 적용되는거다. CSS는 후가공 몇번 했음... ㅡㅡ 옆에 있는거 독이니까 당황하지 마십쇼. 지금 이 글 쓰는 OS 리눅스임.

 

여기서 그리드 뷰로 바꾸는 방법은 간단하다. 첫번째, 그리드 뷰로 바꿀 때 바뀔 요소에 대해 CSS를 적용한다(grid 클래스를 주고). 두번째, JS로 토글되게 한다. 그러면 JS보다 골치 덜 아픈(안아프다고 안했음) CSS부터 들어가보자... 예전에 다크모드 포스팅 한 걸 보셨던 분들이라면 아시겠지만, 그거 비슷하게 돌아간다.

 

.item.grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-gap: 5px;
    align-items: center;
    justify-content: center;
}

.icon.grid {
    max-width: 100%;
    margin: 0 auto;
    font-size: 5em;
    height: auto;
    width: auto;
}

.contents.grid {
    display: none;
}

일단 여기서 그리드 뷰로 바꾸게 되면 바뀌는 거 세 가지다. 아이템(아이템 래퍼를 담고 있는 거)은 display가 그리드가 되고, 3등분 그리드로 안의 컨텐츠를 담는다. contents는 대충 설명같은 느낌인데(위에 보면 아이콘 옆에 있는 글이 contents), 그리드 뷰에서는 contents를 안 보이게 할거니까 display 속성을 none으로 했다. 그리고 아이콘의 경우 크기를 더 키웠다. 아니 쟤가 제일 잘 나가니까 당연한거 아님?

 

//가져올건 이 쪽
let toggleButton = document.querySelector('.slider');
let viewItem = document.querySelector('.item');
let viewCont = document.querySelectorAll('.contents');
let viewIcon = document.querySelectorAll('.icon');

//실행 코드
toggleButton.addEventListener("click", function () {
    if (viewItem.classList.contains('grid')) { //.item은 하나밖에 없어서 하나만 가져왔습니다 
        viewItem.classList.remove('grid');
    } else {
        viewItem.classList.add('grid');
    }
    viewCont.forEach(function (item) {
        if (item.classList.contains('grid')) { //컨텐츠와 아이콘은 HTML파일에 추가된 숫자만큼 여러개 있어서 forEach로 해결 
            item.classList.remove('grid');
        } else {
            item.classList.add('grid');
        }
    })
    viewIcon.forEach(function(item){
        if(item.classList.contains('grid')) {
            item.classList.remove('grid');
        } else {
            item.classList.add('grid');
        }
    })
}, false);

그러면 자바스크립트에서 이거 바꿀 수 있게 해야 한다고 했는데... 그러면 동작 지시할 버튼과 바꿀 요소를 가져와야 한다. 위에 있는 건 버튼이고, 아래 세 줄이 바꿀 요소들. forEach가 들어간것과 안 들어간 것의 차이? HTML에 뭉텅이로 있으면 forEach로 순회하면서 작업해야 다 바뀜....

 

나도 포고해야되니까 최대한 간결하면서도 이해하기 쉽게 설명해봅시다. item 클래스를 가지고 있는 건 HTML 파일에 하나밖에 없고, grid 클래스가 붙으면 3열짜리 그리드로 바꿀 거다. 반면 아이콘이나 콘텐츠도 별도의 클래스를 부여하고 그리드 븅 맞게 바꾸는 건 맞지만 얘네는 HTML 안에 여러개가 있다. 다행히도(?) 동적 생성은 아니고 수제로 복붙함...

 

아무튼 그런 과정을 거쳐서 이런 식으로 토글할 수 있다. 저거 근데 다크모드때처럼 버튼 통으로 가져왔다니 이벤트 두번 적용되더라... ㅡㅡ

반응형

'Coding > JavaScript' 카테고리의 다른 글

눈 내리는 효과 만들기  (0) 2023.12.10
폰트어썸(Font awesome)  (0) 2023.08.11
[HTML 요소] 라디오 버튼  (0) 2023.08.06
개발자 도구는 장식이 아니다  (0) 2023.08.06
자바스크립트는 출력을 어떻게 하나요?  (0) 2023.08.01
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

[HTML 요소] 라디오 버튼

Coding/JavaScript 2023. 8. 6. 23:49
반응형

라디오 버튼이 뭐임? 그 왜 회원가입 받거나 구글폼으로 설문조사 할 때 동그란 버튼 있죠? 중복으로 선택 안 되고 하나만 선택 되는. 지금은 그게 뭔데요? 지만 아래 예시를 보면 아마 바로 아 이거! 할 것이다.


See the Pen Radio button 1 by koreanraichu (@koreanraichu) on CodePen.

봐봐요 이 버튼 어디서 봤잖아. 이게 라디오 버튼이다. 해당 예시에 JS는 적용 안돼서 그냥 선택만 할 수 있는 정도다.

 

<html>
  <div>
    <p>바깥은 위험하니 이 아이들을 데려가렴! <p>
    <input type="radio" name="pokemon" value="Bulbasaur" checked><span>이상해씨</span>
    <input type="radio" name="pokemon" value="Charmander"><span>파이리</span>
    <input type="radio" name="pokemon" value="Squirtle"><span>꼬부기</span>
  </div
</html>

라디오 버튼은 '같은 그룹 내에서 하나만 선택할 수 있는' 버튼이다. 체크박스처럼 중복 선택이 안되는데 그걸 위해서 필요한 게 name이다. 위에 있는거 HTML코드 그대로 가져온거다. 잘 보면 이상해씨, 파이리, 꼬부기가 같은 name으로 묶여있는 것을 볼 수 있을 것이다. 저거 없으면? 우웅 중복선택? 얘네 같은 그룹임? 이 돼서 막 갖다 고를 수 있는 대참사가 터진다.

 

See the Pen Radio button 2 by koreanraichu (@koreanraichu) on CodePen.

이렇게 선택지 그룹에 따라 name을 다르게 하면 여러 개의 선택지를 만들 수도 있다. 그럼 어떻게 만드는 지는 알았으니 여기에 CSS 적용을 어떻게 하는 지 알아보자. 여기서 CSS 적용이라는 건 span 말고 그 옆에 있는 라디오 버튼 말하는거다. 일단 새로 쓰기는 귀찮으니 2번 소스를 복사해서 써먹어봅시다.

 

See the Pen Radio button 3 by koreanraichu (@koreanraichu) on CodePen.

소스에 주석이 붙은 부분도 있지만... 일단 라디오 버튼에 CSS를 주기 위해서는 그냥 줘서는 안된다. 안보이그덩. 그래서 appearance: none;을 줘서 기존 스타일을 숨긴 다음 적용했다. 아무튼 이런 식으로 라디오버튼의 그 동그란거에 대한 CSS를 적용할 수 있다. transition은 PPT의 애니메이션 효과 같은 건데, 이게 있으면 좀 자연스럽게 전환할 수 있다.

 

근데 만약 위 예제에서 스테이크 재료가 다 떨어져서 스테이크를 못 팔면 어떻게 하나요? 아, 그거 간단합니다.

<input type="radio" name="main" value="meat" disabled><span>스테이크</span>

요로코롬 disabled를 써 주면 사용자가 선택을 못 한다. 그렇다면 이제 자바스크립트도 쓰까봅시다.

 

See the Pen Radio button 4 by koreanraichu (@koreanraichu) on CodePen.

갑자기 뭔가 개 복잡한 게 나왔다?? 가끔 스칼렛 바이올렛 중 뭘 사야 할 지 고민하는 사람들이 있어서 만들어 본 선택지다. 정작 오래 걸린 부분은 유효성 검사였던 게 함정. 아무튼... 이 코드가 어떻게 돌아가냐면 1) 질문에 따라 선택을 하면 2) 그 선택지의 value를 배열에 넣고 3) 스칼렛과 바이올렛 중 많은 걸 종합해서 추천해준다. 근데 이게 라디오버튼이 비면 안되잖아요? 그것때문에 처리하느라 오래 걸린거임...ㅠㅠ

 

아무튼... 예제를 보면 선택지가 두개씩인데 스칼렛/바이올렛 버전에 따라 분기되는 걸 나타낸거다. 라디오버튼에 따라 색이 다른 건 CSS 적용해서 그럼. 아무튼 그럼. 그러면 HTML, CSS는 각각 뼈와 살이고 자바스크립트로 작동하는건데... 일단 선택지 요소를 가져온 다음, 반복문과 if문의 조합을 통해 선택된 선택지의 value를 가져온다.

 

const colorList = document.getElementsByName("color");
const timeList = document.getElementsByName("time");
const pfList = document.getElementsByName("professor");
const vehicleList = document.getElementsByName("vehicle");
const pokemonList = document.getElementsByName("pokemon");

이렇게 라디오버튼에 지정해 둔 name으로 묶어서 가져오면, 이 중에서 선택된 거 하나의 결과값을 가져오게 된다. 값은 스칼렛 or 바이올렛이고 전부 선택하면 5개니까 스칼렛쪽이 더 많으면 스칼렛을, 바이올렛 버전이 더 많으면 바이올렛 버전을 추천해주는 거다. 근데 이거 어렵죠? 그래서 위에 있는 메뉴 예제를 다시 가져와봤습니다.

 

See the Pen Radio button 4(w/ JS) by koreanraichu (@koreanraichu) on CodePen.

메뉴가 좀 늘어난 것 같지만 기분탓이다. 그럼 전체 자바스크립트 코드를 보자.

let dish = document.getElementsByName("main");
let drink = document.getElementsByName("desert");
let selection = document.querySelector("#selection");
let selectDish = "";
let selectDrink = "";

function order() {
  //메인메뉴
  dish.forEach((node) => {
    if (node.checked && node.value == "meat") {
      selectDish = "T본스테이크";
    } else if (node.checked && node.value == "bibim") {
      selectDish = "돌솥비빔밥";
    } else if (node.checked && node.value == "sushi") {
      selectDish = "모둠초밥+미니우동";
    } else if (node.checked && node.value == "ddeokggalbi") {
      selectDish = "떡갈비 정식";
    } else if (node.checked && node.value == "burger") {
      selectDish = "수제버거&감자튀김";
    }
  });

  //음료
  drink.forEach((node) => {
    if (node.checked && node.value == "plum") {
      selectDrink = "매실차";
    } else if (node.checked && node.value == "coffee") {
      selectDrink = "아포가토";
    } else if (node.checked && node.value == "greentea") {
      selectDrink = "녹차";
    } else if (node.checked && node.value == "earlgray") {
      selectDrink = "홍차(얼 그레이)";
    } else if (node.checked && node.value == "assam") {
      selectDrink = "홍차(아삼)";
    }
  });

  //주문을 포함한 출력
  let orderDish = document.createElement("p");
  orderDish.innerHTML =
    "주문하신 메뉴는 " + selectDish + "와 " + selectDrink + "입니다. ";
  selection.appendChild(orderDish);
}

메뉴를 하나씩 고르고 버튼을 누르면 식사와 음료가 출력되는 개 심플한 코드다. 유효성 검사... 귀찮아서 안함... 아무튼 위에 두 줄은 getElementsByName인데 이게 라디오버튼의 선택지를 가져오는 코드이다. 그리고 order 함수 에 보면 주석으로 음식과 음료로 나뉘어진 부분이 있는데, 이걸 왜 이렇게 했냐... HTML 태그를 보면 아시겠지만 value가 영어다. 스테이크는 meat, 수제버거+감자튀김은 burger 이런 식인데 이거 사용자한테 그대로 보여줄거임? 아니잖아요. 그니까 노드 밸류에 따라 라디오 버튼 옆에 있는 메뉴로 바꿔줘야 한다.

 

출력은 p태그를 만들어서 div에 갖다 붙이는 식으로 진행된다. 라디오버튼의 경우 동일 그룹 내에서는 하나만 선택할 수 있어서 가져오는 건 쉬운 편이다. 체크박스 과연...

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

개발자 도구는 장식이 아니다

Coding/JavaScript 2023. 8. 6. 20:00
반응형

브라우저에서 F12를 누르면 개발자 도구가 나온다. 아, 오페라는 컨트롤 시프트 I 눌러야 나옴. 아무튼... 가끔 글쓰다가 열리면 어이 이거 뭐야 하게 되지만 사실 이거, 장식이 아니다. 자바스크립트에서 console.log()로 출력하게 되면 결과물 확인할 때 콘솔창을 들러야 한다...만 그거 말고 다른 쓸모가 또 있다. 예전에 고대에서 일할 때 도움 됐던 팁임.

 

오늘은 파폭으로 열었다. 파폭도 개발자 도구 오른쪽에 고정할 수 있는데... 보니까 뭔가 복잡하다 그죠? 검사기에 있는 것들은 지금 내가 보고 있는 이 사이트(네이버 메인)의 DOM이다. 뭐 네이버 검색창이라던가, 내 정보창(로그인 상태니까), 뉴스, 웹툰 이런거 말하는거다. 여기서 DOM을 선택해서 볼 수도 있고, 직접 보고자 하는 요소에 우클릭-검사(대충 비슷한거 있음)를 통해 볼 수도 있다. 그럼 시험삼아 검색창의 속성을 한번 확인해보자.

 

검색을 하기 위해 뭘 입력하는 곳이 포커싱되었다. 내가 지금 속성을 확인중인 것은 검색창 안에 있는 입력창이다. 그리고 저기 포커싱 된 건 마진이나 패딩에 따라 색깔이 달라지는데 아마 보라색이 마진인가 그랬음.

 

여기 보이는 건 선택한 요소의 CSS 선택자다.

 

그리고 여기에 있는 건 CSS 관련된건데, 왼쪽에 있는 게 CSS 속성이다. 근데 아니 이거 알려주려고 이 글 쓰신건가요? 놉.

 

생각해봅시다. HTML/CSS/JS까지 다 해서 올렸는데 이게 처음에는 바로바로 반영이 되겠지만 좀 쌓이다보면 바로바로 반영이 안된다. 캐시 지우고 해야 반영될까 말까인데 이걸 솔직히 일일이 서버 올리고 하는 것도 노가다고, 일일이 캐시 삭제하는 것도 너무 번거롭잖아요? 그러니까 올리고 수정하고 또 올리고 이런 노가다를 할 바에는 개발자 도구에서 미리 수정해보고 적용해라, 이게 내가 들었던 꿀팁이다. 엥? 그게 돼요?

 

여기서 해당 객체의 속성을 수정할 수도 있고

 

좀 간단한거면 여기서 추가해도 된다. DOM 추가는 좀 빡세지만 이미 추가된 DOM의 CSS 속성을 다양하게+빠릿빠릿하게 적용해볼 수 있다. 그리고 개발자 도구로 CSS 속성을 바꾼다고 해도 서버에 올리는 게 아니기때문에 새로고침 하면 원상복구된다. 다르게 말하자면 내가 개발자 도구로 CSS 속성을 바꾼다고 해도 다른 네이버를 열어보는 사람들이 보는 페이지에는 아~무 영향도 가지 않는다.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

자바스크립트는 출력을 어떻게 하나요?

Coding/JavaScript 2023. 8. 1. 02:14
반응형

자 생각해봅시다. 파이썬은 print문으로 출력하잖음? 근데 자바스크립트에는 그런게 없어요. 여기서 오해하시면 안되는 게, 출력이 안되는 게 아니라 파이썬이나 C언어처럼 print 어쩌고로 적는 출력문이 없다는 얘기다. 그럼 어떻게 출력하나요? 그걸 이제 알아볼거다.


자바스크립트는 프론트엔드 삼신기(HTML, CSS, JS) 중 유일한 프로그래밍 언어이다. 거기서 더 나가면 리액트 뷰 앵귤러 삼대장이 기다리고 있지만 아무튼... 삼대장의 삼대장 걔네는 뭐 확장팩같은거고 걍 자바스크립트도 있긴 있잖아요? 그런데 자바스크립트가 왜 프론트엔드 삼신기냐... 프론트엔드 개발자는 HTML로 뼈대를 만들어서 CSS로 살을 붙이고 자바스크립트로 동작하게 하기 때문이다. 

 

하아니 그런데 출력문이 없다고요? 그럼 어떻게 출력함??? print 이딴게 없는거지 출력할 방법 많습니다. 심지어 네 개나 있다.

 

windows.alert()

별도의 대화 상자를 띄워서 출력하는 방식이다.

See the Pen Untitled by koreanraichu (@koreanraichu) on CodePen.

저거는 걍 간단하게 버튼에 연결했지만 반드시 입력해야 하는 필드에 뭐가 빠졌거나 하면 알림창을 띄울 수도 있다. 보통 쓸 때는 windows.alert()가 아니라 걍 alert()라고 쓰면 된다.

 

DOM 조작하기

처음 하시는 분들은 좀 생소할 수 있는데, 간단하게 말하자면 이 페이지에 있는 HTML 요소들을 조작한다는 얘기다. 예전에도 몇 번 코딩한 거 올리면서 얘기했지만 자바스크립트는 뻐대(HTML)는 물론 뼈대에 붙은 살(CSS)을 조작할 수 있다. 뼈대의 내용물을 바꾸거나, CSS 클래스를 새로 추가하거나, CSS 속성을 바꾼다던가 뭐 그런.

See the Pen 직접 DOM 조작하기 by koreanraichu (@koreanraichu) on CodePen.

여기서는 위에서 썼던 버튼을 그대로 우려먹어서(...) 버튼을 누르면 아래에 글자가 추가되게 해놨다. 아래에 div태그로 영역 하나를 만들고, 버튼을 누르면 영역을 가져옴과 동시에 p태그 하나를 만들어서 내용 정하고 갖다 붙이는거다.

 

console.log

자, 생각해봅시다. 직접 DOM을 조작하거나 알림창으로 띄우게 되면 어쨌든 보일 거 아니예요. 근데 나는 사용자가 이런걸 한다는 걸 몰랐으면 좋겠어! 브라우저에 직접 안 떴으면 좋겠어! 그럼 조용히 콘솔.로그를 써보자. 일단 각 브라우저에는 개발자 도구라는 게 있고, F12키를 누르면 열린다.

구글 크롬의 개발자 도구
파이어폭스의 개발자 도구(얘는 밑에 가로로 뜨더라...)
엣지의 개발자 도구
오페라의 개발자 도구(얘는 별도로 설정하지 않으면 단축키가 ctrl+shift+I다)

개발자도구 여셨음? 그러면 console(콘솔)로 들어가자.

console.log는 웹 브라우저 개발자 도구에 있는 콘솔에 결과가 출력된다. 보통 뭐 자잘하게 테스트하거나 버그 잡을 때 유용하다. 개발자 도구의 다른 용도는 또 나중에 설명드리겠음.

 

document.write()

웹 페이지가 로딩될 때 제일 먼저 데이터를 출력한다는데 아직까지 한번도 써본 적이 없다.

See the Pen document.write 사용하기 by koreanraichu (@koreanraichu) on CodePen.

실행하자마자 출력되는 저것은 10!이다. 일단 난 아직까지 써본 적 없지만, 보통 테스트나 디버그용으로 많이 쓴다고...

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

자바스크립트에도 정규식이 있다고???

Coding/JavaScript 2022. 10. 27. 01:00
반응형

https://koreanraichu.tistory.com/118

 

정규식(Regular Expression)-기호와 메타문자

문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕

koreanraichu.tistory.com

여기서 정규식이 대충 와일드카드 같은거고(글은 분량상 두개로 나눴음) 파이썬에서는 re모듈을 쓴다고 했는데, 사실 파이썬 뿐 아니라 자바스크립트에서도 정규식을 쓸 수 있다. 정규표현식, 그러니까 정규식은 파이썬만의 전유물이 아니기때문에 다른 언어에서도 사용하는 방법이 다를 뿐이지 일단 쓸 수는 있다.


정규식에 대해 설명하면서 대충 '와일드카드 같은 것'이라고 했는데, 이런식빵 저런식빵을 모두 식빵 한방에 찾게 해 주는 매우 놀랍고 유용한 것이다.

 

See the Pen RegularExpression_RegExp 1 by koreanraichu (@koreanraichu) on CodePen.

아, 참고로 배열은 

const pokemon_list = ['김부추씨','박숟갈씨','스미스샹델라','스미스루나톤','스미스솔록','박팬텀씨','김쪽파얼갈이김치','김메탕','최팬텀']

얘다. 아니 이름이 다 왜이래 붙일거 없으면 김씨 붙여서요 

 

아니 이런거 말고 다른거 없어요? 이 정규식을 유효성 검사에 활용할 수 있다면 어떰? 유효성 검사는 되게 간단한건데 여러분들도 많이 봤던 그거다. 회원가입 할 때 이메일 입력하다 삐끗했더니 올바른 이메일이 아닙니다! 올바른 아이디가 아닙니다! 이러는거 있잖음? 그거 말고 입력 다 해주세요 이런거. 그것도 유효성 검사다. 입력을 '제대로' 했는지 확인하는 것.

 

See the Pen RegularExpression 2 by koreanraichu (@koreanraichu) on CodePen.

정규식을 이용해 이메일 주소라는 걸 알 수 있는 건, 메일주소에 패턴이 있기 때문이다. 대부분의 메일 주소는 아이디@도메인이고 도메인은 뭐시기닷컴 뭐시기닷넷 이런 식으로 온점이 하나씩 들어간다. 그러니까 yourid@naver.com 이런 형식을 가지고 있다 이거지. 그래서 정규식 패턴이

const mail_check = /^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+/

이렇게 된다. 이게 뭔 소리냐... 영대 영소 숫자 언더바 하이픈(둘 다 아이디에 많이 씀)이 오고 다음에 앳(@, 골뱅이)이 붙고 그 뒤에 영대 영소 숫자 하이픈 그리고 쩜 하고 다시 영대 영소 숫자가 메일 주소 형식이라고 알려주는거다.

 

See the Pen RegularExpression 3 by koreanraichu (@koreanraichu) on CodePen.

여기서는 전화번호가 나온다. 전화번호는 패턴이 어떤가요? 010-1234-5678 이런 식으로 숫자 세개 하이픈 숫자 네개 하이픈 숫자 네개다. 그럼 정규식으로 전화번호를 어떻게 짜나요?

const phone_pattern = /\d{3}-\d{3,4}-\d{4}/

이렇게 짠다. 저기에 왜 3,4가 들어가냐면 옛날에는 국번 세자리도 있었다.

 

const bread_array = ['이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵']

const regex = new RegExp('식빵');

for (let i of bread_array) {
  console.log(regex.test(i))
}

regex(위에 RegExp 쟤).test는 true, false로 출력해주고

const bread_array = ['이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵']

const regex = new RegExp('식빵');

for (let i of bread_array) {
  console.log(regex.exec(i))
}

얘는 Null or 배열로 뽑아준다.

const bread_array = ['이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵']

const regex = new RegExp('식빵');
const cream = /크림/

for (let i of bread_array) {
  console.log(regex.exec(i),cream.exec(i))
}

이렇게 하면 식빵이 있거나 크림이 있으면 배열이 나오고, 둘 다 없으면 널만 두 개 나온다.

const bread_array = ['이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵']

const regex = new RegExp('식빵');
const cream = /크림/

for (let i of bread_array) {
  console.log(i.match(regex),i.match(cream))
}

match도 배열로 돌려주는 건 맞는데 위에 두 놈이랑 순서가 다르다. test나 exec는 패턴.test(문자열)이고 match는 문자열.match(패턴)이라 주의해야 한다. 순서 뻑나면 당연하게도 에 ㅋ 러 ㅋ

 

const bread_array = ['이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵','달빵','땅콩크림빵','딸기크림빵']

const regex = new RegExp('[^식]빵');

for (let i of bread_array) {
  if (regex.test(i)) {
    console.log(i)
  }
}

매우 당연하지만 이런 식으로 식빵 빼는 것도 된다. (대괄호 안에 꺾쇠는 저거 빼고 찾으라는 얘기)

const bread_array = ['풀빵','이런식빵','밤식빵','붕어빵','조런식빵','팥빵','크림빵','슈크림빵','달빵','땅콩크림빵','딸기크림빵']

const regex = new RegExp('[^식|크림]빵');

for (let i of bread_array) {
  if (regex.test(i)) {
    console.log(i)
  }
}

OR과 조합하면 식빵 크림빵을 다 뺄 수 있다. 이런 식으로 정규식의 메타문자와 사용법을 익혀두면 패턴이 존재하는 문자열에 한해서 정규식으로 패턴을 짜서 그것만 필터링할 수 있다. 왜 네이버 블로그에서 뭐 찾을 때

이런거 빼고 찾는것처럼 말이다. 

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

for, for in, for of, forEach

Coding/JavaScript 2022. 10. 11. 02:46
반응형

Python에는 for와 while이라는 반복문이 있고, 이 둘은 범위냐 조건이냐의 차이만 빼면 반복문이라는 기본 골자는 같은데, 이런 게 자바스크립트에도 당연히 있다. 라디오버튼 뺑뺑이 돌면서 얘가 뭘 체크했나 보는 것도 반복문의 일이기 때문.

그런데 이 반복문... Python처럼 심플하지 않아요...


for, for in, for of

See the Pen for, for in, for of by koreanraichu (@koreanraichu) on CodePen.

얘네들은 Pyhlogenic tree로 치자면 그 트리가 막 갈라지는 와중에도 진화적으로 매우 유사한 homolog이기 때문에 또이또이 쌤쌤임을 인정받은 애들... 맞는 비유인지는 모르겠지만, 자매나 형제같은 느낌이다. 그래서 형식 말고 크게 다를 건 없다.

 

let pokemon = ['김부추씨','김상추씨','김배추씨','김양상추씨','김양배추씨','김후추씨']

for (let i = 0;i < pokemon.length;i++) {
  let p_tag = document.createElement('p')
  p_tag.innerText = pokemon[i]
  pokemon_div.appendChild(p_tag)
}
//for

for

 

let num_list = [806, 26, 607, 601, 752, 504, 485, 162, 885, 361, 309, 480, 401, 313, 771, 141, 9, 526, 390, 237]

for (let i in num_list) {
  let p_tag = document.createElement('p')
  if (num_list[i] % 4 == 0) {
    p_tag.innerText = num_list[i]
    for_in_div.appendChild(p_tag)
  }
}
// for in

for in

 

for (let i of num_list) {
  let p_tag = document.createElement('p')
  if (i % 3 == 0) {
    p_tag.innerText = i
    for_of_div.appendChild(p_tag)
  }
}
//for of

for of

 

각 소스에서 이 반복문이 하는 일은

1) 포켓몬 리스트의 요소를 내용으로 하는 p태그를 생성하라
2) 위에 있는 숫자 리스트에서 4의 배수를 p태그로 생성하라
3) 위에 있는 숫자 리스트에서 3의 배수를 p태그로 생성하라

이렇게 세 개다. 그리고 세 반복문은 주어진 일을 하기 위해 각각 주어진 배열에 접근해 해당 요소를 가져와 p태그로 만들어서 내보내게 된다. for of는 파이썬으로 치자면 for i in (리스트)로 직접 접근하는 것으로, 저 경우 i에 들어가는 게 배열이 담고 있는 요소가 된다. DOM이면 DOM, 숫자면 숫자, 문자면 문자 이런 식. 반면 위의 두 반복문은 i 자체는 숫자라 인덱싱 절차가 따로 필요하다. 즉 for in이 for i in (리스트)면 나머지 둘은 for i in range(n)으로 인덱스 번호 만들어서 인덱싱 하는 것.

 

forEach

얘는 위에 셋과는 성격이 조금 다르다. Phylogenic tree로 치자면 쭉 내려가다가 마지막에 가지가 한번 갈라지고 그 다음에 for, for in, for of가 갈라지는 정도. 왜냐하면 얘는 배열에서 뭘 가져온다는 개념이 아니라 배열을 돌면서 주어진 함수를 실행하는 반복문이기 때문이다. 물론 for로 구현할 수 있는 건 forEach로도 구현할 수 있다.

 

See the Pen For and Foreach by koreanraichu (@koreanraichu) on CodePen.

여기서 for와 forEach의 차이점을 볼 수 있다.

 

let p_for = document.querySelectorAll('.for > p')
let p_forEach = document.querySelectorAll('.foreach > p')
// querySlectorAll은 배열로 가져온다

let number_list = ['일','이','삼']

for (let i = 0;i < p_for.length;i++) {
  p_for[i].innerText = number_list[i]
}
//for

p_forEach.forEach(function(element, index){
  element.innerText = number_list[index]
})
//forEach

아니 저거 저렇게 선택되는 줄 몰랐음... 아무튼... 위 코드가 하는 일은 div 안에 있는 p태그의 내용을 number_list에 있는 일, 이, 삼으로 바꾸는 것이다. (원문은 외국어) 둘 다 querySelectorAll()로 가져오기 때문에 가져왔을 때 상태는 배열이고, 배열 안에 p태그 세 개가 담겨 있기 때문에 for나 forEach를 사용해서 안에 있는 p태그의 내용을 바꿔줘야 한다.

 

for문은 말 그대로 위의 배열에서 i번째 요소를 num_list의 i번째 요소로 바꾸는 대단히 심플한 코드인데... forEach에 저거 뭡니까... 아... 저거는 요소와 인덱스로 함수 돌린다는 얘기인데, querySelectAll()로 가져온 배열을 순회하면서 배열이 담고 있는 요소(p태그)를 num_list[인덱스]의 요소로 채운다는 얘기다. 저 인덱스는 querySelectorAll()로 가져온 배열의 인덱스를 말한다. 아니 실화임.

 

See the Pen For and Foreach 2 by koreanraichu (@koreanraichu) on CodePen.

여기서는 for of와 forEach를 비교해보자.

 

let sqrt_n = document.querySelector(".sqrt")
let square_n = document.querySelector(".square")
let num_list = [1,2,3,4,5,6,7,8,9,10]
//sqrt: 제곱근(루트)
//square: 2제곱(3제곱은 cube)

for (let i of num_list) {
  let p_tag = document.createElement('p')
  p_tag.innerText = `sqrt ${i}: ${(i ** 0.5).toFixed(3)}`
  sqrt_n.appendChild(p_tag)
}
// 리스트에 있는 수의 2제곱근을 출력(소수점 이하 3자리에서 반올림)

num_list.forEach(function(element){
  let p_tag = document.createElement('p')
  p_tag.innerText = element ** 2
  square_n.appendChild(p_tag)
})
//리스트에 있는 수의 제곱을 출력

위 코드는 배열 안에 있는 수의 제곱근을 소수점 세자리까지 출력하는 코드이고, 아래 코드는 배열 안에 있는 수를 제곱해서 출력하는 코드이다. 아, 왜 **냐면 자바스크립트와 파이썬에서 ^는 XOR을 의미한다. 그래서 파이썬이나 자바스크립트로 2 ^ 2 하면 4가 아니라 0이 나온다. (XOR은 입력 두 개가 달라야 참임)

 

두 코드가 크게 다를 건 없다. 위 코드는 num_list에 있는 요소(숫자)를 가져와 0.5제곱(2루트)을 하고 innerText로 만든 다음 그걸 추가하는거고, 아래는 num_list를 순회하면서 안에 있는 요소(숫자)의 2승을 구하고 그걸 innerText로 만들어서 추가한다.

 

See the Pen For and Foreach 3 by koreanraichu (@koreanraichu) on CodePen.

for in과 forEach를 비교해보자.

 

let num_list = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16,17,18,19,20]
let num_list2 = [21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]
//아니 자바스크립트는 list(range()) 없나?
let odd_number = document.querySelector('.odd')
let even_number = document.querySelector('.even')

for (let i in num_list) {
  let p_tag = document.createElement('p')
  if (num_list[i] % 2 == 0) {
    p_tag.innerText = `${num_list[i]} is even number`
    even_number.appendChild(p_tag)
  }
  else {
    p_tag.innerText = `${num_list[i]} is odd number`
    odd_number.appendChild(p_tag)
  }
}

num_list2.forEach(function(element){
  let p_tag = document.createElement('p')
  if (element % 2 == 0) {
    p_tag.innerText = `${element} is even number`
    even_number.appendChild(p_tag)
  }
  else {
    p_tag.innerText = `${element} is odd number`
    odd_number.appendChild(p_tag)
  }
})

위 코드는 1~20까지의 배열에 있는 요소(숫자)가 짝수냐 홀수냐에 따라 다른 div에 추가한다. 그리고 아래 코드도 비슷한 일을 하는데, forEach는 21~40까지 있는 배열을 순회하면서 요소(숫자)에 조건문을 적용하고 각각의 div에 추가하게 된다.

 

See the Pen Untitled by koreanraichu (@koreanraichu) on CodePen.

const button = document.getElementById('button')
const print = document.querySelector('.print')
const choose = document.querySelectorAll('.pokemon')

button.addEventListener('click',(e)=>{
  let question = ''
  choose.forEach(function(element){
    if (element.checked) {
      if (element.value == 'grass') {
        question = '풀타입 포켓몬인 이상해씨로 하겠느냐?'
      }
      else if (element.value == 'water') {
        question = '물타입 포켓몬인 꼬부기로 하겠느냐?'
      }
      else if (element.value == 'fire') {
        question = '불타입 포켓몬인 파이리로 하겠느냐?'
      }
      else {
        question = '전기타입 포켓몬인 피카츄로 하겠느냐?'
      }
      print.innerText = question
    }
  })
})

for나 forEach를 사용하면 이런 식으로 동일한 클래스의 라디오버튼을 배열로 받아오고 순회하면서, 선택이 되었는지를 확인하고 선택된 라디오버튼의 값에 따라 다른 이벤트를 줄 수 있다.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

매우 간단한 스크롤 이벤트를 해보자

Coding/JavaScript 2022. 9. 21. 16:27
반응형

addEventListener에 대해 설명하면서 스크롤 이벤트도 '있다'고 했는데, 이건 말 그대로 마우스를 스크롤했을 때 일어나는 이벤트이다. 그게 다다.

 

Reference

https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8

 

Javascript 스크롤 이벤트

web에서 발생하는 스크롤 이벤트를 이용해 다루는 방법을 써보았습니다.

velog.io

https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8

 

Javascript 스크롤 이벤트

web에서 발생하는 스크롤 이벤트를 이용해 다루는 방법을 써보았습니다.

velog.io

https://stackoverflow.com/questions/40475155/does-javascript-have-a-method-that-returns-an-array-of-numbers-based-on-start-s

 

Does JavaScript have a method that returns an array of numbers based on start, stop and desired number of return values?

I'm looking for something similar to numpy.linspace to generate an array of numbers based on a starting value, an ending value and the desired number of values in the array. Example: start=2.0, end...

stackoverflow.com


Basic-마우스 스크롤 위치를 화면에 표시하기

See the Pen scroll events-Basics by koreanraichu (@koreanraichu) on CodePen.

 

 

여기서는 

let contents = document.querySelector('#content1');

window.addEventListener('scroll', () => { 
  console.log(window.scrollX, window.scrollY);
  let new_pTag = document.createElement('p');
  new_pTag.innerHTML = 'scroll are here: ' + window.scrollY;
  contents.appendChild(new_pTag)
});

를 썼는데 이거는 말 그대로 스크롤을 내렸을 때 X, Y축 위치를 나타낸다. 근데 얘는 스크롤바가 없는 상태에서는 안되더라...

 

스크롤을 올리고 내릴때마다 색깔 바꾸기

이건 addEventListener가 아니라 windows.onwheel을 사용해서 구현했다. addEventListener('wheel',())와 비슷하다. 일단 블로그를 참고해서 만든 코드부터 보고 가자.

 

See the Pen Scroll Events-Animation by koreanraichu (@koreanraichu) on CodePen.

HTML이나 CSS는 사실 뭐 특별한 건 없고, 자바스크립트 코드를 보자.

 

//Reference: https://velog.io/@minkyeong-ko/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B0%B0%EA%B2%BD%EC%83%89-%EB%B3%80%EA%B2%BD

var colors = ['#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FFFFFF'];
var wrapper = document.querySelector('.box');
var title = document.getElementsByTagName('h1')[0];
var text = document.querySelector('#text');

wrapper.onwheel = changeColor;

var colorIndex = 0;
var scrollValue = 0;

function changeColor(e) {
    scrollValue += e.deltaY * 0.01;
    if (scrollValue > 10) {
        colorIndex += 1;
        if (colorIndex > colors.length - 1) {
            colorIndex = 0;
        }
        text.innerText = colors[colorIndex];
        wrapper.style.backgroundColor = colors[colorIndex];
        if (colorIndex >= 3) {
            title.style.color = '#000000'
            text.style.color = '#000000';
        }
        scrollValue = 0;
    }

    if (scrollValue < -10) {
        colorIndex -= 1;
        if (colorIndex < 0) {
            colorIndex = colors.length - 1;
        }
        text.innerText = colors[colorIndex];
        wrapper.style.backgroundColor = colors[colorIndex];
        if (colorIndex >= 3) {
            title.style.color = '#000000';
            text.style.color = '#000000';
        }
        scrollValue = 0;
    }
}

델타는 말 그대로 Δ이다. 그... 자 그래서 저 세모 어디서 봤어요? 슈뢰딩거 방정식? 그건 ∇(del operator)임... 저거 미분에 나오잖아여... 변화량. 근데 변화량이랑 스크롤이랑 뭔 상관이냐.... 휠 이벤트는 위에 스크롤과 달리 휠을 올렸는가/내렸는가를 확인해 거기에 맞는 이벤트를 준다. 크게 if문이 두 개인데 위쪽은 스크롤을 올렸을 때, 아래쪽은 스크롤을 내렸을 때. scrollValue라는 변수를 통해 delta, 즉 스크롤의 변화를 누적시킨 다음 어느정도 변화가 생겼다 그러면 다음 색으로 넘긴다.

 

그리고 원래 코드에는 없던 기능이 하나 있는데, 검정->하양으로 가다 보면 글자 색이 하양일 때 안 보이는 배경색이 당연히 존재한다. 이건 뭐 착한 사람도 안 보이는 배경이여... 그래서 colorIndex 배열에서 #999999부터는 글자색도 흰색으로 바꿨다.

 

See the Pen Scroll Events-Animation(Gradation) by koreanraichu (@koreanraichu) on CodePen.

얘는 위의 코드를 살짝 응용했다.

 

function makeArr(startValue, stopValue, cardinality) {
    var arr = [];
    var step = (stopValue - startValue) / (cardinality - 1);
    for (var i = 0; i < cardinality; i++) {
        arr.push(startValue + (step * i));
    }
    return arr;
}

var colors = [];
var red = makeArr(65, 53, 8);
var green = makeArr(184, 73, 8);
var blue = makeArr(131, 94, 8);

for (let i = 0; i < red.length; i++) {
    var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'))
    var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'))
    var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'))
    var color_code = '#' + red_grad + green_grad + blue_grad
    colors.push(color_code)
}

배열 관련해서 추가 및 수정된 부분이 이거. 기본 코드는 배열 안에 풀로 색깔 코드가 들어갔는데, 여기서는 좀 자연스러운 변화를 줘야 하는데 인제 그걸 시작과 끝을 이용해서 알아서 만드는? 뭐 그런거다. 예를 들어서 빨강이 255이고 0까지 5개로 만들어달라고 하면 알아서 딱딱 나누는 대충 넘파이의 linspace같은 기능...인데 이제 그게 자바스크립트에 없어요... 그럼 어쩌겠음. 함수 때려박아야지...

 

그래서 RGB에 대해 일정한 간격을 가지는 배열을 만든 다음 그걸 합해서 색깔 코드를 만든 게 저거다.

 

참고로 배경 고정값이 Vue.js 로고 컬러다. 그거 이쁘잖음.

 

See the Pen Scroll Events-Animation(Gradation 2) by koreanraichu (@koreanraichu) on CodePen.

또 응용편이 나왔는데 이거는 처음 색과 끝 색을 지정해서 매우 자연스러운 색 변화를 유도할 수 있다. 좋아 자연스러웠어 그래서 함수가 또 복잡해졌다. 왜냐하면 입력한 색에서 RGB를 또 가져와야 하거든... 

 

const button = document.getElementById('confirm');
button.addEventListener('click', () => {
    makeColor()
})

function makeColor() {
    var startcolor = document.getElementById('startcolor').value;
    var endcolor = document.getElementById('endcolor').value;

    var start_red = startcolor.substr(0, 2);
    start_red = parseInt(start_red, 16);
    var end_red = endcolor.substr(0, 2);
    end_red = parseInt(end_red, 16);

    var start_green = startcolor.substr(2, 2);
    start_green = parseInt(start_green, 16);
    var end_green = endcolor.substr(2, 2);
    end_green = parseInt(end_green, 16);

    var start_blue = startcolor.substr(4, 2);
    start_blue = parseInt(start_blue, 16);
    var end_blue = endcolor.substr(4, 2);
    end_blue = parseInt(end_blue, 16);

    var red = makeArr(start_red, end_red, 10);
    var green = makeArr(start_green, end_green, 10);
    var blue = makeArr(start_blue, end_blue, 10);

    for (let i = 0; i < red.length; i++) {
        var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'))
        var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'))
        var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'))
        var color_code = '#' + red_grad + green_grad + blue_grad
        colors.push(color_code)
    }

    text.innerText = colors[colorIndex];
    wrapper.style.backgroundColor = colors[colorIndex];

    return colors
}

버튼은 뭐... 다들 아실테니 패스하고, 색깔 부분을 살펴보자. 시작색과 끝색의 RGB로 자연스러운 그라데이션을 만들기 위해서는 RGB별로 10진수가 필요하고, 그걸로 등간격인 10개의 요소를 만들게 된다. 그리고 적용하는 건 똑같다. 근데 이제 여기까지는 글자색이 안바꼈었는데...

 

function makeColor() {
    var startcolor = document.getElementById('startcolor').value;
    var endcolor = document.getElementById('endcolor').value;

    var start_red = startcolor.substr(0, 2);
    start_red = parseInt(start_red, 16);
    var invert_start_red = 255 - start_red;
    var end_red = endcolor.substr(0, 2);
    end_red = parseInt(end_red, 16);
    var invert_end_red = 255 - end_red;

    var start_green = startcolor.substr(2, 2);
    start_green = parseInt(start_green, 16);
    var invert_start_green = 255 - start_green;
    var end_green = endcolor.substr(2, 2);
    end_green = parseInt(end_green, 16);
    var invert_end_green = 255 - end_green;

    var start_blue = startcolor.substr(4, 2);
    start_blue = parseInt(start_blue, 16);
    var invert_start_blue = 255 - start_blue;
    var end_blue = endcolor.substr(4, 2);
    end_blue = parseInt(end_blue, 16);
    var invert_end_blue = 255 - end_blue;

    var red = makeArr(start_red, end_red, 10);
    var invert_red = makeArr(invert_start_red, invert_end_red, 10);
    var green = makeArr(start_green, end_green, 10);
    var invert_green = makeArr(invert_start_green, invert_end_green, 10);
    var blue = makeArr(start_blue, end_blue, 10);
    var invert_blue = makeArr(invert_start_blue, invert_end_blue, 10);

    for (let i = 0; i < red.length; i++) {
        var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'));
        var invert_red_grad = (Math.floor(invert_red[i]).toString(16).padStart(2, '0'));
        var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'));
        var invert_green_grad = (Math.floor(invert_green[i]).toString(16).padStart(2, '0'));
        var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'));
        var invert_blue_grad = (Math.floor(invert_blue[i]).toString(16).padStart(2, '0'));
        var color_code = '#' + red_grad + green_grad + blue_grad;
        var invert_color_code = '#' + invert_red_grad + invert_green_grad + invert_blue_grad;
        colors.push(color_code)
        invert_colors.push(invert_color_code)
    }

    text.innerText = colors[colorIndex];
    text.style.color = invert_colors[colorIndex];
    title.style.color = invert_colors[colorIndex];
    button.style.color = colors[colorIndex];
    button.style.backgroundColor = invert_colors[colorIndex];
    wrapper.style.backgroundColor = colors[colorIndex];
    for (let i = 0; i < label.length; i++) {
        label[i].style.color = invert_colors[colorIndex]
    }
    for (let i = 0; i < input.length; i++) {
        input[i].style.border = '2px solid' + invert_colors[colorIndex];
    }

    return colors, invert_colors
}

놀랍게도 글자색도 바뀌게 할 수 있었다. 이것은 매우 놀랍게도 진짜다. 입력값을 RGB로 나눠서 배열로 만들 때 invert_colors라는 배열을 추가로 만들게 되는데, 여기에 들어가는 요소는 시작색의 RGB, 끝색의 RGB의 255의 보수로 만든 배열이 들어간다. 이게 뭐야 우리가 2의 보수 1의 보수가 유명해서 글치 이진법에서만 보수 쓰라는 법은 없음. 아무튼 그래서.. 

이렇게 됐다. 근데 글자색 알고싶은데 어떻게 하냐고? 

text.innerText = 'background-color: ' + colors[colorIndex] + '/' + 'font-color: ' + invert_colors[colorIndex];

이걸로 다 바꿨지... 

 

참 쉽죠? 

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

DOM 선택하는 방법 (부제: 너로 정했다?)

Coding/JavaScript 2022. 9. 19. 16:05
반응형

DOM은 Document Object Model의 약어로, XML이나 HTML에 접근하기 위한 일종의 인터페이스이다. 자바스크립트는 프론트엔드에서 많이 사용하는 언어의 특성인지는 모르겠지만 아무튼 이 DOM들을 지지고 볶는 게 가능하다. 이벤트 추가는 기본이고 생성 삭제 CSS 클래스 부여까지 다 된다. 남자친구 못 만드는 것만 빼면 만능... 어차피 여욱이도 못 구함 질량이 0이라 


document.querySelector()

얘는 같이 다니는(?) 친구가 하나 있는데 바로 querySelectorAll()이다. 그럼 같은 역할인가요? 기본적으로는 그렇다. 기본적으로는 그런데 친구인 쿼리셀렉터올은 해당하는 요소를 죄다 가져온다. 예를 들어서 어떤 문서에 p태그가 6개 있다 그러면 쿼리셀렉터는 맨 위에꺼 하나만 가져오는데 쿼리셀렉터올은 p태그를 다 가져온다.

 

1) HTML 요소를 가져올 때 -> document.querySelector('p')
2) 클래스 이름으로 가져올 때 -> document.querySelector('.classname')
3) 아이디로 가져올 때 -> document.querySelector('#id')

왜 이렇게 쓰냐면 쟤는 종류불문 저거랑 맞는 걸 가져오기 때문. 클래스건 아이디건 종류 안 가리고 지명이 가능하다. 

 

See the Pen document.querySelector by koreanraichu (@koreanraichu) on CodePen.

(document.querySelector)

 

See the Pen document.querySelectorAll by koreanraichu (@koreanraichu) on CodePen.

(document.querySelectorAll)

 

아, 한가지 중요한 게 있다. querySelectorAll()로 요소를 가져올 때는 배열로 가져온다. 위 예시의 경우 div 세 개를 배열로 가져왔는데, 이 경우 내용이나 CSS를 바꾸기 위해 위의 querySelector에서 했던 것처럼 하게 되면 자바스크립트가 미쳤습니까 휴먼? 하게 된다. 그래서 querySelectorAll로 가져온 것은 for 혹은 foreach 등의 반복문을 돌려서 적용해야 한다.

document.getElement~ 

위에 있는 쿼리 시리즈는 조건이 일치하면 아이디건 클래스건 지명이 되지만, 얘네들은 종류에 따라 쓰는 게 다르다.


1) 클래스명으로 부를때는 document.getElementsByClassName('class')
2) 아이디로 부를때는 document.getElementById('id')
3) 태그 네임으로 부를때는 document.getElementsByTagName('p)

 

쿼리시리즈랑 달리 이쪽은 아이디로 가져올래, 클래스명으로 가져올래, 태그명으로 가져올래가 정해져 있어서 뒤에 가져올 게 뭔지만 쓰면 된다. 즉, 쿼리셀렉터와 달리 클래스나 아이디명으로 넣지 않는 이상 .이나 #이 들어갈 필요가 없다.

 

See the Pen document.getElement~ by koreanraichu (@koreanraichu) on CodePen.

한가지 중요한 게 있다. 아이디는 HTML 내에서 동일할 수가 없는 대신 요소나 클래스명은 동일할 수가 있다. HTML에 p태그 여러개 넣잖아요? 그래서 클래스 이름이나 태그명으로 가져오는 게 Elements인것. 그리고 얘네들은 '배열로' 가져오기 때문에 쿼리셀렉터올마냥 반복문을 써야 한다.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

addEventListener()로 고급진 이벤트 추가하기

Coding/JavaScript 2022. 9. 19. 14:39
반응형

근데 생각해보니까 이거 전에 픽하는게 먼저 와야 하지 않나... 뭐 아무튼.


뭔가 기깔나는 것을 구현하기 위해 이 블로그 혹은 다른 블로그를 보다 보면 그런 게 있다. 어? HTML에서 온클릭도 안 줬는데 작동하네? 어? 이거 더블클릭 하니까 작동하네? 어? 스크롤 내리니까 작동하네?

를 알아보자.


굳이 버튼에 온클릭을 안 줘도 작동하는 비결이 바로 addEventListener()이다. getElementByID나 querySelector같은 걸로 DOM(쉽게 말하자면 문서의 어떤 요소)을 가져와서 addEventListener()로 이벤트를 추가할 수 있다. 이 추가라는 게 단순히 알림이나 콘솔 이런걸 떠나서 뭐 모달 소환 곱하기 이런 함수까지 된다. 

 

See the Pen Eventlistner by koreanraichu (@koreanraichu) on CodePen.

참 쉽죠? 저 코드는 간단하다. h1을 가져온다->h1을 클릭하면 알림이 뜨게 만든다. 끝. 오케이? 그럼 클릭만 되나요? ㄴㄴ 그건 아니다.

 

See the Pen Untitled by koreanraichu (@koreanraichu) on CodePen.

더블클릭도 된다. 그럼 클릭이나 더블클릭 말고 키를 눌러서 입력하는 건 어떻게 할까? addEventListener()에 keydown을 주면 된다. 예전에는 키프레스를 썼었는데 요즘은 키다운/키업이라고... (키다운: 눌렀을 때/키업: 뗐을 때)

 

See the Pen Untitled by koreanraichu (@koreanraichu) on CodePen.

clear버튼에도 addEventListener를 통해 입력된 것을 전부 지우는 기능을 추가했다. 아무 키나 눌렀을 때 표시되는 것은 e.key와 e.code, 그리고 e.keyCode인데

 

e.key a & e.code KeyA & e.Keycode 65

 

이렇게 뜬다. 솔직히 무슨 차이인지는 모르겠다.

 

그럼... 스크롤도 되나요...? 네, 됩니다. 그런데 그건 설명할 게 많아서 이 글에서는 다루지 않을 예정이다. 나중에 스크롤 이벤트 하면서 다뤄보겠듬...

 

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

다크모드 간단하게 토글로 구현해보기

Coding/JavaScript 2022. 9. 13. 14:21
반응형

근데 말이 간단이지 헐 나 이것도 못해 개발자 하면 안되나봐 ㅠㅠ 이럴 정도는 아닙니다…

 

Reference

https://blogpack.tistory.com/1117

 

다크모드 토글 기능 구현과 다크모드 토글 디자인 구현

웹페이지, 또는 사이트에 적용하는 다크 모드는 구현하는 방법이 여러 가지 있습니다. CSS 속성을 기준으로 구분하면 사용된 배경색과 전경(글자) 색들을 바꾸기만 하는 간단한 구현이기 때문에

blogpack.tistory.com

https://www.w3schools.com/howto/howto_css_switch.asp

 

How To Create a Toggle Switch

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

https://codechacha.com/ko/javascript-foreach/

 

JavaScript - forEach(), 다양한 예제로 이해하기

forEach()는 배열을 순회하면서 인자로 전달한 함수를 호출하는 반복문입니다. 배열 뿐만 아니라, Set이나 Map에서도 사용 가능합니다. forEach()의 문법은 아래와 같으며, 함수로 value, index, array를 전

codechacha.com


들어가기 전에: 딥-다크-모드

VScode
Wikipedia의 다크모드

요즘은 많이 쓰이고 있는 다크모드는 배경이 어두운 색인 모드로, 다크 테마라고도 한다. OS나 브라우저, 각종 앱(게임 말고)에서도 지원하는 기능으로, 개발자들 IDE는 다크테마가 국룰. 밝으면 벌레가 꼬인다나... 본인은 PC에서는 디스코드만 다크모드고 폰/패드는 일출/일몰 시간에 따라 다르다. 그래서 내 폰은 해 떨어지면 다크모드가 된다.

 

그런데 왜 이놈을 쓰는거죠? 일단 나도 가끔 개발하시는 분들을 보는데 다 IDE가 어두운 색이라 한번 물어본 적 있었다.

https://okky.kr/articles/1088381

 

OKKY - IDE 배경 다들 검정색으로 쓰세요?

요즘 스터디카페에서 공부를 하는데, 여기가 노트북 존이 아예 분리되어서 그런지 개발자분들이 가끔 오십니다. 모니터 부럽... 와... 난 그거까지 들고갔다간 진짜 팔 떨어지는데... (노트북 말

okky.kr

다크모드가 익숙해서, 기본 설정이라서 쓰시는 분들도 계셨지만 눈이 덜 피곤해서 쓰신다고...

 

낮에는 햇빛이 있으니까 상관 없지만 밤에 캄캄한데 계속 밝은 화면을 보면

이렇게 된다. 그리고 밝은 화면을 계속 보여주게 되면 배터리도 훅훅 떨어진다. 자고로 빛의 혼합은 가산 혼합이라서 흰색 배경을 띄울 때 RGB를 풀로 쏴제껴야 흰색이 되거든... 

 

물론 CSS에서 색깔 잘못 잡으면 라이트모드에서는 잘 보이던 UI가 다크모드로 바꿨더니 안 보이는 경우도 있다.


초간단 다크모드 토글하기

그래서 이번에는 뭘 만들거냐... 

이거요. 이미지를 잘 보면 글이랑 슬라이드 버튼이 있고, 글상자 두개 밑에 보이는 버튼도 다크모드를 토글할 때 색깔이 바뀐다.

 

<html>

<head>
    <title>딥-다크-모드</title>
    <meta charset="utf-8">
    <link href="style.css" rel="stylesheet">
    <script src="https://kit.fontawesome.com/dc58858c96.js" crossorigin="anonymous"></script>
</head>

<body>
    <div class="wrap">

        <div class="title">
            <h1>Deep-Dark-mode</h1>
            <p>아래 슬라이드 버튼을 눌러 라이트모드와 다크모드를 테스트해보세요! </p>
            <label class="switch" id="toggle">
                <input type="checkbox">
                <span class="slider round"></span>
            </label>
        </div>

        <div class="article">
            <h1>Title: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
                dolore magna aliqua.</h1>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
                dolore magna aliqua. Lacinia at quis risus sed vulputate. Et tortor consequat id porta nibh venenatis.
                Tellus integer feugiat scelerisque varius morbi enim nunc faucibus a. At lectus urna duis convallis.
                Lorem ipsum dolor sit amet consectetur adipiscing elit. Nec feugiat nisl pretium fusce id velit ut
                tortor. Nulla facilisi cras fermentum odio eu feugiat pretium. Consequat semper viverra nam libero justo
                laoreet sit amet cursus. Orci sagittis eu volutpat odio facilisis mauris sit amet. Pellentesque sit amet
                porttitor eget dolor morbi non arcu. Et netus et malesuada fames ac turpis egestas. Pellentesque
                habitant morbi tristique senectus et netus et malesuada fames. Augue interdum velit euismod in. Urna
                cursus eget nunc scelerisque viverra mauris in aliquam sem. Ac tortor dignissim convallis aenean et
                tortor at risus. Pulvinar elementum integer enim neque volutpat ac tincidunt.</p>
            <h1>Title: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
                dolore magna aliqua.</h1>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
                dolore magna aliqua. Commodo nulla facilisi nullam vehicula ipsum. Nullam ac tortor vitae purus faucibus
                ornare suspendisse. Tortor at auctor urna nunc id cursus metus. Diam vulputate ut pharetra sit amet
                aliquam id. Tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius. In est ante in nibh
                mauris cursus mattis molestie a. Scelerisque purus semper eget duis at tellus. Pharetra massa massa
                ultricies mi quis hendrerit dolor. Neque ornare aenean euismod elementum nisi.</p>
        </div>
        <button class="button" type="button">Button 1</button>
        <button class="button" type="button">Button 2</button>
        <button class="button" type="button">Button 3</button>
    </div>
    <script src="script.js"></script>
</body>

</html>

HTML(슬라이드 버튼은 W3schools에 있는 소스 갖다 배경색만 바꿨음)

 

@font-face {
    font-family: 'KyoboHand';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_20-04@1.0/KyoboHand.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

:root {
    --dark-color: #32475e;
    --green-color: #41b883;
    --white-color: #f9f9f9;
    --yellow-color: #ffd41d;
}

* {
    font-family: 'KyoboHand';
    font-size: 16pt;
    margin: 0;
    padding: 0;
    line-height: 1.5em;
}

body {
    background-color: var(--white-color);
    color: var(--dark-color);
}

.dark-mode {
    background-color: var(--dark-color);
    color: var(--white-color);
}

h1,
p {
    margin-bottom: 5px;
}

h1 {
    font-size: 1.5em;
}

.wrap {
    width: 1280px;
    margin: 0 auto;
}

.title,
.article {
    border: 5px solid var(--green-color);
    border-radius: 7.5px;
    margin: 20px auto;
    padding: 10px;
}

/* The switch - the box around the slider */
.switch {
    position: relative;
    display: inline-block;
    width: 60px;
    height: 34px;
    margin-top: 10px;
}

/* Hide default HTML checkbox */
.switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

/* The slider */
.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: var(--dark-color);
    -webkit-transition: .4s;
    transition: .4s;
}

.slider:before {
    position: absolute;
    content: "";
    height: 26px;
    width: 26px;
    left: 4px;
    bottom: 4px;
    background-color: var(--white-color);
    -webkit-transition: .4s;
    transition: .4s;
}

input:checked+.slider {
    background-color: var(--green-color);
}

input:focus+.slider {
    box-shadow: 0 0 1px var(--green-color);
}

input:checked+.slider:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
    border-radius: 34px;
}

.slider.round:before {
    border-radius: 50%;
}

button {
    border: 0;
    width: 150px;
    height: 50px;
    border-radius: 7.5px;
    background-color: var(--yellow-color);
    margin-right: 10px;
}

button:hover {
    background-color: var(--yellow-color);
}

CSS

 

let button = document.getElementById('toggle');

button.addEventListener("click", function() {
    if(document.querySelector('body').classList.contains('dark-mode')){
        document.body.classList.remove("dark-mode");
    }else{
        document.body.classList.add("dark-mode");
    }
},false);

JS

 

슬라이드 버튼은 버튼이 쇽쇽 밀려나가는 것 말고 사실상 체크박스나 라디오버튼이랑 다를 게 없다. 자바스크립트 코드는 버튼을 눌렀을 때 클래스에 dark-mode가 있으면 지우고(라이트모드로) 아니면 붙여라(다크모드). 근데 위 코드대로 하면 어떻게 되느냐... 글이랑 배경은 바뀌는데 버튼 색이 그대로예요. 그러면 버튼에도 이걸 줘야 하는데...

 

button.dark-mode {
    color: var(--white-color);
    background-color: var(--green-color);
}

버튼에도 dark-mode를 추가하고... 위 코드대로 주면 에러난다. 버튼이 세 개니까 다 바꾸려면 querySelector가 아니라 querySelectorAll로 가져와야 하는데 문제가 뭐냐면 저걸로 갖고오면 배열이 된다. 그래서 자바스크립트 입장에서는 아니 배열인데 클래스가 어딨음? 착한 사람만 보임? 이렇게 되기 때문에 반복문으로 배열을 순회해서 볼거다.

 

let togglebutton = document.getElementById('toggle');
let button = document.querySelectorAll('button')

togglebutton.addEventListener("click", function () {
    console.log('버튼!')
    if (document.querySelector('body').classList.contains('dark-mode')) {
        document.body.classList.remove("dark-mode");
    } else {
        document.body.classList.add("dark-mode");
    }
    button.forEach(function(item){
        if (item.classList.contains('dark-mode')) {
            item.classList.remove('dark-mode');
        }
        else {
            item.classList.add('dark-mode');
        }
    })
}, false);

버튼을 querySelectorAll로 가져오게 되면 배열이라고 했는데 그러면 못 주느냐? 놉. 반복문 주면 가능하다. 배열 안의 요소들에 dark-mode가 있으면 지우고(라이트모르도) 반대로 없으면 붙이게(다크모드로) 하면 된다. 하나가 아니라 뭉텅이라 배열로 들고 온 것 뿐이지 내용물이 변하는 건 아니거든.

반응형
Lv. 36 라이츄

Lv. 36 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

방명록