HTML에 기반을 둔 커스텀 엘리먼트인 컴포넌트를 제작하고 활용

컴포넌트의 상탯값 관리와 뷰 간의 이동을 도와주는 Vuex와 라우터제공

 

05-1 복잡한 로직과 computed 속성  

computed 속성 : 머스태시를 이용해 HTML 엘리먼트값 변경에 따른 연산 작업지원

 - 원본 data를 수정으로 필요성 확인

 

* 010501 [DoIt!실습] 대문자로 변환하는 프로그램 만들기

- 0105/ex05_01 > computed.html 파일 생성

<!DOCTYPE html>
<html lang="KO">
<head>
    <meta charset="UTF-8">
    <title>computed</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <p>원본 문장 : "{{ sOriginalMessage }}"</p>
        <p>대분자로 변환된 문장 : "{{ fnUpperCaseMsg }}"</p>
    </div>
    <script>
        new Vue({
            el:'#main',
            // data는 머스태시 안에 넣을 값이 간달할 때 사용
            data:{
                sOriginalMessage: 'How are you?'
            },
            computed:{
                // sOriginalMessage의 데이터를 모두 대문자로 변환
                // 이때 데이터에 접근하기 위해 this 사용
                fnUpperCaseMsg: function(){
                    return this.sOriginalMessage.toUpperCase();
                }
            }
        })
    </script>
    
</body>
</html>

 

* 머스태시 사용 : 문자열을 {{}} 로 감싸고 엘리먼트(P) 값 표시 
 - {{ sOriginalMessage }} : 문자열 변수 대체

 - {{ fnUpperCaseMsg }} : 함수실행결과 대체

* data 속성

 - 문자열 변수(sOriginalMessage - 속성 : JSON 형식내 값 > 뷰에서는 변수처럼 처리됨) 값 초기화

* computed 속성 : computed 속성은 캐시 메모리에 저장 - 속도개선 효과 기대

 - 머스태시 내용이 복잡한 경우 함수로 전환하여 사용

 - fnUpperCaseMsg() 함수에서 this를 사용하여 data에 정의된 변수(sOriginalMessage)를 사용하여 처리함


05-2 이벤트 핸들러 로직과 methods 속성  

* 메서드 :  뷰 인스턴스에 포함해 사용하는함수

 - methods 속성 : 이벤트 핸들러를 사용해 이벤트 실행로직 작성(마우스 클릭 등)
 - 예제 : 버튼을 누를 때마다 10부터 거꾸로 세는 예제

 > computed 속성 : 머스태시 확장할 때 사용

 > methods 속성 : 이벤트 핸들러에 사용

 

* 010502 [DoIt!실습] 카운트다운 프로그램 만들기

- 0105/ex05_02 > computed.html 파일 생성

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>mothods</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <p>클릭 숫자 : {{nClicks}}</p>
        <p>카운트다운 : {{fnCounter}}</p>
        <!-- 버튼을 누르면 fnIncrement 메서드 실행 -->
        <button v-on:click="fnIncrement">눌러주세요!</button>
    </div>
</body>
<script>
    new Vue({
        el:'#main',
        data:{
            nClicks:0
        },
        // computed는 머스태시 안의 로직이 복잡할 때 사용
        computed: {
            fnCounter(){
                // nClicks 값이 10을 기준으로 카운트다운 되도록 1만큼 감소시킴
                return 10 - this.nClicks;
            }
        },
        // 메서드는 이벤트 핸들러 로직을 실행할 때 사용
        methods:{
            // nClicks 값을 1만큼 증가시킴
            fnIncrement(){
                this.nClicks++;
            }
        }
    });
</script>
</html>

* 머스태시적용

 - nClicks : 클릭개수 정보 변수를 바인딩 - 엘리먼트(p)

 - fnCounter() : 카운트로 변경되는 값 반환 - 10부터 시작하는 카운트다운 처리

* v-on 디렉티브 적용

 - 버튼을 누르면 fnlncrement() 함수를 이벤트 핸들러로 연결하여 실행

 > fnlncrement() 함수의 구체적인 기능을 methods 속성에서 정의한다

* data, computed 속성

 - data : nClicks 변수 초기값 설정 - 0

 - computed : 머스태시 선언 함수 기술 - fnCounter()
 > fnCounter() 함수는 10을 기준으로 지금까지 클릭한 횟수를 저장

 > nClicks 변수값과 뺄셈을 수행

 * 머스태시에 선언된 내용의 로직이 복갑해지면 함수로 바꿔서 computed 속성에 정의

* methods 속성

 - fnlncrement() 함수 : nClicks 변수(클릭한 횟수 저장) 값을 ++ 연산자로 증가시킨 후 반환

 > data 속성에 정의된 nClicks 변수에 접근하기 위 해 this를 사용

 

* [하나만 더 배워요!] computed 속성과 methods 속성의 차이점

 - 함수 정의 시 두 속성의 역할 : 함수 실행

 • computed 속성 : 복잡한 로직으로 머스태시 작업을 함수로 정의 - 계산량이 많아 캐시가 필요할 때
 • methods 속성 : 뷰의 이벤트 핸들러 로직을 함수로 정의


05-3 컴포넌트로 HTML 엘리먼트 만들기  

* 컴포넌트(component) : HTML의 기본 엘리먼트 외에 자신만의 엘리먼트 제작 지원

 

* 컴포넌트의 동작 원리 이해하기

 - 컴포넌트 사용법 : HTML 엘리 먼트와 동일.  여는 태그 <>, 닫는 태그 </>에 적용해 사용
  > <my-element></my-element>

 - 템플릿(template) : 컴포넌트를 등록하여 엘리먼트처럼 사용
 - 컴포넌트를 신규 엘리먼트로 구성 시 화면에 표시할 부분을 대응하는 속성 : 템플릿 속성

  > 기존 HTML, CSS, 자바스크립트를 사용해서 화면에 표시할 내용 구현

  > 사용 방법 : [template:] 속성 선언 > 문자열로 HTML 문서의 내용을 작성

 ** 문자열 줄바꿈을 고려한 이스케이프 문자 사용 : 역따음표(',backtic-백틱) - 예제 참고 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>component</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <my-element></my-element>
    </div>
</body>

<script>
    // my-element 엘리멘트용 컴포넌트 등록
    Vue.component('my-element',{
        // 컴포넌트의 data 속성은 반드시 함수로 정의!
        data: function(){
            return {
                strHello: '안녕하세요',
            }
        },
        // 템플릿은 화면에 표시할 엘리멘트 구조를 정의
        template: `<h1>{{strHello}}</h1>`
    });
    new Vue({
        el:'#main',
    });
</script>
</html>

* 010503 [DoIt!실습] 좋아하는 과일 나열하기

- 0105/ex05_03 > component_basic.html 파일 생성

- 화면에 표시할 내용 : template 속성으로 HTML, CSS, 자바스크립트를 함께 사용하면서 작성
- 백틱을 사용한 가독성 확보
 > 예제 활용 : template, data 속성만 사용하지 만 computed, methods 속성도 활용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>component_basic</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        .fruit_style {/* 테두리 스타일과 안쪽 여백을 넣어줌*/
            border: 1px solid #ccc;
            background-color: #fff;
            padding-left: 1em;
        }
    </style>
</head>
<body>
    <div id="main">
        <h1>{{ sTitle }}</h1>
        <!-- 신규 컴포넌트 엘리먼트 2개 사용 -->
        <favorite-fruits></favorite-fruits>
        <favorite-fruits></favorite-fruits>
    </div>
</body>
<script>
    // 좋아하는 과일 3개를 표시하는 컴포넌트 정의
    Vue.component('favorite-fruits',{
        // 컴포넌트의 data 속성은 반드시 함수로 정의
        data: function(){
            return {
                aFruits:[{sFruit_name:'사과'}, {sFruit_name:'오렌지'},{sFruit_name:'수박'}]
            }
        },
        // 컴포넌트 템플릿 화면에 표시할 엘리먼트 구조 정의
        template:`
        <div>
            <div v-for="item in aFruits" class="fruit_style">
                <p>좋아하는 과일:{{item.sFruit_name}}</p>
            </div><br>
        </div>`
    });
    new Vue({
        el:'#main',
        data:{
            sTitle:'안녕하세요!'
        }
    });
</script>
</html>

* 박스 스타일

 - 화면에 표시할 영역을 눈으로 쉽게 확인하기 위해 CSS 스타일 적용

 - [.fruit_ style]이라는 클래스 선택자로 경계선 구성

 > 선 : 직선, 두께 : 1px, 색상 : #ccc(회색) 설정

 > 배경색 : 흰색

* 컴포넌트 사용

 - sTitle(제목 문자열) 변수 : h1 엘리먼트의 값으로 표시.

 - h1 엘리먼트 : HTML5 예약어는 커스텀 불가

 - favorite-fruits 커스텀 엘리먼트 : HTML 엘리먼트와 같은 방식으로 사용

 > 좋아하는과일 세 가지 목록을 표시

 > 두 번 연속 사용 : 두 번 표시됨

* 컴포넌트 등록 - 뷰 객체의 component() 함수를 사용해 엘리먼트 등록

 - 매개변수1 : [favorite-fruits] 전달

 - 매개변수2 : [data, template] 속성 정의

 > data 속성 : aFruits 배열을 JSON 형식으로 정의 - 변수나 함수로 선언

 > aFruits 배열 :  sFruit_name, 과일 이름(사과, 오렌지, 수박) 항목 3개 구성

 - function() 함수에서 return 문으로 반환

** 컴포넌트에서 data 속성을 사용할 때는 반드시 함수로 사용

 - 컴포넌트 안에 data 속성을 변 수로 선언하면 실행 시 인스턴스가 생성되지 않음
 > ‘ReferenceError: aFruits is not defined’라는 오류 발생

 - 같은 컴포넌트를 여러 개 사용 시, data 속성의 변숫값들이 별도의 메모리 공간에서 개별적으로 관리되도록 하려는 의도 

 - 따라서 컴포 넌트 내부는 반드시 함수로 작성해야 합니 다.

* 컴포넌트 템플릿 작성

 - div 엘리먼트로 그룹

 - v-for 디렉티브를 사용해서 aFruits 배열 변수에 있는 항목을 하나씩 꺼내서 표시

 - p 엘리먼트에 머스태시로 바인딩하기 위해 {{ item.sFriiit_name }} 입력

 > 항목이 3개 표시, fruit_ style 클래스 선택자로 스타일 적용

 

* [하나만 더 배워요!] 목록의 구조를 잡을 때 사용하는 ul, ol, li 엘리먼트
 - ul(unordered list)과 ol(ordered list) : 목록 영역 결정
 > ul : 순서 없는 목록 - 글머리 기호 항목 앞에 표시

 - li(list) : 목록의 각 항목 표시

 > ol : 순서 있는 목록 - 항목 앞에 번호가 하나씩 커지면서 표시

<!-- ul, ol, li 엘리먼트사용 예 -->

<ul>
  <li>사과 </li> <li> 바나나 </li> <li> 수박 </li>
</ul> 

<ol>
  <li> 커피 </li> <li> 홍차 </li> <li> 녹차 </li>
</ol>




05-4 컴포넌트 속성 props  

* 컴포넌트 속성(props) : 컴포넌트에서 전달되는 어트리뷰트의 값
 - 문자열, 객체 배열 형식

 > 좋아하는과일 나열 예제 변경 : 컴포넌트 엘리먼트로 props 속성 사용

 

* 010504 [DoIt!실습] 컴포넌트 속성을 활용해 좋아하는 과일 나열하기

- 0105/ex05_04 > component_prop.html 파일 생성

 

* 뷰 컴포넌트의 어트리뷰트를 선언하는 방법, 값을 전달받아 사용하는 방법 확인

 - 뷰의 컴포넌트 기능은 HTML의 일반엘리먼트처럼 사용할 수 있으므로 기능을 무한대로 확장가능

 > 다양한 주제별로 그에 맞는 엘리먼트 설계해서 사용
 > 의미있는 컴포넌트 엘리먼트 이름으로 심플코드 개발 가능(어트리뷰트 설계 유의) : 유지보수 용이

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>component_prop</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
        // Vue 인스턴스에 신규 엘리먼트 컴포넌트 등록
        // props에 엘리먼트에 사용될 속서 이름 선언
        // template에 전달받은 속성 객체의 text 제목을 렌더링에 활용
        Vue.component('favorite-fruits', {
            props: ['fruit'],
            template:`<li>{{ fruit.text }}</li>`
        })
    </script>
</head>
<body>
    <div id="app">
        <h1>좋아하는 과일!</h1>
        <ol>
            <!-- 
                favorite-fruits 신규 엘리먼트 사용
                aFruits 배열의 값을 반복문으로 가져와 fruit 속성에 바인딩하여 컴포넌트에 전달
                key 속성은 반드시 고유한 값으로 전달되어야 하므로 item의 id값 대입
             -->
             <favorite-fruits
              v-for="item in aFruits"
              v-bind:fruit="item"
              v-bind:key="item.id">
             </favorite-fruits>
        </ol>
    </div>
    <script>
        var app = new Vue({
            el:'#app',
            data:{
                aFruits:[
                      {id:0, text: '사과'}
                    , {id:1, text: '오렌지'}
                    , {id:2, text: '수박'}
                ]
            }
        });
    </script>
</body>
</html>

* 컴포넌트등록 

 - 컴포넌트 : HTML 엘리먼트와 동일하게 사용 - 어트리뷰트 사용가능

 > props 속성 선언

 - 선언된 이름을 다른 속성에서 전달받아 매개변수처럼 사용

* 컴포넌트 등록 (이름 : favorite-fruits)

 - props 속성에 대괄호([])를 사용해서 어트리뷰트 이름을 문자열로 선언
 > HTML에서 favorite-fruits 엘리먼트를 사용할 때 다음과 같이 fruit 어트리뷰트에 값 전달

 <favorite-fruits fruit="사과"></favorite-fruits>

* template 속성에 li 엘리먼트로 속성값 표시

 - 머스태시로 <li>{{ fruit.text }}</li> 작성 :  li 엘리먼 트값으로 바인딩
 > 속성값으로 전달받은 fruit 변수는 text 속성으로 전달

 > 유의 : props 속성에 선언하여 어트리뷰트로 전달받은 fruit 변수 : 일반 변수처럼 사용가능

* 컴포넌트사용 

 - favorite-fruits 컴포넌트를 등록 > 일반적인 HTML 엘리먼트처럼 사용

 > 소스에서는 먼저 ol로 순서 있는 목록의 영역 지정

 - 목록의 개별 항목은 li 엘리먼트 대신에 favorite-fruits 엘리먼트 사용

 > favorite-fruits 엘리먼트 : 내부적으로 li 엘리 먼트를 가지 면서 전달받은 속성값을 표시하도록 설계

 - 신규로 등록한 컴포넌트의 엘리 먼트에 어트리뷰트를 어 떻게 사용하는지 잘 표현

 - v-for 디렉티브도 사용가능 : aFruits 배열 변수에서 값을 꺼내 item에 하나씩 저장

 - v-bind 디렉티브를 사용해서 fruit 어트리뷰트에 바인딩하여 항목값을 전달

 > v-bind:key 바인딩은 v-for 디렉티브를 사용할 때는 key 어트리뷰트에 고유한 값 전달해 사용하도록 강제
 > item.id의 값을 전달하면 간단히 해결

* data 속성 

 - aFruits 배열 변수 : data 속성에 정의

 > JSON 형태로 id와 text에 번호와 과일 이름을 저장

 


05-5 상탯값 관리와 Vuex  

 

 


05-5 상탯값 관리와 Vuex  

 

 


05-6 내비게이션과 라우터  

 

 


05-7 새로 고침이 필요 없는 SPA 만들기  

 

 

드디어 뷰다뷰

04-1 뷰, 자바스크립트프레임워크의절대 강자

* 뷰 (Vue.js)

 - 2013년 출시 : 에반 유(Evan You) 개발 - 자바스크립트 프레임 워크

 - 앵귤러, 리액트에서 발견할 수 없는 콤팩트한 프레임워크 제작

 - 훌륭한 문서, 제이퀴리를 넘어선 좋은 아이디어 결합

 > 뷰 2.0부터 크게 주목

 

https://ko.vuejs.org/

 

Vue.js - The Progressive JavaScript Framework | Vue.js

접근성 HTML,CSS, 자바스크립트 표준을 기반으로, 쓰기 편한 API와 최고 수준의 문서를 제공합니다.

ko.vuejs.org

 

* 목적 : 인터랙티브 웹 인터페이스를 개발 - 프로그레시브 자바스크립트 프레임워크

 - 프로그레시브(progressive) : 프로그램 실행에 필요한 최소한의 모듈로부 터 점점 확장

 > 웹에서 UI, 비즈니스로직, 데이터 관리를 돕는 최고 성능의 콤팩트한 자바스크립트 라이브러리 

 

[뷰가 주목받는 4가지 이유]

 - 뷰의 기능 대부분이 앵귤러, 리액트와 유사하며 가상 돔(virtual DOM)을 제어하는 기능도 제공

① 디자이너와 개발자를 위해 쉽게 설계

 - HTML과 CSS 토대에서 동작 : 기존 웹 표준 작업과 유사

 - 접근성이 좋은 공식 문서

  (리액트 : JSX라는 새로운 문법 공부, 모두 자바스 크립트로만 관리 - 진입 장벽이 높음)

② MVC(model view controller) 모델을 지원

 - 리액티브 양방향 데이터 바인딩(reactive two-way data binding) 지원 (like 앵귤러)

 > 리액티브 : 데이터의 변화를 자동으로 체크해서 화면을 바꾸는 동기화

 - DOM 작업에 집중할 수 있도록 직관적으로 쓰기 편한 디렉티브를 제공

③ HTML5와 자바스크립트만 알면 되므로 쉽게 시작

 - 뷰는 HTML5와 자바 스크립트만 필요

 - 앵귤러 비

 > 정적 타입의 자바스크립트를 위해 만든 타입스크립트(TypeScripr)문법 필요

 > 파일 구조 복잡, 큰 덩치

④ 설치하기 쉽고 용량이 작아서 속도가 빠르다

 - 설치하기 쉽고 필요한 파일 용량이 작다.

 - HTML, CSS, 자바스 크립트환경에서 연결해 사용하기 편리

 

[뷰, 자바스크립트 프레임워크의 절대 강자!]

 - 뷰 : 출발은 늦었지만 두 프레 임 워크의 단점 보완 - 성능 우수

 > 앵귤러, 리액트에 비해 전망이 좋다.

 - 자바스크립트 관련 기술 트렌드 통계 :  bestofjs.org

 

 


04-2 ‘안녕하세요!’ 예제 만들기

* 핵심내용

 - 처음 시작을 CDN으로 설정 하는 방법

 - 머스태시 {{ }}  활용법

 - data 속성 바인딩 관계

 

* 010402 [DoIt!실습] 뷰로 ‘안녕하세요!’ 출력하기

- 0104/ex04_01 > hello_vuejs.html 파일 생성

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>hello_vuejs</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>

<body>
    <div id="main">
        <!-- sTitle값을 받아서 HTML의 엘리멘트값으로 변환하여 표시 -->
        <p>{{ sTitle }}</p>
    </div>    
    <script>
        // VUE 객체를 생성해 앱을 초기화하고 시작
        new Vue({
            // id 선택자인 'main'의 div 엘리먼트와 앱을 연결해서 구동
            el : '#main',
            data : {
                // {{ sTitle }}로 데이터값 전달
                sTitle : '안녕하세요!'
            }
        });
    </script>
</body>
</html>

* 보완 : cdn 참조링크
 - 교제 : https://cdn.jsdelivr.net/npm/vue 

 > 수정 : https://cdn.jsdelivr.net/npm/vue@2

 

 * 뷰 적용시 가장 쉬운 방법 : cdn 연결
  -  방법 : 뷰 모듈 주소를 head 테그 사이에 설정

 * 머스태시 사용 : 변수, 함수 결과를 html의 엘리먼트 값으로 변환하여 브라우저에 출력 - 랜더링(rendering)

  -  중괄호 2개를 겹쳐서 표현 : 콧수염 모양과 미슷하여 '머스태시'라고 함

  > {{ sTitle }} : sTitle 문자열 값을 p 엘리먼트의 값으로 변환하여 표시

 * 뷰 앱 구동 

  - 뷰 객체 생성 : HTML의 body 엘리먼트 중, 뷰 화면이 표시될 영역을 el(element) 속성에 선택자로 지정

  > [el : '#main'] - el속성에 #main 으로 div 엘리먼트 부분을 연결 : #main 부분에 뷰 실행내용이 렌더링 됨

 * data 속성

  - 뷰안에서 사용할 데이터를 변수명으로 선언하여 관리

  > 객체, 함수 선언 - 데이터를 읽고 저장하는 일 지원 : 리엑티브(reactive) 하다고 표현?

  - [sTitle : '안녕하세요!'] 문자열의 제목을 저장하는 sTitle 변수의 초기값 정의

  > 뷰에서 HTML 엘리먼트와 함께 머스태시 안에 바인되어 자동으로 표시할 때 sTitle 값 활용

  (sTitle 값을 HTML 구조 안에서 직관적으로 활용 가능)


04-3 단방향 바인딩과 v-bind 디렉티브

 

데이터 바인딩 : HTML의 어트리뷰트값을 수정할 때 V-bind라는 디렉티브를 이용해서 데이터를 브라우저 화면에 지동으로 반영하는 것

 - 변수값을 HTML 어트리뷰트값에 연결 : 변수가 새로운 값으로 바뀔 때마다 HTML 엘리먼트에 실시간으로 렌더링

 > v-bind 디렉터브는 데이터가 한쪽으로만 바인딩되는 단방향 바인딩 (양방향 : v-model - 04-4절)

    (HTML 엘리먼트의 어트리뷰트값 변경시, 연결된 변수값은 변경안됨)

 

* 010402 [DoIt!실습] 올해 연도를 자동으로 표기하는 프로그램 만들기

# 0104/ex04-02/v-bind.html

<!DOCTYPE html>
<html lang="kr">
<head>
    <meta charset="UTF-8">
    <title>v-bind</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        /* 화면에 렌더링할 때 사용할 제목의 색상을 파란색으로 정의 */
        .blue_style {color: blue;}
    </style>
</head>
<body>
    <div id="main">
        <!-- v-bind 안에서도 자바스크립트를 사용할 수 있으므로 변수와 문장을 연결 -->
        <h1 v-bind:class="sColorName + '_style'">안녕하세요!</h1>
        <!-- 콜론(:) 앞은 생략 가능 -->
        <!-- <input:value="sDate"/> 화면깨짐 -->
        <input v-bind:value="sDate"/>
    </div>
    <script>
        let app = new Vue({
            el: '#main',
            data:{
                // Data 객체의 getFullYear() 메서드로 올해 연도 문장 준비
                sDate: '올해 연도: ' + new Date().getFullYear(),
                sColorName: 'blue'
            }
        })
    </script>
</body>
</html>

* 제목에 CSS 스타일 적용 : 뷰는 CSS 스타일을 그대로 활용 - 웹 표준 활용 가능
 - 제목의 글자 색상 스타일 파란색으로 변경

 > .blue_style 클래스 선택자 이용 : color: blue 정의

* v-bind 디렉티브 적용
 - <h1> 태그 안에서 class 어트리뷰트와 뷰의 속성 바인딩 : v-bind 디렉티브 활용

 > v-bind 입력 > 콜론(:)  > 바인딩할 뷰의 속성 연결
 - sColorName 색상 문자열 제목 + _style 연결 : 클래스 선택자 이름

 > class 어트리뷰트에 대입 : sColorName 값이 blue > blue_style 완성된 선택자 이름

 > v-bind 디렉티브를 통해 바인딩 : class="blue_style" 대입

 > h1 엘리먼트 : 파란색 제목으로 표시

* v-bind 생략 : 되나? 된다. 책 코드 자세히 보면 input 뒤에 스페이스가 있...
 - v-bind는 콜론(:)만 남기고 생략 가능

 > input 엘리먼트에서 :value만 사용 : value 어트리뷰트에 sDate의 날짜를 문장으로 받아서 대입

 > input 엘리먼트를 통해서 만들어진 텍스트 박스 안에 오늘 날짜 표시

 > (:) 만 있고 엘리먼트의 어트리뷰트 이어서 표시 : 'v-bind' 디렉티브 생략

* sDate와 sColorNamedata 속성
 - 올해 연도 저장 : sDate 문자열 변수

 - CSS 스타일에 사용 : sColorNam 문자열 변수

 > 올해 연도 : 자바스크립트의 Date객체 생성 - getFullYear() 메서드 : 올해 연도를 숫자로 반환 - sDate에 저장

 > ‘blue’라는 문장을 sColorName 변수에 초기값으로 대입

 > sDatesColorName 두 변수에 담긴 문자열은 v-bind 디렉티브를 사용해서 바인딩할 때 적용

 

* 화면깨짐 : <input:value="sDate"/>
 - Vue 버전 영향인 둣  > input 다음에 공백(스페이스) 있었...

* 개선소스 결과

 

* 하나만 더 배워요! - 머스태시와 v-bind의 차이점

 - 머스태시({{ }}) : HTML의 값을 만들 때 사용

 - v-bind : HTML 어트리뷰트에 바인당할 때 사용

머스태시와 v-vind 차이점
<p>{{ sTitle }}</p> // HTML 엘리먼트값을 만듬
<input v-bind:value=”sDate"> // HTML 어트리뷰트값을 만듬

04-4 양방향 바인딩과 v-model 디렉티브

* 양방향 데이터 바인딩 : v-model 디렉티브를 사용
 - HTML 어트리뷰트에 양방향 데이터 바인딩을 수행

 > 작성 : v-model:[HTML 엘리먼트의 어트리뷰트]

 - 바인딩된 값이 해당 엘리먼트의 어트리뷰트에 대입

 > 엘리먼트의 어 트리 뷰트값이 변수와도 연동

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>v-model</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <p>{{ sMsg }}</p>
        <!-- v-model은 데이터를 가져오는 동시에 입력이 동기화 됨 -->
        <!-- 엘리먼트의 어트리뷰트는 'v-model:' 다음에 명시 -->
        <input v-model:value="sMsg">
    </div>
    <script>
        var main = new Vue({
            el:'#main',
            data: {
                sMsg:'안녕하세요!'
            }
        })
    </script>
    
</body>
</html>

 - v-model 디 렉티브 : v-bind와 비슷하지만 양방향으로 바인딩됨

 - 변수에 있는 값을 바인딩하여 HTML 어트리뷰트에 렌더링

 > sMsg라는 문자열 변숫값은 p 엘리먼트에 머스태시로 바인딩되어 HTML값을 표시

 > input 엘리먼트의 value 어트리뷰트는sMsg라는문자열 변수와 바인딩되어 input 엘리먼트 안에 값을 표시

 -  HTML 어트리뷰트의 값이 바뀌면 바인딩된 변수의 내용도 함께 동기화

 > input 엘리먼트의 입력값 변경 시 value 어트리뷰트에 저장

 > 저장된 값은 실시간으로 sMsg 변수와 연동되어 자동으로 저장

 >> input 엘리먼트에 입력된 값은sMsg 변수와 일치됨(동기화)

 - sMsg 문자열 변수는 상탯값을 저장하고 있으므로 data 속성에 정의 : 초기값 설정

 

* [ 하나만 더 배워요! ] v-bind v-model의 차이점

<input v-bind:value=’’sDate"> // sDate 값을 HTML 어트리뷰트에 보내기만 함
<input v-model:value="sMsg"> // sMsg 값과 입력값이 서로 연동됨

04-5 조건 판단과 v-if, v-else 디렉티브

* v-if 디렉티브 : 조건이 충족될 때만 렌더링을 수행하도록 돕는 어트리뷰트

 - HTML 엘리먼트중에서 어떤 것을사용할지 특정 조건을 기준으로 판단 시 사용

 > v-if 디렉티브에 조건을 바인딩해서 대입하면 true 또는 faIse에 따라 사용할 HTML 엘리먼트를 결정

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>v-if</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="app">
        <h1>{{ bFlag }}</h1>
        <!-- v-if, v-else 로 직접 bFlag 데이터에 접근해 조건 판단 -->
        <p v-if="bFlag == true">앞면!</p>
        <p v-else>뒷면!</p>
    </div>
    <script>
        var app = new Vue({
            el:'#app',
            data:{
                // 난수(0~1) 생성 후 0.5보다 크면 true, 아니면 false 지정
                bFlag:Math.random() > 0.5
            }
        })
    </script>
</body>
</html>

 - h1 엘리먼트를 사용해서 true 또는 false라는 값을 가진 bFlag 변숫값을 제목으로 표시

 > v-if 디렉티브를 이용해서 true이면 p 엘리먼트값으로 ‘앞면!'

 > false이면 v-else 디렉티브에 지정한 엘리먼트를 실행하므로 ‘뒷면!'

 - 상황을 연출하기 위해서 random() 함수를 사용

 > random() 함수는 01 사이의 부동소수점 난수(임의의 수)를 생성
 >> 0.5보다 큰지 확인하는 조건을 설정 > 동전 던지기처럼 truefalse값을 bFlag에 저장


04-6 반복문과 v-for 디렉티브

* v-for 디렉티브 : 반복문으로 배열값을 읽어서 목록의 항목과 인덱스 변수에 저장하도록 돕는 어트리뷰트
- 반복문으로 데이터를 하나씩 차례로 꺼내서 사용할 때 유용

 > 값을 하나 꺼내 저장해 두는 항목변수(item)를활용해 원하는 데이터 속성에 접근

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-for</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <h1>좋아하는 과일은?</h1>
        <ol>
            <!-- v-for를 통해서 반복문으로 aFruits 과일 배열 데이터를 가져옴 -->
            <li v-for="item in aFruits">
                <!-- aFruits 안의 항목을 하나씩 꺼내서 HTML로 렌더링 -->
                {{ item.sFruitName}}
            </li>
        </ol>
    </div>
    <script>
        var main = new Vue({
            el:'#main',
            data:{
                // 과일 이름으로 이루어진 aFruits 배열을 데이터로 정의
                aFruits:[
                    {sFruitName : '사과'},
                    {sFruitName : '오렌지'},
                    {sFruitName : '포도'}
                ]
            }
        })
    </script>
</body>
</html>

 - 데이터를 하나씩 차례로 읽어 원하는 항목만 선택해서 표시 : 배열 데이터를 주로 활용

> 처음부터 끝까지 값을 하나씩 읽고 원하는 로직으로 바인딩한 후 HTML로 렌더링 하는 방식

 - aFruits라는 배열에 저장된 데이터 : v-for디렉터브를 이용해서 값을 하나씩 차례로 꺼낸 후 item이라는 변수에 대입

 - 머스태시를 이용해서 순서 있는 목록을 만드는 ol 엘리먼트의 리스트 항목인 li로 하나씩 연결

 > 과일 이름은 item 변수의 sFruitName 문자열 변수에 저장되었으므로 점(.)을 이용해서 접근

 - 과일 이름을 배열로 정의하기 위해 대괄호를 이용 : JSON 형식으로 저장

 > JSON : 중괄호를 사용하고 키(sFruitName)와 값(과일 이름)을 콜론(:) 으로 구분



04-7 이벤트 핸들러 실행과 v-on 디렉티브

* v-on 디렉티브 : 뷰에서 발생하는 이벤트를 지켜보면서 DOM 엘리먼트를 제어

 - 이벤트가 발생했을 때 이에 해당하는 함수를 실행하는 방식으로 사용자와 상호 작용시 사용

  > 작성 : v-on:[이벤트 이름]

 - 이벤트 핸들러 :  이벤트가 발생했을 때 실행되는 함수

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>v-on</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="app">
        <h1>{{ sTitle }}</h1>
        <!-- 버튼을 누르면 fnChangeTitle 메서드로 이벤트 핸들러 수정 -->
        <button v-on:click="fnChangeTitle">눌러주세요.</button>
    </div>
</body>
<script>
    new Vue({
        el:'#app',
        data:{
            // sTitle의 초기값 설정
            sTitle:'안녕하세요!'
        },
        methods:{
            // 버튼을 눌렀을 때 sTitle의 제목값 변경
            fnChangeTitle(){
                // this는 Vue 객체의 인스턴스를 가리킴
                this.sTitle = 'Hello!'
            }
        }
    });
</script>
</html>

 - v-on 디렉티브를 이용해 button 엘리먼트를 click 이벤트에 바인딩해서 fnChangeTitleQ 함수를 실행

 - 화면에 표시되는 값이 실시간으로 바뀌도록 sTitle이라는 문자열 변수를 정의 : 초기값 설

 - methods 속성 : 이벤트를 발생시키거나 뷰 안에서 어떤 기능을 수행하는 모듈 형식의 함수를 만들 때 사용

 > methods 속성 안에 fnChangeTitleQ 함수정의 : 사용자가 버튼을 클릭했을 때 이벤트 핸들러로 실행

 - this 키워드는 methods 속성의 소유자를 지목 : this는 생성된 뷰 객체 자신

 > this를 사용하는 이유 : methods 속성의 소유자만이 바깥에 있는 data 속성에 접근 - sTitle값 사용

 

 

Uncaught TypeError: Cannot read properties of undefined (reading 'browserObject')
at webcontent.js:1:266
at webcontent.js:2:463
at webcontent.js:2:467

methods 를 method 로 오타 상태에서 라이브서버를 실행하니 화면이 안떴다. 그래서 오타를 수정하고 새로고침 상태에서 실행하니 위와 같은 오류메시지가 표시되며 이벤트가 동작하지 않았다. 
수정없이 라이브서버를 재실행 했더니 이벤트가 잘 동작했다.

그랬다9.


미션 코딩! v-for 디렉티브로 고객 정보 출력하기

 

1차 html 코딩

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>v-for-mission</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <h1>고객정보</h1>
        <!-- 
        * 번호 : 0
          이름 : 홍길동
          나이 : 27
        * 번호 : 1
          이름 : 이순신
          나이 : 30
        * 번호 : 2
          이름 : 김유신
          나이 : 40
        -->
        <ul >
            <li>
                번호 : 0
            </li>
            <p>이름 : 홍길동</p>
            <p>나이 : 27</p>
            <li>
            번호 : 1
            </li>
            <p>이름 : 이순신</p>
            <p>나이 : 30</p>
            <li>
            번호 : 2
            </li>
            <p>이름 : 김유신</p>
            <p>나이 : 40</p>
        </ul>
    </div>
    <script>
        var main = new Vue({
            el:'#main',
            data:{
            }
        })
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>v-for-mission</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="main">
        <h1>고객정보</h1>
        <!-- 
        * 번호 : 0
          이름 : 홍길동
          나이 : 27
        * 번호 : 1
          이름 : 이순신
          나이 : 30
        * 번호 : 2
          이름 : 김유신
          나이 : 40
        -->
        <ul v-for="item in customers">
            <li>
                번호 : {{item.no}}
            </li>
            <p>이름 : {{item.name}}</p>
            <p>나이 : {{item.age}}</p>
        </ul>
    </div>
    <script>
        var main = new Vue({
            el:'#main',
            data:{
                customers : [
                    {no:0, name:"홍길동", age:27}, 
                    {no:1, name:"이순신", age:30}, 
                    {no:2, name:"김유신", age:40}, 
                ]
            }
        })
    </script>
</body>
</html>

 


 

* 뷰(Vue.js) : 실글페이지 애플리케이션 (SPA), 리액티브프로그래밍, 데이터바인딩 지원

* 뷰티파이(Vuetify.js) : 구글 머티리얼 디자인 스펙에 맞는 컴포넌트 단


03-1 ‘안녕하세요! PWA by JS’ 구경하기  

 - 3장에서 작성할 실습 프로젝트 실행

 

* 010301 [DoIt!실습] ‘안녕하세요! PWA byJS’ 예제 실행하기

- 0103/ex03_01-sample : index.html > <GO Live> 실행

 


* 매니페스트 등록 확인
 - 크롬 개발자도구 > Application > Manifest
 > Identity
 > Presentation

 > Icons


* 서비스워크 동작
 - 크롬 개발자도구 > Application > Service Worker

 > Status : 녹색 상태 아이콘 - 동작


* PWA 이벤트 처리 :  console 확인


* Offline 상태 동작확인
 - 크롬 개발자도구 > Network > No throttling > Offline : 인터넷 차단

 > 새로고침하여 동작여부 확인

 - Network에서 Offline 설정 시 
 > 정상 처리된 거래는 캐시에서 조회된 파일

 > 연결 실패한 거래는 빨간 항목으로 표시


* 서비스워커 삭제 : 캐시에 남아있는 결과화면 방지를 위해 실습 후의 기존 서비스워커 삭제 필요
 - 크롬 개발자도구 > Application > Storage > Clear site data (Usage 그래프 아래) 

* 프로그램 종료

 - vsCode <Go Live> 서버 종료 : IDE 하단 상태바에 표시된 [Port:5500] 클릭으로 서비스 정지

 


 

03-2 매니페스트 작성하기  

* 010302 [DoIt!실습] 프로젝트 준비하기

- 0103/ex03_practice > 프로젝트 폴더 설정 : 파일 > 폴더 열기

* 다양한 아이콘 준비 : 멀티플랫폼 지원 대응 - 셈플프로젝트 이미지 리소스 복사

 - 홈화면 아이콘

 - 웨브라우저 파비콘(favicon)

 - 스플래시스크린(splash screen)


* 010303 [DoIt!실습] 웹앱 매니페스트 작성하기
- 0103/ex03_practice/manifest.json 파일을 생성

 

* 파일작성

 - 유효성 검사 : https://manifest-validator.appspot.com/ 막힘

{
    "name":"안녕하세요! PWA by JS",
    "short_name":"PWA by JS",
    "description":"PWA start program",
    "scope":".",
    "start_url":"./",
    "display":"fullscreen",
    "orientation":"protrait",
    "theme_color":"#ffffff",
    "background_color":"#ffffff",
    "icons":[
        {
            "src":"images/icons/android-chrome-512x512.png",
            "sizes":"512x512",
            "type":"image/png"
        }
    ]
}

 - name : 바로가기아이콘설치 퀀장 팝업 배너 및 스크린에 표시되는 제목

 - short_name : 바탕화면 바로가기 아이콘 아래 표시되는 제목

 - description : 애플리케이션의 간단한 소개 (PWA 수집 웹크롤러에 수집되는 정보)

 - scope :  매니페스트에 정의된 내용이 적용될 파일들의 범위 지정

 - start_url : 프로그램 실행으로 시작될 URL을 루트경로로 지정

   ('.' : 현재위치 / './' : 현재위치를 중심으로 시작하는 하위폴더)

 - display : PWA를 실행하면 나타나는 화면의 형태

  > fullscreen : 최대화면 - 지원하지않는 OS인 경우 standalone 적용

  > standalone : 화면만 표시(주소, 상태표시줄등 제거)

  > minimal-ui : standalone에 주소만 추가 - 지원하지 않는 OS인 경우 standalone 적용

  > browser : 브라우저와 같은 구성

  (모바일기기가 PWA를 앱으로 인식하는 옵션 : fullscreen, standalone, minimal-ui / 웹으로 인식하는 옵션 : browser)

 - orientation : 화면의 방향

  > portrait : 세로(초상화)

  > landscape : 가로(풍경화)

 - theme_color : 상태표시줄의 색상 설정

 - background_color : 스플래시스크린 배경색 설정

 - icons : 스플래시스크린에 표시할 아이콘 이미지 - 128dpi에 가까운 이미지를 화면에 표시
  > src : 이미지 경로(절대/상대)

  > sizes : 이미지 픽셀 크기

  > type : 이미지 파일 유형


 

03-3 메인 화면 작성하기 

* 010303 [DoIt!실습] index.html 파일 작성하기

- 0103/ex03_practice > index.html 파일 작성하기

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">

    <!-- PWA 매니페스트 파일 연결, 상태 표시줄 색상을 흰색으로 변경 -->
    <link rel="manifest" href="manifest.json">
    <meta name="theme-color" content="#ffffff">

    <!-- 모바일 기기 뷰포트, 브라우저 주소 표시줄의 파비콘 설정 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- <meta name="viewport" content="width=device-width, user-scalabe=no"> -->
    <link rel="shortcut icon" href="images/icons/favicon.ico">
    <link rel="icon" type="image/png" sizes="16x16" href="images/icons/favicon-16x16.png">
    <link rel="icon" type="image/png" sizes="32x32" href="images/icons/favicon-32x32.png">

    <title>안녕하세요! PWA by JS</title>
        <style>
            html, body{
                /* html, body 모두 높이를 100%로 고정시켜야 플렉스 박스 동작 */
                heigth: 100%;
                background-color: #F3A530;
                color: #ffffff;
            }
		/* 화면에 출력될 div엘리먼트를 화면 가운데 배치하도록 설정 */
            .container{
                height: 100%;            /* 높이를 100%로 고정 ㅇ*/
                display: flex;           /* 플렉스 박스로 배치 */
                align-items: center;     /* 상하 가운데 정렬 */
                justify-content: center; /* 좌우 가운데 정렬 */
            }
        </style>
</head>
<body>
    <div class="container">
        <h1>안녕하세요!</h1>
        <img src="/images/hello-pwa.png" alt=""/>
        <p>by JK</p>
    </div>
    <!-- 서비스워커 등록 -->
    <script>
        if('serviceWorker' in navigator){
            navigator.serviceWorker
            .register('/service_worker.js')
            .then(function () {
                console.log("서비스워크가 등록됨!");
            })
        }
    </script>
</body>
</html>

 

* 언어설정 : 설정하지 않으면 실행할 때마다 ‘디른 언어로 번역하시 겠습니 까?’라고 질문

 - <html lang="ko">

* 뷰포트설정 - 모바일 브라우저로  PC 사이트 접속시 작게 보이는 현상 방지

 - content의 어트리뷰트 값 설정

  > width-=device-width : 몹바일 기기의 해상도로 너비값 자동 설정

  > initial-scale=1 : 모바일 기기에서 확대하거나 축소 기능 허용

  > user-scalable=no : 모바일 기기에서 확대하거나 축소 기능 제한

* 플렉스 박스 설정 : 화면에 표시할 글자와 이미지를 배치할 레이아웃 - 플렉스 박스(flex box)
  - 모바일 기기의 크기를 자동으로 고려한 최적의 레이아웃 표현
  > html, body 높이를 100%로 고정 필요

* 화면 요소 배치

  - 화면에 실제 출력되는 내용 :  container 클래스를 선택자로 지정한 div 엘리먼

 > div 엘리먼트를 화면 가운데 배치하도록 지정

* 서비스워커 등록 : if('serviceWorker' in navigator)...

 - navigator.serviceworker에는 ServiceWorkerContainer라는 읽기 전용의 객체가 반환
 > 이 객체 안에 있는 register() 메서드를 이용해

 모바일 브라우저가 서비스 워커를 지원하는지 확인한 후

 > 서비스 워커를 등록

 - then() 메서드는 register() 메서드의 실행이 성공하면 실행

 > register() 메서드가 실행되면 콘솔에 성공 메시지를 줄력

 


 

03-4 서비스 워커 만들고 실행하기  

* 010304 [DoIt!실습] 캐시를 관리하는 서비스 워커 만들기

- 0103/ex03_practice > 캐시를 관리하는 서비스 워커 만들기

 

* 서비스워커

 - 브라우저와분리되어 독립해서 실행 가능

 - 캐시, 푸시 알림 , 웹 API와 연동 등 다양한 기능을 별도로 수행

 > 실습대상 : 필요한 파일을 캐시하여 메모리에 저장

 

* service_worker.Js 파일 생성

// 캐시 제목과 캐시할 파일 선언
const sCacheName = 'hello-pwa'; // 캐시 제목 선언
const aFilesToCache = [         // 캐시할 파일 선언
    './', './index.html', './manifest.json', './images/hello-pwa.png'
];

// 서비스 워커 설치하고 캐시파일 저장
self.addEventListener('install', pEvent => {
    console.log("서비스 워커 설치함!");
    pEvent.waitUntil(
        caches.open(sCacheName)
        .then(pCache => {
            console.log("파일을 캐시에 저장함!");
            return pCache.addAll(aFilesToCache);
        })
    );
});

//고유 번호를 할당받은 서비스 워커 작동
self.addEventListener('activate', pEvent => {
    console.log("서비스워커 동작 시작됨!");
});

// 데이터 요청을 받으면 네트워크 또는 캐시에서 찾아 반환
self.addEventListener('fetch', pEvent => {
    pEvent.respondWith(
        caches.match(pEvent.request)
        .then(response => {
            if(!response){
                console.log("네트워크에서 데이터 요청!", pEvent.request);
                return fetch(pEvent.request);
            }
            console.log("캐시에서 데이터 요청!", pEvent.request);
            return response;
        }).catch(err => console.log(err))
    );
});

 - 오프라인 동작을 위해 서비스워커가 캐시에 저장하

 > 캐시 제목과 캐시할 파일 선언 : 캐시 제목은 서비스워커와 구분되도록 고유이름 사용

* 서비스 워커 설치 및 캐시 파일 저장 - install 이벤트

 - 서비스 워커의 생애 주기

 > [install - activate - fetch] 순서로 이벤트 발생

 * install : PWA를 설치 - 서비스워커의 첫번째 생애주기

 

 > 설치전 : installing

 > 설치 후 대기 :installed

* 서비스 워커가 제대로 설치되면 pEvent에 포함된 waitUntil() 함수를이용해 비로소 캐시에 필요한 파일 저장
* 서비스 워커가준비될 때 캐시를 저장하는 것 :  ‘프리 캐시(pre-cache)’
 - waitUntil() 함수는 installing 상태에서 프리 캐시가 완료될 때까지 대기

 - activate : 설치후 상태

 

* activate 이벤트 : 서비스 워커의 두 번째 생애 주기


- 서비스 워커 업데이트  : 서비스 워커가 고유한ID를 발급받아 브라우저에 성공적으로 등록되면 동작
 > 웹 브라우저 의 개발자 도구에서 확인

 

* 서비스 워커 설치 후 - 업데이트 등의 이유로 캐시 제목 변경 : install 이벤트 처음부터 다시 발생

 - 테스트할 때는 'Update on reload’ 체크 박스를 선텍 : 매번 캐시제목 변경 서비스워커등록 생략

 > 새로 고침 : 기존 서비스 워커 ID 제거 -> 새로운 ID를 부여 : install 이벤트부터 새로 시작

 

* 앱 업데이트 시 서비스 워커 새로운 내용으로 교체 : activate 이벤트

 - 활성중 : activating

 - 활성후 : activated

* 서비스 워커의 내용 업데이트 : 
 - 먼저 캐시 제목과 프리 캐시 파일 변경 : 새로운 서비스 워커 ID로 새로운 캐시 내용이 설치 목적

 - activating 상태에서 waitUntil() 함수를 사용해서 기존 캐시 제거 : 코드작성

 

* 오프라인 전환할 때 동작 - fetch 이벤트

 - 서비스 워커의 마지막 생애 주기는 fetch 이벤트로부터 시작
 > 이벤트가 발생 사례 : 브라우지 〈새로 고침〉
* 동작

 - 온라인 상태 : 서버에서 조회

 - 오프라인 상태 : 캐시에서 조

* 서비스 워커의 유무에 따른 fetch 이벤트 처리

 - 1 : 온라인 - 서비스워커 없음

 - 2 : 오프라인 - 서비스워커 있

* PWA 오프라인 동작 구조 :  fetch 이 벤트 발생 후 (pEvent에 있는) respondWidth() 함수 활용

 - respondWidth() 함수 : 결과값 준비 까지 네트워크 요청 일시 정지

 > 캐시, 모바일 기기에 임시로 저장한 데이터로 처리

 

* service_worker.js

 - 오프라인 처리 : PWA가 실행되면 캐시에서 가져올 데이터를 caches.match() 함수로 캐시 저장소에서 검색

 > 발견된 캐시(response)를 반환하도록 코드를 작성

 - 캐시를 발견하지 못하면 fetch(pEvent.request)를 통해 네트워크에 요청

 

* 실행 실습 후 서비스워커 삭제 : 다음실습 준

 


* 서비스 워커의 주요 이벤트 복습하기

 - install : 서비스워커가 설치될 때 실행(앱설치) - 캐시파일 저장

 - activate : 서비스워커 설치 후, 업데이트 역할 - 기존캐시 제거

 - fetch : 서비스워커 설치 후 다음 실행 때 실제 작업할 내용 작성 - 브라우저 서버요청시 오프라인 상태면 캐시파일 조회

 

* 사용하는 브라우저 서비스워커 지원 확인

 - https://mobilehtml5.org/tests/sw 접속 후 새로고

서비스워커 지원하지 않을때 표시되는 메시지라고? 
Service Worker NOT serving files on first loads
Couldn't ask for Service Worker ID.

두번째 하니 아래와 같이 표시된다. 뭐지?


 

미션 코딩! 캐시 변경하고 서비스 워커 다시 등록하기  

 

 

* 03장 실습 결과물을 복사한 후 캐시 제목을 바꾸고 캐시 이미지를 추가해 서비스 워커를 다시 등록

 - 크롬 개발자 도구의 캐시 저장소(Cache Storage)에서 캐시 제목과 추가한 이미지 확인

 > 실습할 때마다 기존의 서비스 워커는 반드시 미리 제거

 - 캐시 제목 뒤에 -v1, -v2..처럼 버전의 번호를 올리면서 테스트

// 캐시 제목과 캐시할 파일 선언
// const sCacheName = 'hello-pwa'; // 캐시 제목 선언
// const aFilesToCache = [         // 캐시할 파일 선언
//     './', './index.html', './manifest.json', './images/hello-pwa.png'
// ];
// // 미션코딩 - 캐시변경하고 서비스워커 다시 등록하기
const sCacheName = 'hello-pwa-v1'; // 캐시 제목 변경 *
const aFilesToCache = [         // 캐시할 파일 선언
    './', './index.html', './manifest.json', './images/hello-pwa.png',
    './images/icons/favicon.ico',               //파비콘 이미지 캐시 추가 *
    './images/icons/android-chrome-192x192.png' //아이콘 이미지 캐시 추가 *
];

* 이전 서비스 워커를 제거한 후 테스트

 - 라이브 서버로 웹 브라우저에서 실행

 - Update on reload' 체크 박스 선택 해제

 > 웹 브라우저 새로 고침에도 서비스 워커 : 신규 ID로 등록되지 않고 그대로 있음

* Status 항목에서 skipWaiting을 선택

 - 캐시 저장소에서 변경된 캐시 제목과 캐시에 추가로 등록된 이미지 확인

 - 앱 재실행 후에도 Status 항목에 skipWaiting 표시가 안되네.. 뭘 놓쳤지..

 

 

02-1 재활용할 수 있는 블록 함수

 - ES6부터 스코프를 고려한 변수 관리기능 강화 및 변수에 함수를 저장하는 함수표현식 추가.

 

선언식(declaration) : 기존 선언방식

 - function 뒤에 함수 이름을 적고 소괄호()안에 필요한 매개변수를 쉼표(,)로 구분해서 작성, 함수가 수행할 명 령을 중괄호 {}로 감싸서 구현

<!DOCTYPE html>
<html>
<head>
    <title>Page Title</title>
<script>
/*
  함수명(매개변수, ...){
  	// 명령
  }
   - 호출부와 함수의 연결(인터페이스) : 매개변수
*/
function fnSayHello(){
	alert("기존 함수사용방식");
    return;
}

</script>
<body>

    <button onclick="fnSayHello()"> 눌러주세요 </button>

</body>
</html>

 - 함수이름 선언 : fnSayHello
 - alert : 자바스크립트 내장함수 : 문자열을 메시지 창에 표시

 - return : 처리결과 응답 (생략가능 : undefined 반환) 

 - 매개변수 : 없을 시 () 로 생략 가능

 - 버튼 클릭시 fnSayHello() 함수 호출 : onclick

 - 버튼제목 : <button> 테그사이의 문자열이 버튼에 표시됨
 > 이벤트 핸들러 : 키보드나 마우스 버튼을 눌러서 이벤트가 발생하면 자바스크립트 코드와 연결시키는 역할

 

표현식(expression) : ES6+ 함수 표현식

 - 함수명 없이 선언한 후에 객체 변수에 저장 : 함수를 호출할 때는 변수명을 이용 (모던 자바스크립트)

/*
  표현식 함수형 변수 선언
*/
const fnMinusNumbers = function(pNum1, pNum2){
    return pNum1 - pNum2;
}

 - fnMinusNumbers() 함수의 함수 표현식 선언 : 변수명 = 함수명

 - 매개변수 2개를 입력받고 처리결과 반환

/*
  [표현식]
  변수 = function(매개변수, ...){
    // 명령
  }
*/
const fnMinusNumbers = function(pNum1, pNum2){
    return pNum1 - pNum2;
}

<button onclick="console.log(fnMinusNumbers(3, 5))">3 - 5 = ?</button>

자바스크립트의 호이스팅

  • 자바스크립트에서 함수 선언식은 호이스팅 (hoisting)이 적용됨
    - 호이스팅 : 코드를 실행하기 전에 내부에서 변수와 함수의 위치를 맨 위로 옮겨 선언
    > 장점 : 변수나 함수를 좀 더 유연하게 사용
    > 단점 : 오류가 생기면 찾기 어렵다
  • 선언식을 사용한 fnSayHello() 함수 / 표현식을 사용한 fnSayHello2() 함수
     - 선언문 보다 호출문을 먼저 작성했을 때 호이스팅 영향
/*
  [호이스팅]
*/
fnSayHello1();
function fnSayHello1(){
    console.log("선언식 함수 호출");
}

fnSayHello2();
const fnSayHello2 = function(){
    console.log("표현식 함수선언 변수 호출");
}

 - 선언식 함수를 정의하면 호이스팅으로 선언하기 전 코드에서 함수를 사용할 수 있음
 - 표현식 함수선언 변수는 호이스팅 대상이 아니기 때문에 선언하기 전 코드에서 변수(함수)를 사용할 경우 오류발생

 

[DoIt!실습] 함수 선언식과 표현식 실습하기

 - 0201. : Doit 실습 - 함수 선언식과 표현식 실습하기

 - \0201\ex02-01\function.html

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>Page Title</title>
</head>
<body>
    <button onclick="console.log(fnSayHello())" id="clickme">눌러주세요!</button>
    <br/>
    <button onclick="alert(fnPlusNumbers(3,5))">3+5 = ?</button>
    <button onclick="console.log(fnMinusNumbers(3,5))">3 - 5 = ?</button>
    <script>
        function fnSayHello(){
            document.querySelector('#clickme').innerHTML = '안녕하세요';
        }
        function fnPlusNumbers(pNum1, pNum2){
            return pNum1 + pNum2;
        }
        const fnMinusNumbers = function (pNum1, pNum2){
            return pNum1 - pNum2;
        }
    </script>
</body>
</html>

 - document.querySelector('#clickme').innerHTML = '안녕하세요';
  > id값이 #clickme 엘리먼트의 내용 설정

 - 덧샘결과 반환 함수의 선언식 표현 : fnSayHello

 - 뺄셈결과 반환 함수의 함수 표현식 : fnMinusNumbers

 

* 실행

* [눌러주세요!] 버튼클릭
 - 안녕하세요 표시문구 변경

* 3+5 버튼 클릭

* 3-5 버튼 클릭

 



02-2 변수 선언

var : 함수 스코프(function scope)만 지원, 블록 스코프(block scope) 지원 안함.

 - 스코프 : 유효범위

 

* 함수 스코프 예시

 - 함수에서 선언한 변수를 함수 밖(전역)에서 사용하면 오류발생

<script>
    fnMyFunction();
    function fnMyFunction(){
        var apple = 5;
        console.log(apple); // 5 출력
    }
    console.log(apple); //오류! Uncaught ReferenceError: apple is not defined
</script>

* 블록 스코프 예시

 - var 키워드는 블록스코프 지원하지 않음 : 블록내부 var 변수는 외부사용 가능

<script>
    var apple = 3;
    {
        var apple = 5;      // var 선언 변수는 블록 스코프가 아니어서 재선언 가능
        console.log(apple); // 5 출력
    }
    console.log(apple);     // 3 대신 5 출력
</script>

 - var 변수 : 전역변수 

 - 블록내 var 변수 : 동일한 이름으로 다른값 할당 (재할당)

 - 블록내에서 재할당한 변수는 블록에만 유효한 것이 아닌 전역변수 값을 변경함
  > var는 함수스코브에서만 유효성이 제한됨

* var 특징

  - 블록스코프 미지원 : 함수외부 선언 변수는 전역변수 역할

  - 같은 이름으로 중복선언 가능 : 기존에 선언한 변수를 덮어씀.

  > 블록으로 명시적인 스코프 적용을 의도하는 실수 등 코드 가독성을 저해하고, 디버그에 어려움 발생.

  : var 대안으로 let, const 사용

 

* let, const 키워드 : 블록 스코프 지원

  - 블록외부에서 사용 불가

  - 중복선언 제한

  > let : 스코프 적용한 변수선언 - 가변(mutable)

  > const : 스코프 적용한 상수선언 - 불변(immutable)

<script>
    {
        let apple = 3;
        console.log(apple);     // 3 출력
        apple = 5;              // let 변수 재할당 가능
        console.log(apple);     // 5 출력
        let apple = 7;          // let 변수 재선언 불가 - Identifier 'apple' has already been declared 

        const car;              // const 선언, 할당 동시 설정 필요
        const carname = "하이브리드카";
        console.log(carname);   // '하이브리드카' 출력
        carname = "디젤카";      // const 재할당 불가 - 불변성

    }
    console.log(apple);     // 블록내 let 변수 참조 불가
    console.log(carname);   // 블록내 const 변수 참조 불가
</script>

* 모던 자바스크립트에서 변수 사용 3원칙

 - const 우선 사용 : 변경대상이 아닌 변수

 - let 차선 사용 : 변경사용 변수

 - var 불가피한 경우 사용 : 전역변수 필요시 최상위 수준에서 사용 

 

* 하나만 더 - console.log() 함수와 템플릿 리터럴로 디버깅

 - 디버깅시 alert() 함수사용으로 브라우저에서 팝업창을 이용하여 결과 값 확인

 - 템플릿 리터럴 : 역따옴표 [`] - 문자열 안에 표현식 적용 가능  > 달러($), 중괄호({}) 를 이용하여 여러줄 사용

 - 디버그 시 브라우저 개발자도구의 콘솔 창 활용

<script>
    let apple = 3;
    const carname = "하이브리드카";
    console.log('사과: '+apple+', 자동차: '+carname);     // 이전 스타일
    console.log(`사과: ${apple}, 자동차: ${carname}`);  // ES6 스타일(템플릿 리터럴)
</script>




02-3 화살표 함수

* ES6 문법에서 추가된 새로운 함수표현
기존 : funtion(){ return ... }
개선 : function, return 키워드 생략, => (fat arrow) 기호로 직관적인 표현

 

* 화살표 함수 예

// 전통 함수 표현식
const fnPlusNumbers = function(pNum1, pNum2){
    return pNum1 + pNum2;
}
// 화살표함수 표현식
const fnPlusNumbers2 = (pNum1, pNum2) => {
    return pNum1 + pNum2;
}
// 화살표함수 표현식 - return 생략 (실행문 하나인 경우 불필요햔 중괄호도 함께 생략)
const fnPlusNumbers3 = (pNum1, pNum2) => pNum1+pNum2;
// 매개변수 1개인 경우 소괄호 생략
const fnPlusNumbers4 = pNum => pNum+1;
// 매개변수 0개인 경우 () 만 표시
const fnPlusNumbers5 = () => '안녕하세요.';

[DoIt!실습] 화살표 함수 실습하기

 - 0202. : Doit 실습 - 화살표 함수 실습하기

 - \0201\ex02-02\arrow_function.html

* 코드

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>arrow_function</title>
</head>
<body>
    <button onclick="
        console.log(fnSayHello());
        console.log(`1+2 = `, fnPlusNubers1(1,2));
        console.log(`2+3 = `, fnPlusNubers2(2,3));
        console.log(`3+4 = `, fnPlusNubers3(3,4));
        console.log(`4+1 = `, fnPlusNubers4(4));
    " id="clickme">화살표 함수 실행!</button>
    <script>
        const fnPlusNubers1 = function(pNum1, pNum2){
            return pNum1 + pNum2;
        }
        const fnPlusNubers2 = (pNum1, pNum2) => {
            return pNum1 + pNum2;
        }
        const fnPlusNubers3 = (pNum1, pNum2) => pNum1 + pNum2;
        const fnPlusNubers4 = (pNum1) => pNum1 + 1;
        const fnSayHello = () => '안녕하세요!';
    </script>
</body>
</html>

 -  버튼을 만들고 onclick 이벤트 핸들러에 각 함수 호츨문 등록.
 > onclick=" ~ "
 - 매개변수를 두 개 입력받아 덧셈 후 반환하는 함수 선언.
 > fnPlusNumbers1;
 - function 키워드를 생략한 화살표 함수 선언.
 > fnPlusNumbers2;

 - 화살표 함수에서 return 키워드 생략. (자동으로 결과값 반환) 한줄이므로 중괄호 {}도 생략.
 > fnPlusNumbers3;
 - 화살표 함수에서 매개변수가 하나일 때는 소괄호 ()도 생략.
 > fnPlusNumbers4;
 - 
화살표 함수에서 매개변수가 없을 때는 반드시 소괄호 ()를 사용.
 > fnSayHello();

 

* 실행결과



02-4 모듈 내보내기와 가져오기

모듈(module) : 코드를 관리하는 가장 작은 단위
 - 코드 관리와 재활용에 용이 :
 소스 복잡 > 변수, 함수 충돌 증가
 - ES6부터는 import, export 문 추가 : 모듈을 이용한 협업 개선
 - 모듈 내보내는 방식 
 > 여러 값을 공유하는 ‘이름으로
(named) 내보내기’

 > 기본값 하나만 공유하는 ‘기본으로(default) 내보내기’ 방식

 

* 이름으로 내보내고 가져오기
 - 소스 파일에 선언된 식별자를 복수로 선택 공유
 > export 키워드 작성 > 공유하고 싶은 식별자를 쉼표로 나열 : 중괄호 {}로 감싸기
 (식별자 : 변수, 상수, 함수, 클래스 등을 선언한 이름)

//외부와 공유할 conHello 상수 와 fnPlusNumbers 함수 선언
const conHello = '안녕하세요';
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

//외부 사용을 위해 내보내기
export {conHello, fnPlusNubers};

 - export 키워드 다음에 작성한 식별자 이름 : 모듈을 사용할 파일에서 import 키워드로 가져올 식 별자 이름과 일
 > {conHello, fnPlusNubers}

- 이름을 다르게 해서 내보내기 : 내보낼 식별자 이름 뒤에 as 키워드를 이용하 새 이름 지정

 > 외부 파일에서 새 이름으로 참조 가능

// js 파일에서 내보낸 식별자를 가져와 conHello, fnPlusNumbers 객체에 저장
import {conHello, fnPlusNubers} from './04-1_ibrary_named.js';
console.log("conHello : ", conHello);
console.log("fnPlusNubers : ", fnPlusNubers(1,2));

// js 파일에서 내보닌 모든 식별자를 가져와 myLibrary 객체에 저장
import * as myLibrary from './04-1_ibrary_named.js';
console.log("myLibrary.conHello : ", myLibrary.conHello);
console.log("myLibrary.fnPlusNubers : ", myLibrary.fnPlusNubers(1,2));

- 내보낸 모듈을 다른 파일에서 가져와 쓰려면 import 키워드를 사용

 > from 키워드 다음에 해당식별자 가 선언된 모듈. 즉 소스 파일의 경로 선언 : './04-1_ibrary_named.js'
- 모든 식별자 호출 : 별표(*) 선언

 > as 키워드와 함께 객체명지정 : as myLibrary

 > 객체에 점(.)을사용해서 식별자를사용 : myLibrary.conHello

 

* 기본으로 내보내고 가져오기

 - 소스 파일에 있는 식별자 중 하나를 대표로 지정
 > export 키워드 다음에 default 키워드를 추가

 - 모듈 하나 당 하나의 함수나 클래스만 공유
 > var, let, const는 사용 불가

/* HOST : 04-4_default.js*/
// 외부와 공유할 함수 : 기본(default) 내보내기는 모듈 하나에 하나의 함수나 클래스 만 가능 (var, let, const 불가)
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

// 기본 모듈 내보내기
export default fnPlusNubers;

/* GUEST */
//외부에서 기본 모듈로 내보내기 후 이름을 변경하여 사용
import fnMyFunction from './04-4_default.js';
console.log("fnMyFunction : ", fnMyFunction(1,2));

 - export default로 내보낸 식별자를 가져올 때 이름 변경가능
 >
library_default.js 소스에서 내보낸 함수 : fnPlusNumbers()
 > 가져올 때 : fnMyFunction() 이름변경

 

[DoIt!실습] 모듈 export, import 실습하기

 - 0203. : Doit 실습 - 화살표 함수 실습하기

* 코드

 - \0201\ex02-03\library_named.js

//외부와 공유할 conHello 상수 와 fnPlusNumbers 함수 선언
const conHello = '안녕하세요';
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

//외부 사용을 위해 내보내기
export {conHello, fnPlusNubers as fnPlusNumbers};

// 간소화 방법
// export const conHello = '안녕하세요!';
// export const fnPlusNumbers = (pNuml, pNum2) => pNuml + pNum2;

 - \0201\ex02-03\library_default.js

// 외부와 공유할 함수 : 기본(default) 내보내기는 모듈 하나에 하나의 함수나 클래스 만 가능 (var, let, const 불가)
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

// 기본 모듈 내보내기
export default fnPlusNubers;

 - \0201\ex02-03\main.js

// js 파일에서 내보낸 식별자를 가져와 conHello, fnPlusNumbers 객체에 저장
import {conHello, fnPlusNumbers} from './library_named.js';
console.log(conHello, "이름으로 내보내기입니다.");
console.log("[fnPlusNubers] 1 + 2 = : ", fnPlusNumbers(1,2));

// js 파일에서 내보닌 모든 식별자를 가져와 myLibrary 객체에 저장 : * 
import * as myLibrary from './library_named.js';
console.log(myLibrary.conHello, "*을 사용한 이름으로 내보내기 입니다.");
console.log("[myLibrary.fnPlusNubers] 3 + 3 = : ", myLibrary.fnPlusNumbers(3,4));

// default export를 이용한 기본 내보내기
import fnMyfunction from './library_default.js';
console.log("안녕하세요! 기본으로 내보내기입니다.");
console.log("[fnMyFunction] 5 + 6 = ", fnMyfunction(5,6));

 - \0201\ex02-03\main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>module-import2</title>
</head>
<body>
    <p>콘솔 창을 열어서 결과를 확인하세요!</p>
    <!-- 모듈 사용 시 type 어트리뷰트값으로 "module"을 지정합니다. -->
    <script type="module" src="main.js"></script>
</body>
</html>

- HTML 문서에서 import, export 문을 사용한 모듈 파일을 가져올 때 : 가져온 파일을 모듈로 인식
 > <script> 엘리먼트의 type 어트리뷰트값을 반드시 "module"로 지정

 > 모듈이 되면 import, export 구문을 사용, 상수 선언은 모듈 스코프로 관리

 > 모듈 파일에 선언된 내용은 외부에서 사용할 수 없고 반드시 그 안에서 만 동작

 



02-5 콜백 함수와 비동기 처리 방식

Promise(ES6에 새롭게 추가) 이해를 위한 중간 개념정리

 - 동기(synchronous) 처리 방식 : 순서대로 실행 - 일렬

 - 비동기(asynchronous) 처리 방식 : 선행작업까지 기다리지 않고 실행 - 병렬


* 동기와 비동기 처리 개념 이해하기

구분 동기 처리 방식  비동기 처리 방식
실행 순서  • 모든 코드가 위에서 아래 순서로 실행   • 코드들이독립적으로실행
실행 대기 • 명령 요청 후 결과 응답시 까지 대기
 - 반환 결과를 계속 기다리므로 시간 지연이 큼
 • 명령을 요청 후 결과와 상관없이 다음작업 실행
 - 요청결과 응답시 별도 응답처리


* 콜백 함수로 비동기 처리 구현하기

 - 보통 함수는 값을 매개변수로 전달받는데
 > 자바스크립트에서 함수는 객체로 취급 - 함수의 매개 변수로 함수 전달 가능

// 콜백함수로 사용되는 함수
function fnFunctionA(pNum){
    return pNum;
}
// 콜백함수를 호출할 함수
function fnFunctionB(pFunc){
    console.log("fnFunctionB param fnFunctionA : "+pFunc(20));
}

fnFunctionB(fnFunctionA); // fnFunctionB 함수에 매개변수로 fnFunctionA 함수 전달

 - 매개변수로 전달된 함수 : 콜백함수 - fnFunctionA

 > 콜백함수는 다른 함수에 독립적으로 실행됨 : 비동기처리 구현시 사용

 - 두번째로 전달받은 fnFunctionA() 함수가 fnFunction() 함수에서 fnCallBack 매개변수에 담겨 실행딜 때 비동기로 실됨.

 

* 단순하게 표현한 콜백함수 구조 : 콜백함수 선언과 정의 함께 작성 > ES6 부터 Promise 방식으로 개

// 매개변수 전달 시 함수 선언과 정의 함께 작성 : 비동기처리의 완료 로직 적용
fnFunctionB("콜박함수실행!", function fnFunctionA(pNumA){
    console.log("pNumA : " + pNumA);
});

// 콜백함수를 호출할 함수
function fnFunctionB(pNumB, fnCallBack){
    fnCallBack(pNumB);
}

 

* 콜백으로 호출한 함수가 실행될때 비동기로 처리되는것이라고?

 - 함수 호출구조로 비동기처리가 된다?

 

* 콜백 비동기 호출 예
 -  비동기 처리 함수 : 독립적으로 실행되고 결과도 별도로 처리하는 함수

//콜백함수 실행
fnMsg(fnHello);

// 콜백함수 : 3 실행 후 실행
function fnMsg(fnCallback){
    console.log("1"); // first
    fnCallback(); // 매개변수로 전달받은 함수실행 : 비동기
    console.log("3"); // second
}

function fnHello(){
    setTimeout(() => console.log("2"), 1000); // third - 2초 후 실행에 따라 지연출력
}

 

[DoIt!실습] 콜백 함수의 비동기 처리 방식으로 상품 배송 서비스 구현하기

 - 0204. : Doit 실습 - 비동기 처리 방식 비스 구현하기

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>callback</title>
</head>
<body>
    <button onclick="
    /*콜백 함수를 순서대로 실행하면 콜백 지옥의 문제점 발생!*/
    fnProductReady(1, 2000, function(pRet){
        console.log(pRet);
        fnProductReady(2, 1000, function(pRet){
            console.log(pRet);
            fnProductReady(3, 500, function(pRet){
                console.log(pRet);
                console.log('가독성이 낮고 유지,보수하기 어려운 콜백 지옥 발생!');
            })
        })
    })
    ">콜백 함수 실행!</button>
    
    <script>
        //콜백 함수 생성
        function fnProductReady(pNum, pTime, fnCallback){
            setTimeout(() => {
                console.log(pNum);
                fnCallback("상품이 성공적으로 배송되었습니다");
            }, pTime); // 타이머로 가상의 네트워크 지연 상황 연출
        }
    </script>
</body>
</html>

- 버튼클릭 : 콜백함수를 매개변수로 갖는 함수를 호출하며 자신 함수를 콜백함수로 전달 (중첩선언)
 > 콜백함수 2초, 1초, 0.5초 소요메서드 호출

 > 지연시간 이후 다음 콜백함수 호출

- 콜백함수 : fnProductReady()

 > 매개변수 3개 : 실행번소, 타이머지연시간, 콜백함수

 > 실행번호, 메시지 표시

- 중첩 선언으로 콜백지옥 문제점 확인

- 타이머를 이용한 시간지연 효과 적용 : setTimeout(function, milliseconds);
 > function : 타이머 종료 후 실행될 함수

 > milliseconds : 타이머 동작시간 (ms - 1초 = 1000ms)

 

* 콜백 함수의 한계와 Promise

 - 콜백함수 : 유지보수, 가독성 저하

 > 콜백지옥 구성 : 중첩 코드 구성에서 발생

 > 반환값 처리 문제 : 콜백함수 종료 후 반환값 처리시점이 분리됨 - 부적응

 - 대안 : Promise



02-6 JSON과 Fetch API

* Fetch API를 이용해 서버에서 JSON 데이 터를 가져올 때 Promise를 사용하면 얼마나 편리한지 확인

 

* JSON 이해하기 - JSON(JavaScript object notation)

 

 - 자바스크립트에서 데이터를 저장하고 교환할 때 사용하는 정형화된 텍스트 형식
 > 대부분의 프로그래밍 언어에서 서버와 브라우저 간에 데이 터를 주고받는 형식으로 많이 사용

 - 시작과끝을중괄호({))로 지정하고, 각항목은 ‘키:값’ 형식으로 묶어서 표현, 각 항목은 콤마(,)로 구분
 >  JSON의 원본값은 텍스트 - 객체로 바꾸는 작업 : JSON.parse()
 > JSON 데이터가 담긴 자바스크립트 객체 - 텍스트로 변환 : JSON.stringify()

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>json</title>
</head>
<body>
    <script>
        // JSON.stringify()와 JSON.parse() 함수 사용예시
        let myObj = {"name":"홍길동", "age":35, "email":"test1@naver.com"};
        
        strJSON = JSON.stringify(myObj);
        console.log(strJSON);
        newObj = JSON.parse(strJSON);
        console.log(newObj);
        
    </script>
</body>
</html>

특정 환경에서만 발생하는 크롬 브라우저 확장프로그램 오류인것 같은데, 해결이 안된다.
 - 오류이후 처리는 정상 진행되니... 일단패스.
Uncaught TypeError: Cannot read properties of undefined (reading 'browserObject')
at webcontent.js:1:266
at webcontent.js:2:463
at webcontent.js:2:467
webcontent.js:1

실행결과

 - 텍스트 형태 출력  : {"name":"홍길동","age":35,"email":"test1@naver.com"}

 - 객체형태 출력 : Object - 확장하면 상세정보 확인 가능

 

* Fetch API 이해하기

 - API에서 제공 : 원격 서버에서 제공하는 데이터의 CRUD(create, read, update, delete) 작업 지원
 > HTTP Request, ResponsePost, Get, Put, Delete 메서드로관리 (셋째마당)
- 테스트 원격 웹 서비스 : JSONPlaceholder 웹사이트 이용 - https://jsonplaceholder.typicode.com/

 (JSON 형태의 더미 데이터 제공 : 포스트, 댓글, 사진 앨범, To-Do 리스트, 사용자 등)

 - fetch() 함수 : 매개변수 path에 주소 전달 - 서버 응답 정보를 Promise 객체로 반환

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>json</title>
</head>
<body>
    <script>
        // fetch 사용예시
        fetch('https://jsonplaceholder.typicode.com/users')
        .then(pResponse => pResponse.json())
        .then(pJSON => console.log(pJSON));
        
    </script>
</body>
</html>

 - jasonplaceholder 웹 사이트에서 테스트로 제공하는 사용자(users) 정보의 첫 번째값 조회

 - 서버에서 결과를 전송하면 Promise 객체에 서버가 응답한 값을 매개변수로 전달받아서 JSON 데이터로 변경한 후 출력

 

 

[DoIt!실습] 원격에서 정보를 Promise로 받기

 - 0205. : Doit 실습 - 원격에서 정보를 Promise로 받기

 > 콜 백 함수보다 Promise를 사용하면 훨씬 직관적이고 간결하다는 것 확인

# 0201/ex02-05/data.json

{
    "items":[
        {"name":"홍길동1", "age":35, "email":"test1@naver.com"},
        {"name":"홍길동2", "age":30, "email":"test2@naver.com"},
        {"name":"홍길동3", "age":45, "email":"test3@naver.com"}
    ]
}

# 0201/ex02-05/promise_getjson.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>promise</title>
</head>
<body>
    <button onclick="
        // JSON 로컬 텍스트 표시
        fetch('./data.json')
        .then(pResponse => pResponse.text())
        .then(pJSON => console.log(pJSON))
        ;
    ">JSON 로컬 읽기</button>

    <button onclick="
        // JSON 원격 텍스트 표시
        fetch('https://cors-anywhere.herokuapp.com/'
         + 'https://jsonplaceholder.typicode.com/posts/1')
        .then(pResponse => pResponse.text())
        .then(pJSON => console.log(pJSON));
    ">JSON 원격 읽기</button>
</body>
</html>

 - fetch() 함수로 로컬에 있는 data.json 파일을 읽어서 Promise 객체로 pResponse 매개변수에 저장
 > JSON값을 텍스트로 변경해 Promise로 반환하는 text() 함수 이용
 - <JSON 원격 읽기> 버튼를 클릭하면 원격(JSONPlaceholder 사이트)에서 제공하는 포스트 목록에서 첫 번째 항목 조회
 > fetch() 함수의 매개변수에 'https://jsonplaceholder.typicode.com/posts/1' 경로를 전달

 

*JSONPlaceholder를 fetch()함수로 바로 접근하면 CORS 오류가 발생
 - CORS(cross origin resource sharing) : ‘교차 줄처 리소스 공유’ - 보안을 위해 같은 도메인의 자료만 접근하도록 허용하는 정책
 > 테스트 목적 대응조치 : CORS 헤더 추가 
 : 접속할 주소 앞에 ‘https://cors-anywhere.herokuapp.com/’ 포함

GET https://cors-anywhere.herokuapp.com/https://jsonplaceholder.typicode.com/posts/1 403 (Forbidden)
 - promise_getjson.html:24 
onclick @ promise_getjson.html:24

See /corsdemo for more info
 - promise_getjson.html:27 

 - 최초 접속시 접속승인 버튼 클릭
 > 콜백 함수를 사용하지 않아도 Promise로 원격 데이터를 읽고 표시

 

 



02-7 Promise와 비동기 처리 방식

* Promise란?

 - 비동기 처리 방식으로 실행된 결과의 성공과실패를관리하는 객체

물건 거래를 예로 한 경우의 수
• 물건을 주는경우 - 약속이행(성공,resolved)
• 물건을 주지 못하는 경우 — 약속 불이행(실패,rejected)
• 물건을주지 못하고 지연된 경우- 약속 이행 지연(대기,pending)

 - Promise : 약속을 생성하는 과정과 최종 결과로 나누어 구성

• 실행 중 결과 기다림 (pending):약속은 아직 이행되거나 거절되지 않았고 지연 상태
 - 요청한 실행의 반환을 계속 대기 :  작성할 코드 없음
• 요청한 실행이 성공함 (resolved):약속을 지키기는 데 문제가 없는 경우
 - 요청 실행 성공한 경우 : 필요한 코드 작성
• 요청한 실행이 실패함 (rejected):약속을 지키는 데 문제가 생겨 거절하는 경우
 - 요청했던 실행이 실패한 경우 : 필요한 코드 작성

 - 약속의 실행 최종 결과 구분

• 약속 지킴 최종 성공(fulfilled):약속이 지켜져서 물건을 성공적으로 받은 경우
 - 코드상에서는 성공적으로 원하는 결과를 반환받은 경우
• 약속 못 지킴 최종 실패(unfulfilled):약속이 거절되어서 물건을 못 받게 되어 그다음 대책 실행
 - 코드상에서는 요청이 실패해서 오류 처리를 해야 하는 경우
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>promise</title>
</head>
<body>
    <script>
        // 가상의 서버 데이터 요청 및 그 결과 랜덤값 반환
        function RequestData(){
            return Math.random() > 0.5;
        }

        // 약속을 생성하는 부분
        const oProductReady = new Promise(function (fnResolve, fnReject){
            //실행 중 결과 기다림(pending)
            let bStatus = RequestData();

            if(bStatus){
                // 요청한 실행이 성공함(resolved)
                fnResolve('상품이 성공적으로 배송되었습니다.');
            }else{
                // 실행 중 결과 기다림(pending)
                fnReject('죄송합니다. 상품이 아직 준비되지 못했습니다.');
            }
        });

        // 약속의 실행 최종 결과
        oProductReady.then(function (pResult){
            // 약속 지킴 최종 성공(fulfilled)
            console.log(pResult);
        }, function (pErrMsg){
            // 약속 못 지킴 최종 실패(unfulfilled)
            console.log(pErrMsg);
        });
    </script>
</body>
</html>

 - 서버요청결과를 고려하여 랜덤함수의 결과로 응답결과를 분리하여 결과 확인
 > Math.random() > 0.5

 - 비동기 처리를 위한 Promise 생성부분 : const oProductReady

 > 상품 준비 요청 결과(RequestData())에 따라 fnResolve()fnReject() 함수 호출

 - Promise 실행결과에 따른 응답결과 처리

 > then() 메서드에서 콜백 함수와 비슷한기능 처리
  정상처리 : 콘솔결과 성공표시 - 첫번째 파라미터로 전달된 함수 실행
  실패처리 : 콘솔결과 실패표시 - 두번째 파라미터로 전달된 함수 실행

 

 

[DoIt!실습] 하나의 Promise 실습하기

 - 0206. : Doit 실습 - 하나의 Promise 실습하기

# 0201/ex02-06/promise_resolve_reject.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Promise</title>
</head>
<body>
    <button onclick="
        // Promise 실행
        console.log('Promise 시작!');
        let bStatus = Math.random() > 0.5;
        fnCreatePromise(bStatus)
        // 비동기 실행으로 결과를 알려 줌
        .then(pResult => console.log(pResult))
        .catch(pErrMsg => console.error(pErrMsg));
        console.log('Promise 종료!');
    ">상품 배송 시작!</button>
    <script>
        // Promise 생성
        function fnCreatePromise(pStatus) {
            return new Promise((fnResolve, fnReject) => {
                // 상품 준비를 확인하는 비동기 함수를 실행했다고 가정함
                setTimeout(() => {
                    // 상품 준비 결과는 랜덤정보 true, false로 가정함
                    if(pStatus) fnResolve('상품이 성공적으로 배송되었습니다.');
                    else fnReject('죄송합니다. 상품이 아직 준비되지 못했습니다.');
                }, 3000);
            });
        }

    </script>
</body>
</html>

 - 외부 네트워크에 접속하진 않지만 비슷한상황을 연출하기 위해 타이머로 시간 지연
 > setTimeout(() => ...)

 - 결과의 성공 여부는 랜덤 함수로 예측할 수 없게 설정
 > let bStatus = Math.random() > 0.5;
 > Promise를 생성하는 fnCreatePromiseQ 함수 호출 때 전달

 - 시나리오 별 예상 응답 - 콘솔 메시지 순서

 > 동기실행 시 예상 시나리오 :   Promise 시작! - [결과] -Promise 종료!

 > 비동기실행 시 예상 시나리오 :  Promise 시작! -Promise 종료! - (3초 후)[결과]

 - Promise를 실행한 후

 > 성공하면 then() 메서드를 호출

 > 실패하면 catch() 메서드를 호출

 - fnCreatePromise() 함수에서 Promise를 생성하고 결과를 응답

 > pStatus 매개변수에 성공 여부를 판단 : (앞으로 일어날)  성공, 실패 별 처리함수 fnResolve()fnReject() 각각 작성


* Promise 여러 개 사용하기

 - Promise 연결 사용 장점

• 콜백 지옥 문제점 해결: 비동기 처리 순서대로 처리 시, (콜백 함수처럼) 중첩 불필요
 - 소스를 간결하고 직관적 으로 작성
 비동기 처리 완료 후 반환값 관리 쉬움 : 성공과 실패 모두
then()catch()에 전달된 함수를 통해 관리

 

[DoIt!실습] 여러 개의 Promise 실습하기

 - 0207. : Doit 실습 - 여러 개의 Promise 실습하기

# 0201/ex02-07/promise_multi.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>promise_multi</title>
</head>
<body>
    <button onclick="
        // Promise로 비동기 함수를 순서대로 실행
        fnProductReady(1, 2000)
        .then((pResult) => {
            console.log(pResult);
            return fnProductReady(2, 1000);
        })
        .then((pResult2) => {
            console.log(pResult2);
            return fnProductReady(3,500);
        })
        .then((pResult3) => console.log(pResult3));
    ">Promies : 상품배송시작!</button>
    
    <script>
        function fnProductReady(pNum, pTime){
            return new Promise((fnResolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    fnResolve('상품이 성공적으로 배송되었습니다.');
                }, pTime);
            });
        }
    </script>
</body>
</html>

 - fnProductReady()는 가상으로 상품을 준비하는 비동기 처리 함수

 > 처리결과를 동기화 하여 동일한 함수를 2번 더 호출하며 3번의 비동기 호출을 진행 - 정상처리 시 then 처리

 - 버튼 클릭 시,  비동기 처리가 각각 2초, 1초, 0.5초로 지연되지만 1 > 2 > 3의 실행 순서 보장

* 비동기 실행의 Promise 결과가 (시간지연과 함께) 1 > 2 > 3 순서대로 콘솔 창에 표시
 - 코드보고 설명이 가능할 만큼 이해해보자. (78p)



02-8 await 연산자와 async 비동기 함수

* Promise 한계 : 비동기 처 리를 위해 then() 메서드 중첩 사용

 - ES8부터는await 연산자와async 함수 사용

 

* await 연산자 : 결과가 나올때 까지 기다리다.
 - await 연산자의 오른쪽 항을 동기로 처리

 >  Promise를 반환하는 함수를 대상으로 await 적용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>await</title>
</head>
<body>
    <script>
        // Promise 비동기 기능 동기처리
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve("상품이 성공적으로 배송되었습니다.");
                }, pTime);
            });
        }
        
        // strRet = await fnProductReady(1, 2000);
        strRet = fnProductReady(1, 2000);
        console.log(strRet);
    </script>
    
</body>
</html>
* 예제 코드 실행결과 오류발생 - async await 사용 방법에 이유가 있을듯...
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules (at 08-1_await.html:20:18)
 - 08-1_await.html:20

* await 연산자 제거시 정상동작

 - 다음 예제의 async 구조가 되어야 정상 동작

* await만 사용하면 결과가 나오지 않을 때 무한루프 

 - 비동기 방식으로 처리하는 밍령이 있는함수는 반드시 async를 실행


* async 함수

 - 일반 함수를 선언할 때 앞에 async를 붙여서 비동기 처리 방식으로 선언

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async</title>
</head>
<body>
    <script>
        // Promise 비동기 기능 동기처리
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve("상품이 성공적으로 배송되었습니다.");
                }, pTime);
            });
        }
        async function fnDoAsyncFunc(){
            console.log(await fnProductReady(1, 2000)); // 2초 지연
            console.log(await fnProductReady(2, 1000)); // 1초 지연
            console.log(await fnProductReady(3, 500));  // 0.5초 지연
        }
        fnDoAsyncFunc();
    </script>
</body>
</html>

 - async 함수 사용방법 : 일반함수 사용과 동일
 > fnDoAsyncFunc();

 


[DoIt!실습] await 연산자와 async 비동기 함수 실습하기
- 0208. : Doit 실습 - await 연산자와 async 비동기 함수 실습하기
# 0201/ex02-06/promise_resolve_reject.html

* await 연산자와 async 비동기 함수를 사용하면 Promise를를 좀 더 유연하게 활용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async_await</title>
</head>
<body>
    <!-- async 함수 실행 -->
    <button onclick="fnDoAsyncFunc()">async, await : 상품 배송 시작!</button>

    <script>
        // await로 비동기 함수를 순서대로 실행
        // Promise 보다 소스가 간결하고 가동성 향상
        async function fnDoAsyncFunc(){
            console.log(await fnProductReady(1, 2000)); // 2초 지연
            console.log(await fnProductReady(2, 1000)); // 1초 지연
            console.log(await fnProductReady(3, 500)); // 0.5초 지연
        }
        //Promise로 비동기 함수 생성
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve('상품이 성공적으로 배송되었습니다.');
                }, pTime);
            });
        }
    </script>
</body>
</html>

- fnProductReady() 함수 앞에 await 연산자 추가

 > async 함수 안에서 await 인산자가 사용된 함수 호출문이 하나씩 실행 
 > 완료될 때까지 다음 함수 호출하지 않고 대기
 > 처리순서 보장 :  1 > 2 >3 
- 무한 루프에 빠지지 않도록

 > async로 함수 전체를 감싸서 비동기로 처리

- fnProductReady() 함수 처리 시, 상품을 준비하는 동안 시간이 지 연되는 연출을 위해 

 > 매개변수로 번호, 지연시간 정보를 받아서 Promise를 생성하여 반환

 



미션 코딩! 입력된 숫자의 범주 판별하기

사용자가 숫자를 입력했을 때 메시지를 표시하는 프로그램 

 - 1~100 범위에 속하면 "성공적으로 입력하셨습니다!”라는 메시지 표시

 - 그렇지 않으면 "입력 범위가 맞지 않습니다!”라는 메시지 표시

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ex02-mission</title>
</head>
<body>
    <h1>1부터 100 범위 안의 숫자를 입력하세요.</h1>
    <input type="text" id="comIn" value="" />
    <button onclick="fnMeasure()">확인</button>
    <p>입력 결과 : </p>
    <textarea id="comOutPut" style="width:200px"></textarea>
    
    <script>
        function fnMeasure(){
            let iNumber, strResult;
            
            //입력한 숫자를 가져옴
            iNumber = document.querySelector("#comIn").value;

            //1부터 100까지 범위인지 확인
            if(iNumber < 1 || iNumber > 100) strResult = "입력 범위가 맞지 앖습니다.";
            else strResult = "성공적으로 입력하였습니다.";
            document.querySelector("#comOutPut").innerHTML = strResult;

        }
    </script>
</body>
</html>

 

 

 


* github에 작성한 실습파일 패키지경로 수정

 - 0104 > 0101/ex01-04

 - 0201 > 0102

01-1 프로그레시브 웹앱이 뭐예요?

 

PWA : progressive web app

 

네이티브앱 : SDK로 개발(안드로이드 스튜디오 : 자바 / 엑스코드 : 오브젝트C, 스위프트)
 - 운영체제 별 서비스 개발 : 안드로이드, IOS

 - 배포 : 앱스토어(애플), 플레이 스토어(구글)

 - 사용 : 스토어에서 다운로드하여 설치 (설치후 알림등의 다양한 기능 활용)

 > 네이티브앱 장단점 비교표

 

모바일 웹앱 : 모바일 베이스의 네이티브 앱

 - 웹 영역은 HTML5, CSS3, Javascript로 구현

 - 웹 영역은 스토어 배포 없이 서버의 컨텐츠 교체 만으로 최신기능 적용

 - 인터넷 속도 영향, 네이티브앱에 비해 제한된 기능

 > 모바일 웹앱 장단점 비교표

 

하이브리드 앱 : 네이티브앱과 모바일 웹앱의 장단점 활용 

 - 컨텐츠를 웹앱으로 제작 후 네이티브앱으로 변환하여 배포
 > 웹앱 방식의 개발, 네이트브 앱 방식의 배포
 - 제한적인 네이티브 앱 기능 사용
 - 크로스 플랫폼(아파치 코르도바 - 오픈소스)을 이용한 운영체제 별 네이트앱 배포

 > 하이브리드 앱 장단점 비교표

 

프로그래시브 웹(PWA) : 웹의 장점을 유지하며 네이티브 앱의 장점 활용 ? 하이브리드?
 - 하이브리드는 네이티브로 웹앱 컨텐츠를 패킹하고, 네이티브로 HW 기능을 구현하는 서비스

 - PWA는 네이티브가 아닌 API로 네이티브가 제공하는 HW 기능을 구현하는 서비스
 > 프로그래시브 웹앱 장단점 비교표 


01-2 프로그레시브 웹앱을 대표하는 6가지 핵심 기술

 - 필수 : 서비스워커, 웹앱 매니페스트, HTTPS
 - 확장 : 푸시알림, 홈화면 추가, 웹API

 

1. 서비스워커
 - 웹브라우저 내부에서 웹페이지와 독립적으로 백그라운드 실행
 - 브라우저와 서버 사이에서 상태 모니터링, 푸시알림 지원

 - 오프라인 동작 (인터넷 연결상태와 독립된 서비스 제공)

 

2. 웹앱 매니페스트
 - 앱 소개정보(메타데이터) 제공 (JSON) : manifest.json
 - 매니페스트 : 앱에서 사용하던 기능 - 브라우저에 정보제공

 

3. HTTPS (hypertext fransfer protocol over secure soket layer)
 - 보안을 강화한 웹 통신 규약 : 네트워크 영역에서 통신정보가 노출되어도 보안유지
  (전자상거래 등 보안이 중요한 서비스에 적합)
 > 서비스워커를 이용한 PWA 배포에 필수
 > PWA 성능평가 프로그램(라이트하우스 - lighthouse)에 인증받기위한 의무요소
 > 홈화면 추가 기능은 HTTPS에서만 지원

 

4. 푸시알림
 - 사용자에 알림정보 제공
 > PWA 푸시알림 동의 시 : 사이트 이탈 사용자, PWA가 종료된 백그라운드 상태에도 알림 가능

 

5. 홈화면 추가(add to home screen - 모바일) - 옴니박스(omnibox - 데스크톱) : 설치 (즐겨찾기, 바로가기 아님)

 - 웹 브라우저 사용 시 PWA 설치 안내
 > 운영체제에서 앱으로 인식
 - 홈화면 추가 제안 조건 :
 > HTTPS 접속 : PWA 호스팅 의무요소

 > 매니페스트 등록 : short_name, name, icons(192px X 512px), start_url, display( : fullscreen || standalone || minimal-ui)
 > 서비스 워커 설치 : 브라우저에 서비스워커 설치 의무

 > PWA 설치여부 : 해당 PWA 서비스가 이전에 설치되지 않은 상태
 - 설치된 아이콘은 네이티브 앱과 동일함

 

6. 웹 API

 - javascript api 사용 :  웹사이트, 웹앱, PWA 사용 (네이티브 기능을 지원하기 시작 : 위치정보, 카메라 등)

 

* 스타벅스의 PWA

 - 인터넷 접속 제한환경 극복 : 오프라인 지원

 - 멀티플렛폼 범용 POS(point of sale) 시스템 구축

 - 가볍고 빠른 반응속도

 

* PWA 사용자경험

 - 온라인, 오프라인을 아우르는 신뢰성

 - 네이티브 앱에 비해 쉬운 설치 지원
 - HTTPS를 의무 적용한 보안성
 - 알림을 통한 구독자 관리
 - 멀티 플랫폼 지원

 - 검색노출에 따른 확장성

 - 최신 서비스 제공이 가능 신속성

 - 네이티브 앱과 같이 HW 기능도 사용 가능

 - 네이티브 앱 대비 빠른 배포, 실행, 반응속도


01-3 비주얼 스튜디오 코드 설치하기

 

* 회사 보안 이슈로 VsCode 사용 불가

 - ecilpse로 대체해 보자.
 > 라이브서버 기능은 어떻게 대체하지... 

 

회사에서도 함께 진행했으면 하여 eclipse에서 live server를 실행해볼까 싶어 찾아봤지만,
관련 기능을 제공하는 플러그인이 없는 듯 하다.
eclipse 버전차이로 webclipse는 지원하지 않는 듯 하고, Tern Eclipse 로 대용하던게 있던것 같은데, javascirpt 관련 기능을 목적으로 쓰인 것이었던지...  codemix는 또 뭐냐... 어지럽다. 일단 그냥 집에서 vsCode로 해보자.
보안팀을 졸라볼까 ㅋ

01-4 '안녕하세요' 예제 만들기

 

index.html 파일만들고

코드생성기능으로 html 5 템플릿 코드를 생성한 뒤

 

언어 설정과 셈플텍스트 입력해주고

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>안녕하세요!</h1>
</body>
</html>

라이브서버를 실행해주면

엑세스허용 메시지를 확인하는 것으로 

크롬에 작성한 화면이 나온다.

디버그 모드에서 

디바이스 툴바 토글버튼으로 웹에서 모바일 모드로 전환하고

 

 

디바이스 목록에서 아이폰 6/7/8을 선택해 주면

show device frame 속성 선택시 프레임이 표시된다.

vscode의 상태 표시줄에 port:5500 영역을 클릭하면,

live server가 종료되면서 Go Live 버튼으로 변경된다.

다시 Go Live 버튼을 클릭하면 live server가 시작된다.

 

eclipse에서 live server 시도하다가 시간만 보냈.. ㅋ
어찌어찌하여 1장은 봤는데, 생각보다 시간이 좀 걸리네... 어쩌지...

 

 

 

AS : code-design.web.app@gmail.com / https://code-design.web.app/

* Do it! 스터디룸 카페 : https://cafe.naver.com/doitstudyroom

* Do it! 공부단 정보 :  https://cafe.naver.com/doitstudyroom/6325

 - 신청 : https://cafe.naver.com/doitstudyroom/43619

 

[Do it! 프로그레시브 웹앱 만들기] 공부단 신청합니다.

Do it! 프로그레시브 웹앱 만들기반응형 웹 개발부터 하이브리드 앱 배포까지 PWA 완전 정복! https://search.shopping.naver.com/book/cat...

cafe.naver.com

 

+ Recent posts