본문 바로가기
카테고리 없음

05 프로그레시브 웹앱

by 살길바라냐 2021. 1. 29.
반응형

05 뷰 고급 기능 익히기

 

- computed: html 엘리먼트 값이 어떻게 변경되는 살펴보면서
필요한 연산작업을 도와줌

- methods: 뷰 인스턴스를 포함해 사용하는 함수를 말한다.
이벤트 핸들러를 사용해 마우스 클릭과 같은 이벤트 발생시
실행되는 로직이 많이 사용한다.

- 컴포넌트 html 엘리먼트 만들기: 기본 엘리먼트 외에 자신만의
엘리먼트를 만들어 쓰는 모듈을 말함 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <style>
        .fruit-style {
            border: 1px solid #ccc;
            background-color: white;
            padding-left:1em;
        }
    </style>
</head>
<body>
    <div id="main">
        <h1>{{ sTitle }}</h1>
<favorite-fruits></favorite-fruits>
<favorite-fruits></favorite-fruits>
        </div>     
</body>
<script>
    Vue.component('favorite-fruits', {
        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>

 

- props: 컴포넌트에서 전달되는 속성값을 말하며 문자열이나 객체의
배열 형식으로 되어 있음 

- 상탯값 관리와 Vuex: 

state: 공유한 상태값 데이터의 정의
mutations: setters의 의미로 이해, 외부에서 동기 방식으로 저장할때 사용
getters: state의 데이터값을 외부에서 읽어 올 때 사용
actions: 외부의 api 실행 같은 비동기 실행을 관리할 때 사용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="https://unpkg.com/vuex"></script>
    </head>
    <body>
        <div id="app">
            <h1> 안녕하세요! </h1>
            <com-counter msg="카운터1"></com-counter>
            <com-counter msg="카운터2"></com-counter>
        </div>
        <script>
            const store = new Vuex.Store({
                state:{
                    count: 0
                },

                mutations: {
                    fnIncData: function (state) {
                        return state.count++
                    },

                    fnDecData: state => state.count--
                },
                getters: {
                    fnGetData(state) {
                        return state.count;
                    },
                },
                actions: {
                    async fnDecData({
                        commit
                    }, state) {
                        const result = await api.fnDecrement();
                        if(result == true) commit('fnDecData')
                    }
                }
            })
            const api = {
                fnDecrement() {
                    return new Promise((resolve)=> {
                        setTimeout(() => {
                            resolve(true);
                        }, 1000);
                    });
                },
            };

            Vue.component('com-counter', {
                props: ['msg'],
                template:`
                 <div>
                 <h2>{{ msg }}</h2>
                 <p>카운터: {{ fnGetCount }} </p>
                 <button @click="fnIncCount">+1 증가</button>
                 <button @click="fnDecCount">-1 감소(원격 API 실행)</button>
                 <hr>
                 </div>`,
                 computed: {
                     fnGetCount() {
                         return store.getters.fnGetData;
                     }
                 },
                 methods: {
                     fnIncCount() {
                         store.commit('fnIncData')
                     },
                     fnDecCount() {
                         store.dispatch('fnDecData')
                     }
                 }
            })
            var gApp = new Vue({
                el: '#app',
                store
            })
        </script>
    </body>
</html>

 

내비게이션과 라우터

라우터: 페이지끼리 이동할수 있는 기능

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
  <div id="app">
    <h1>안녕</h1>
    <router-view></router-view>
    <hr>
    <p>라우터 사용:
      <router-link to ="/main">메인 페이지 이동</router-link>
      <router-link to ="/sub">메인 페이지 이동</router-link>
    </p>
  </div>
  <script>
    const tmMain = {
      template: '<h2> 메인 페이지 입니다.</h2>'
    }
    const tmSub = {
      template: '<h2> 서브페이지 입니다 </h2>'
    }

    const rtRoutes = [{
      path: '/main',
      component: tmMain
    },
    {
      path: '/sub',
      component: tmSub
    }]

    const router = new VueRouter({
      routes: rtRoutes
    })

    var gApp = new Vue({
      el: '#app',
      router
    })
  </script>
</body>
</html>

 

프로젝트 만들기

// App.vue
<template>
  <div id="app">
    <h1>안녕</h1>
    <router-view></router-view>
    <hr>
    <p>라우터 사용:
      <router-link to ="/main">메인 페이지 이동</router-link>
      <router-link to ="/sub">서브 페이지 이동</router-link>
    </p>
   
    </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

// main_page.vue
<template lang="html">
<div>
  <h2>메인 페이지</h2>
  <button @click="fnSubPage">서브페이지 이동</button>
  </div>
</template>

<script>
export default {
  methods: {
    fnSubPage() {
      this.$router.push('./sub')
    }
  }
}
</script>

// sub_page.vue

<template lang="html">
<div>
  <h2>서브 페이지</h2>
  <button @click="fnMainPage">메인페이지 이동</button>
  </div>
</template>

<script>
export default {
  methods: {
    fnMainPage() {
      this.$router.push('./main')
    }
  }
}
</script>

06 뷰티파이 기초 

 

vuetify: 뷰 자바스크립트 프레임워크에 멀티리얼 디자인을
사용할 수 있는 컴포넌트 프레임워크

특징
- 구글 머티리얼 스펙 지원
- 80개 이상의 시맨틱 머터리얼 디자인 컴포넌트
- 빠른속도
- 쉬운 학습

엡바 영역: v-app-bar 
본문 영역: v-content
여백 자동 설정: v-container
바닥글 영역: v-footer

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, minimal-ui">
    <link href="https://fonts.googleapis.com/css?fmaily=Roboto:100,300,400,500,700,900|Material+icons" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font3.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
    </head>
    <body>
       <div id="app">
           <v-app>
           <v-app-bar app>
               <v-app-bar-nav-icon></v-app-bar-nav-icon>
               <v-toolbar-title>header입니다.</v-toolbar-title>
           </v-app-bar>
           <v-content>
                안녕하세요
               <v-container>Contents입니다.</v-container>
           </v-content>
           <v-footer>
               <div>Footer입니다</div>
           </v-footer>
           </v-app>
       </div>

       <script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
       <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
       <script>
           new Vue({
               el: '#app',
               vuetify: new Vuetify()
           })
       </script>
    </body>
</html>


앱바 스타일:

v-app-bar 엘리먼트 사용
- 색상 : (
primary:파란색,
secondary:짙은 회색,
accent: 콘플라워 블루,
error: 빨간색,
info:바다색,
success:초록색,
warning:노란색 
)

dark 속성을 지정하면 글자색을 흰색으로
바꾼 후 테마와 글자의 명도를 자동 조정

fixed 속성 스크롤에 영향받지 않고 앱바의 위치를 고정

앱바 메뉴 아이콘: 앱바 영역이 지정되면 그 안에 메뉴 아이콘
제목 등을 넣을 수 가 있음
v-app-bar-nav-icon,
제목은 v-toolbar-title 

앱바 정렬 및 아이콘: 

앱바의 메뉴 아이콘과 텍스트를 오른쪽 정렬로 넣고 싶다면 
v-spacer 엘리먼트 하나넣어 구분

구글 제공하는 아이콘을 사용하고 싶다면 v-btn 엘리먼트 
버튼을 먼저 넣고 아이콘의 공식 이름을 지정

 

본문영역과 자동 여백:

v-content 단독으로 쓰이면 사용할수 있는 모든 영역을 본문으로 잡음
v-container 안에 있는 모든 엘리먼트를 대상으로 화면크기에 맞는 적절한
여백을 자동으로 부여함

항상 v-content를 먼저사용하고 그다음에 v-container를 레이아웃에 
맞춰서 사용한다.

서체 크기와 종류 설정:

타이포그래피 스타일은 display, headline, title, subheading, body, caption

엘리먼트 여백:

m 바깥쪽 여백
p 안쪽 여백
(t top, b bottom, l left, r right, x left right,  y top bottom)

바닥글 스타일:

푸터 v-footer 엘리먼트를 사용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, minimal-ui">
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@3.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.2.x/dist/vuetify.min.css" rel="stylesheet">
    </head>
    <body>
       <div id="app">
           <v-app>
          <v-app-bar app color="primary" dark fixed>
              <v-app-bar-nav-icon></v-app-bar-nav-icon>
              <v-toolbar-title>마스터 페이지</v-toolbar-title>
              <v-spacer></v-spacer>
              <v-btn icon> 
                   <v-icon>mdi-dots-vertical</v-icon>
              </v-btn>
          </v-app-bar>
          <v-content>
          <v-content>
              <h1 class="display-1 my-5">안녕하세요</h1>
              <h1 class="body-2 my-5">마스터 페이지</h1>
              <v-divider></v-divider>
              <h1 class="display-3 my-4">안녕하세요</h1>
              <p class="body-1 my-4">마스터 페이지</p> 
          </v-content>
        </v-content>
        <v-footer color="secondary" dark fixed>
            <div class="mx-auto">copylight &copy;</div>
        </v-footer>
       </div>
       <script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
       <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
       <script>
           new Vue({
               el: '#app',
               vuetify: new Vuetify()
           })
       </script>
    </body>
</html>

 

 

 

 

728x90