간만에 windows 11에 레드마인을 설치했다. 

 

bitnami redmine을 설치하는데, OS별 설치파일 다운로드 하는곳을 못찾아서 

https://bitnami.com/stack/redmine/virtual-machine

 

Redmine Virtual Machines

Bitnami VMs optimized for VMware Cloud on AWS and VMware Cloud Director are available through the VMware Marketplace. VMware Marketplace

bitnami.com

레드마인 커뮤니티에서 낮은버전을 찾아 설치했다.

http://www.redmine.or.kr/projects/community/wiki/%EB%A0%88%EB%93%9C%EB%A7%88%EC%9D%B8_%EC%84%A4%EC%B9%98(bitnami) 

 

레드마인 설치(Bitnami) - REDMINE 커뮤니티 - Redmine 커뮤니티

 

www.redmine.or.kr

 

bitnami-redmine-4.2.4-0-windows-x64-installer.exe

 

설치야 특별할게 없어서 잘 진행했는데, 

서버 포트와 db 포트를 변경하고 싶었다. 

 

간단하게 인터넷을 찾아보고 변경을 했는데, db 포트를 변경해도 안바뀌고 

dbeaver에서 변경한 포트로 접속이 안됐다.

변경을 시도하다가 이상한 에러로그때문에 잠깐 삽질을 했었지만..

더보기

[Thu Aug 31 21:58:33.018393 2023] [ssl:warn] [pid 19064:tid 444] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Aug 31 21:58:33.068371 2023] [ssl:warn] [pid 19064:tid 444] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Aug 31 21:58:33.086154 2023] [mpm_winnt:notice] [pid 19064:tid 444] AH00455: Apache/2.4.52 (Win64) OpenSSL/1.1.1m PHP/7.4.28 configured -- resuming normal operations
[Thu Aug 31 21:58:33.086154 2023] [mpm_winnt:notice] [pid 19064:tid 444] AH00456: Apache Lounge VC15 Server built: Dec 23 2021 11:00:40
[Thu Aug 31 21:58:33.086154 2023] [core:notice] [pid 19064:tid 444] AH00094: Command line: 'D:\\jkSpace\\redmine\\redmine-4.2.4-0\\apache2\\bin\\httpd.exe -d D:/jkSpace/redmine/redmine-4.2.4-0/apache2 -f D:\\jkSpace\\redmine\\redmine-4.2.4-0\\apache2\\conf\\httpd.conf'
[Thu Aug 31 21:58:33.091358 2023] [mpm_winnt:notice] [pid 19064:tid 444] AH00418: Parent: Created child process 17280

 

결국 설정파일 중 관련 내용을 들춰보다 변경에 성공하여 남겨둔다.

 

 

(...)\redmine-4.2.4-0\apache2\conf\httpd.conf
Listen 8000 … ServerName localhost:8000
(...)\redmine-4.2.4-0\apache2\conf\bitnami\bitnami.conf
<IfVersion < 2.3 > NameVirtualHost *:8000 NameVirtualHost *:443 </IfVersion> <VirtualHost default:8000>
(...)\redmine-4.2.4-0\apps\redmine\htdocs\config\database.yml
port: 3366
(...)\redmine-4.2.4-0\mariadb\my.ini
[mysqladmin] user=root port=3366 … datadir="D:/jkSpace/redmine/redmine-4.2.4-0/mariadb/data" port=3366
(...)\redmine-4.2.4-0\apps\redmine\conf\httpd-vhosts.conf
<VirtualHost *:8000>
(...)\redmine-4.2.4-0\apps\redmine\htdocs\config\configuration.yml
git 관련 명령 수정

 

'install > redmine' 카테고리의 다른 글

bitnami redmine 설치  (2) 2017.03.05

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>

 


 

+ Recent posts