Day17 __ JavaScripts-Example-6

KSGMN·2023년 10월 24일
0

JavaScripts-Examples

목록 보기
6/6

📒 Examples

📌 Note 만들기

  • Array.splice(인덱스, 갯수) : 특정 인덱스의 아이템을 삭제
  • .prepend() 메서드는 선택한 요소의 시작 부분에 지정된 내용을 삽입 (끝에 추가하려면 .add())
<style>  /* 노트 만들기 */
    *{
        box-sizing: border-box;
    }

    #container{
        display : grid;
        grid-template-columns: repeat(2,minmax(0, 1fr));
        gap : 1rem;
    }

    textarea{
        width : 100%; height : 12rem; padding : 1rem; border : none;
        box-shadow: 0 0 10px #888; outline : none; resize : none;
    }

    #add-btn{
        background-color: #333; color : #fff; border : none;
        padding : 0.5rem 0.75rem; margin : 1rem 0; font-size: 1rem;
        cursor: pointer;
    }

    #add-btn:hover{
        background-color: #222;;
    }
</style>

<button id="add-btn">New Note + </button>

<div id="container"></div>


<script>
    var container = document.getElementById("container");
    var addBtn = document.getElementById("add-btn");
    // 노트를 저장할 변수
    var notes = [];

    // 로컬스토리지 동기화 처리
    function saveData(notes){
        localStorage.setItem("noteStorage", JSON.stringify(notes));
    }

    // 씨드데이터 생성 함수(첫 예시 데이터)
    function seedData(){
        var seed = [{ id : "n0", content : "첫번째 메모"}];

        saveData(seed);
    }

    // 앱 첫 사용인 경우 샘플 메모를 생성한다
    if(!localStorage.getItem("noteStorage")){
        seedData();
    }

    // 이벤트처리
    document.addEventListener("DOMContentLoaded", getNotes);
    addBtn.addEventListener("click", addNote);

    // 노트 가져오기
    function getNotes(){
        // 로컬스토리지에서 노트를 가져온다.
        notes = JSON.parse(localStorage.getItem("noteStorage"));

        console.log(notes);

        // 노트 렌더링
        for(var i = 0; i<notes.length; i++){
            createNoteElement(notes[i].id, notes[i].content);
        }
    }

    // 노트 추가
    function addNote(){
        // 새 노트객체 생성
        var newNote = { id : "n" + Date.now(), content : ""};

        // 노트리스트에 추가
        notes.push(newNote);

        // 로컬 스토리지 동기화
        saveData(notes);

        // 노트 엘리먼트 생성
        createNoteElement(newNote.id, newNote.content);
    }

    // 노트 편집
    function editNote(id, content){
        // 전달받은 id와 일치하는 id를 가진 노트 객체의 content를
        // 전달받은 content로 업데이트 한다.
        for(var i = 0; i<notes.length; i++){
            if(notes[i].id === id){
                notes[i].content = content;
            }
        }

    }

    // 노트 삭제
    function deleteNote(id, noteElement){
        for(var i = 0; i<notes.length; i++){
            if(notes[i].id === id){
                // Array.splice(인덱스, 갯수)
                // 특정 인덱스의 아이템을 삭제할 수 있다.
                notes.splice(i, 1);
            }
        }

        // 로컬스토리지 동기화
        saveData(notes);

        // 엘리먼트 제거
        noteElement.remove();

    }

    // 렌더링 처리
    function createNoteElement(id, content){
        var noteElement = document.createElement("textarea");

        noteElement.value = content;

        // 노트엘리먼트에 이벤트리스너를 추가한다.
        noteElement.addEventListener("change", function(){
            editNote(id, this.value);
        });

        noteElement.addEventListener("dblclick", function(){
            deleteNote(id, this);
        })

        // 문서에 노트 엘리먼트 추가
        container.prepend(noteElement);
    }

</script>


📌 JS Image Editor

  • canvas(캔버스), ctx(펜)이라고 생각
  • "load" : 이미지를 로드하는 이벤트
    .naturalWidth;, .naturalHeight; : 원본 너비, 높이
  • .drawImage(이미지엘리먼트, x, y) : 캔버스에 이미지를 배치한다.
  • .nextElementSibling : 이 속성은 동일한 트리 수준의 다음 요소를 반환한다.
    다음 코드의 element.nextElementSibling.textContent = value; 에서는 <p>엘리먼트가 된다.(그래서 수치 조정할때 value값 계속 바뀜)
<style>     /* JS Image Editor */
    *{
        box-sizing: border-box;
        margin : 0; padding : 0;
    }

    nav {
        position : fixed;
        padding : 0 1rem;
        top : 0; left : 0;
        width : 250px; height: 100vh;
    }

    .title{
        display : flex;
        flex-direction: column;
        height: 8rem;
        justify-content: center;
    }

    .filter-group{
        margin : 1rem 0;
    }

    label{
        display : block;
        font-weight: 600;
    }
    .filter-input{
        width : 100%;
    }
    main {
        margin-left : 250px;
        padding : 4rem;
        height: 100vh;
        background-color: #333;
        overflow : auto;
    }
</style>

<nav>
    <h1 class=" title">JS Image Editor &#127912;</h1>

    <div class="filter-group">
        <label for="brightness">Brightness</label>
        <input type="range"name = "brightness" class="filter-input"
        min ="0" max="200" value="100" oninput="setFilter(this)">

        <p class="filter-value">100</p>
    </div>

    <div class="filter-group">
        <label for="saturate">Saturate</label>
        <input type="range" name="saturate" class="filter-input"
        min="0" max="200" value="100" oninput ="setFilter(this)">
        <p class="filter-value">100</p>
    </div>

    <div class="filter-group">
        <label for="invert">Invert</label>
        <input type="range" name="invert" class="filter-input"
        min="0" max="100" value="0" oninput="setFilter(this)">
        <p class="filter-value">0</p>
    </div>

    <div class="filter-group">
        <label for="blur">Blur</label>
        <input type="range" name="blur" class="filter-input"
        min="0" max="10" value = "0" oninput="setFilter(this)">
        <p class="filter-value">0</p>
    </div>
</nav>

<main>
    <canvas id="canvas"></canvas>
</main>

<script>
    // 캔버스
    var canvas = document.getElementById("canvas");
    // 펜
    var ctx = canvas.getContext('2d');
    // 필터 단위 저장변수
    var UNIT = {
        brightness : "%",
        saturate : "%",
        invert : "%",
        blur : "px",
    }
    // 필터 객체
    var filter = {};

    // 이미지 생성 및 가져오기
    var imgElement = new Image();
    imgElement.src =  "cat.jpg"

    // 이미지 로드 이벤트
    imgElement.addEventListener("load", function(){
        canvas.width = imgElement.naturalWidth;
        canvas.height = imgElement.naturalHeight;

        // 캔버스에 이미지를 랜더링한다.
        render();
    });

    function render(){
        // ctx.drawImage(이미지 엘리먼트, x, y)
        ctx.drawImage(imgElement, 0, 0);
    }

    // 필터 적용
    function setFilter(element){
        var name = element.name;
        var value = element.value;

        filter[name] = value + UNIT[name];

        // 필터 객체 (필터 수집)
        console.log(filter);

        // 필터를 문자열 타입으로 변환한다.
        var filterInString = "";

        // for in 반복문 : 객체 순회 반복문
        /*
            for (key in 객체)
        */
        for(var key in filter){
            filterInString += `${key}(${filter[key]}) `;
        }

        // 변환결과 (캔버스가 요구하는 형식에 맞게 변환)
        console.log(filterInString);

        // 필터 적용
        ctx.filter = filterInString.trim();

        render();

        // 필터값 수치 데이터 ( 이 경우엔 <p>엘리먼트가 됨)
        element.nextElementSibling.textContent = value;
    }

</script>


📌 URL(path, query)

  • url에서 ? 앞이 path 뒤가 query
    1 SPA (Single Page Application)의 구조
         자바스크립트를 사용하여 화면을 업데이트한다
         속도가 빠르고 화면 전환이 부드럽다.

	2 URL (Uniform Resource Locator)
         웹사이트/서버의 주소
         예) https://google.com/news/sports/?page=1

         - URL 구조 분석
             1) 경로
             리소스의 경로
             예) https://google.com/news/sports

             2) 쿼리 parameter
             url안에 작은 데이터를 전송할 때 사용한다
             path?key=value의 형태

             예) news/sports/?page=1

             3) location hash
             웹페이지에서 특정한 지점을 찾을 때 사용한다.
             url#hash

             예) news/sports/?page=1#lastArticle

	3 Router
         요청 URL과 적절한 리소스를 연결한다.
<style> /* URL(path, query) */
    a{
        color : #000;
    }
</style>

<nav>
    <ul>
        <li>
            <a href="#/">Home</a>
        </li>
        <li>
            <a href="#/posts">Posts</a>
        </li>
        <li>
            <a href="#/contact">Contact</a>
        </li>
    </ul>
</nav>

<div id="root"></div>

 
<script>
    var root = document.getElementById("root");

    // url 파싱(분석) 처리
    function parseUrl(url){
        // URL에 쿼리가 있는지 확인
        var hasQuery = url.indexOf("?") > -1;
        var path, query;

        if(hasQuery){ // 쿼리가 있을 경우
            // path(경로)와 쿼리를 변수에 저장한다.
            path = url.substring(url.indexOf("?"), -1),  // -1 은 반대방향
            query = url.substring(url.indexOf("?"))
        } else { // 쿼리가 없을 경우
            path = url;
            query = null;
        }
        return{ url, path, query } ; 

    }
    // 로드 이벤트 처리
    document.addEventListener("DOMContentLoaded", hashRouter);

    // hash 변경 이벤트 처리
    window.addEventListener("hashchange", hashRouter); // window.  는 생략가능

    // 해시 기반 라우터
    function hashRouter(){
        // console.log(location.hash);

        // 요청 URL
        var url = location.hash.substring(1); // # 지움

        console.log("원본 URL : ", url);

        var urlData = parseUrl(url);

        console.log("URL 파싱 결과 : \n", urlData);

        // 라우트 목록
        var routes = [
            { path : "/", element : Home },
            { path : "/posts", element : Posts },
            {path : "/post", element : Post },
            { path : "/contact", element : Contact },  
       ]

       // 라우팅
       for(var i=0; i<routes.length; i++){
        if(routes[i].path === urlData.path){
            root.innerHTML = routes[i].element(urlData.query);
        }
       }
    }

    // 각각의 페이지를 문자열로 트리 작성
    // 홈
    function Home(){
        return(`
            <h1>Home</h1>
            <p>Welcome to my blog.</p>
        `);
    }

    // 게시글 목록
    function Posts(){
        return(`
            <h1>Posts</h1>
            <ul>
                <li>
                    <a href="#/post?postId=p1">Second post</a>
                </li>
                <li>
                    <a href=#/post?postId=p0">First post</a>
                </li>
            </ul>`)
    }   

    // 게시물 보기
    function Post(query){
        return(`
            <h1>Post</h1>
            <p>${query}</p>
        `)
    }

    function Contact(){
        return(`
            <h1>Contact</h1>
            <p>john@example.com</p>
            `)
    }

</script>


profile
ming

0개의 댓글