SSAFY/Django

[JS] Vue 기본

황성안 2021. 5. 8. 21:55
728x90

Vue.js

프론트 엔드

  • HTML, CSS , JavaScript
  • Vue.js, React(facebook), Angular(google)

 

Vue.js

  • 사용자 인터페이스를 만들기 위한 프로그레시브 프레임워크
  • 현대적인 tool과 다양한 라비러리를 통해 SPA(Single page Aplication)를 완벽하게 지원

 

Evan You (2014)

  • Angular 개발자 출신
  • 학사 미술, 미술사 전공/ 석사 디자인 & 테크놀로지 전공
  • 구글 Angular 보다 더 가볍고, 간편하게 사용할 수 있는 프레임워크를 만들기 위해 개발

 

 

SPA

  • 단일 페이지 애플리케이션

  • 현재 페이지를 동적으로 작성, 사용자와 소통하는 웹 애플리케이션

  • 단일 페이지 구성, 처음 페이지만 받아오고 (HTML) 동적으로 DOM을 구성

    • 새로고침 X
    • 사용자 경험(UX)을 향상
    • 트래픽 감소, 속도, 사용성, 반응성
  • 동작원리 일부가 CSR을 따름

 

등장 배경

  • 모바일 최적화에 대한 필요성

 

CSR (Client side Rendering)

  • 최초 요청 시 서버에서 빈 문서를 응답 후 클라이언트에서 데이터를 요청해서 데이터를 받아 DOM을 렌더링하는 방식
  • SSR보다 초기 전송되는 페이지 속도는 빠르지만, 서비스에서 필요한 데이터 클라이언트(브라우저)에서 추가로 요청하여 재구성해야기때문에 페이지 완료시점은 SSR보다 느림
  • SPA가 사용하는 렌더링 방식

 

CSR단점

Server > HTML > JS

Vue가 JS를 다 실행해야하고 이 과정이 다끝나야 페이지를 띄움

// 빈페이지를 받아온다. JS에서 전부 다운받아 실행시켜서 완료해야지 사용자가 사용가능하다.

 

장점

서버와 클라이언트 간의 트래픽 감소

  • 웹 애플리케이션에 필요한 모든 정적 리소스를 최초에 한번 다운로드

사용자 경험 향상

  • 전체 페이지를 다시 렌더링하지 않고 변경되는 부분만을 갱신

 

단점

  • SEO(검색엔진 최적화) 문제가 발생할 수 있음

    • 구글 엔진 , naver 등 검색결과 최상단에 올리기가 힘들다. (단, 강제하는 방법이있음)

SSR(반대되는 개념 Server side)

  • 서버에서 사용자에게 보여줄 page를 미리 모두 구성해서 사용자에게 페이지를 보여줌

Server > 모두완료시킴 HTML > 보여줌 ( 매번 HTML을 받아야해서 느림)

장점

  • 초기 로딩 속도가 빠르기 때문에 사용자가 컨텐츠를 빨리 볼 수 있음
  • SEO(검색엔진 최적화)가 가능

단점

  • 모든 요청에 새로고침이 되기 때문에 사용자 경험이 떨어짐

    • 상대적으로 요청 횟수가 많아져 서버 부담이 커짐

 

 

SEO

  • search engine Optimization(검색 엔진 최적화)

  • 웹 페이지 검색엔진이 자료를 수집하고 순위를 메기는 방식에 맞게

  • 웹페이지를 구성해서 검색 결과의 상위에 노출될 수 있도록 하는 작업

  • 인터넷 마케팅 방법중 하나

  • 구글 등장이후 검색 엔진들이 컨텐츠의 신뢰도를 파악하는 기초 지표로 사용됨

    • 다른 웹사이트에서 얼마나 이용됐나
    • 얼마나 제목이 ?

 

SEO 문제 대응

Vue.js 또는 React 등의 SPA 프레임워크는 SSR을 지원하는 SEO 대응 기술이 존제

 

Vue.js 는 왜 사용해야 할까

  • 페이지 규모 계속 커져, 데이터 늘어나고, 사용자랑 상 호작용 많이 이뤄짐
  • Vanilla JS만으로 관리하기가 어렵다.

 

 

 

Django & Vue.js 코드 작성 순서

Django

  • url > view > temlplate

 

Vue.js

  • Data 로직 작성 > DOM작성

 

Vue.js

(https://kr.vuejs.org/v2/guide/index.html)

여기에 다있습니다.

# 개발버전 
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!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>Vue Quick Start</title>
</head>
<body>
  <!-- 2. 선언적 렌더링 -->
  <h2>선언적 렌더링</h2>
  <div id="app">
    <p>{{ message }}</p>
    <p>{{ message }}</p>
    <p>{{ message }}</p>

  </div>
  <!-- 3. 엘리멘트 속성 바인딩 , 데이터 바인딩 -->
  <h2>Element 속성 바인딩</h2>
  <div id="app-2">
    <span v-bind:title="message">
      내 위에 잠시 마우스를 올리면 동적으로 바인딩 된 title을 볼 수 있습니다!
    </span>
  </div>
  <!-- 4. 조건 v-if="들어갈조건"-->
  <h2>조건</h2>
  <div id="app-3">
    <p v-if="isVisible">이제 나를 볼 수 있어요</p>
  </div>
  <!-- 5. 반복 -->
  <h2>반복</h2>
  <div id="app-4">
    <ol>
      <li v-for="todo in todos">
        {{ todo.text }}
      </li>
    </ol>
  </div>
  <!-- 6. 사용자 입력 핸들링 -->
  <h2>사용자 입력 핸들링</h2>
  <div id="app-5">
    <p>{{ message }}</p>
    <button v-on:click="reverseMessage">메시지 뒤집기</button>
  </div>
  <!-- 1. Vue CDN -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>


  <script>
    // const pList = document.querySelectorAll('p')
    // pList.forEach(p => {

    //   p.innerText = '새로운 메세지'
    // })


    // 2. 선언적 렌더링
    var app = new Vue({
      el: '#app',
      data: {
        message: '안녕하세요 Vue!'
      }
    })
    // 3. 엘리먼트 속성 바인딩 , 데이터 바인딩
    var app2 = new Vue({
      el: '#app-2',
      data: {
        message: '너모재밌다'
      }
    })
    // 4. 조건
    var app3 = new Vue({
      el: '#app-3',
      data: {
        isVisible: true
      }
    })
    // 5. 반복
    var app4 = new Vue({
      el: '#app-4',
      data: {
        todos: [
          { text: 'JavaScript 배우기' },
          { text: 'Vue 배우기' },
          { text: '무언가 멋진 것을 만들기' }
        ]
      }
    })
    // 6. 사용자 입력 핸들링
    var app5 = new Vue({
      el: '#app-5',
      data: {
        message: '안녕하세요! Vue.js!'
      },
      methods: {
        reverseMessage: function () {
          this.message = this.message.split('').reverse().join('')
        }
      }
    })
  </script>
</body>
</html>

 

 

Vue instance

https://kr.vuejs.org/v2/guide/index.html

  • 하나의 Vue 인스탠스는 Vue 컴포넌트이다.

    • Vue Instance === Vue Component
  •  

 

Options/DOM – ‘el’

  • Vue 인스턴스의 데이터 객체
  • Vue 앱의 데이터를 정의하는 곳
  • v-bind, v-on과 같은 디렉티브에서 사용가능

 

 

Options/Data – ‘data’

  • Vue 인스턴스에 추가할 메서드
  • Vue template에서 interpolation을 통해 접근 가능
  • v-on과 같은 디렉티브에서도 사용 가능 •
  • Vue 객체 내 다른 함수에서 this 키워드를 통해 접근 가

 

 

this keyword in vue.js(중요)

  • vue 인스턴스 자체를 가리킴(자기자신 객체를 가르침)

 

 

Template Syntax

  • 렌더링 된 DOM을 기본 Vue 인스턴스의 데이터에 선언적으로 바인딩 할 수 있는 HTML 기반 템플릿 구문을 사용

    1. Interpolation
    2. Directiv

 

 

v-text

  • 엘리먼트의 textContent를 업데이트
  • 내부적으로 interpolation 문법이 v-text로 컴파일 됨
<div id = "app">
	<p v-text="message"></p>
	<p>{{ message }}</P>
<div>


<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
	el: '#app',
	data: {
		message:'Hello',
	}
})
</script>

 

 

 

 

v-html

  • 안녕!
  • v-html 사용 절대 금지 Xss 공격을 받을수있다.
<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <p v-html="coolMessage"></p>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data:{
        coolMessage: '<h1>안녕!</h1>'
      },
    })

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

 

v-show

isLoggedIn 이 참이면 보이고 거짓이면 안보이고~

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <p v-show="isLoggedIn">보이나요</p>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data:{
        isLoggedIn: true,
      },
    })
  </script>
</body>
</html>

 

v-if, v-else-if, v-else

조건문으로 나타내깅~

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <p v-if="myType==='AB'"> 
      AB입니다.
    </p>
    <p v-else-if="myType==='O'"> O입니다.</p>
    <p v-else>사람이 아닙니다.</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        seen: true,
        myType: 'O',
      },
    })
  </script>
</body>
</html>

 

 

 

v-for

key 속성

v-if와 v-for 와 동시에 사용하지 말 것!

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <h2>String</h2>
    <p v-for="(char, idx) in message" v-bind:key="idx">
      {{ idx }} {{ char }}
    </p>

    <h2>Array</h2>
    <p v-for="(todo, idx) in todos" v-bind:key="idx">
      {{ todo.title }}
    </p>

    <h2>Object</h2>
    <p v-for="(value, idx) in myObj" v-bind:key="idx">
      {{ value }}
    </p>

  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message:' Hello, Vue!',
        todos: [
          { title:'점심 먹기'},
          { title: 'JS복습하기'},
        ],
        myObj: {
          name: 'Lee',
          age: 100,
        },
      },
    })
  </script>
</body>
</html>


 

 

 

 

v-on(중요 많이 씌임)

v-on:clikc => @click 너무많이쓰여서

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <!-- 메서드 핸들러 -->
    <button v-on:click="onClick">Show Message</button>
    <button @click="onClick">Show Message</button>

    <!-- 기본 동작 방지 (이벤트가 발동했을때)-->
    <form @submit.prevent>
      <button>submit</button>
    </form>

    <!-- 키 별칭을 이용한 키 입력 수식어 (때질때 발동)-->    
    <input type="text" @keyup.enter="onInput">
    <input type="text" @keyup.enter="onInput2($event, '값')">

  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el:'#app',
      data:{
        message: 'Hello, Vue!',
      },
      methods: {
        onClick: function() {
          alert(this.message)
        },
        onInput: function(e) {
          console.log(e.target.value)
        },
        onInput2: function(e, value) {
          console.log(e, value)
        },
      },
    })
  </script>
</body>
</html>

 

v-bind

https://kr.vuejs.org/v2/guide/index.html

class와 속성의 bind

동적으로 클래스 바인딩을 주고싶다

  • HTML요소의 속성에 Vue의 상태 데이터를 값으로 할당

  • Object 형태로 사용하면 value가 true인 key가 class 바인딩 값으로 할당

  • 약어

    • : (콜론)
    • v-bind:href => :href
<!DOCTYPE html>
<html lang="en">
<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>
  <style>
    .active {
      color: red;
    }

    .my-background-color {
      background-color: yellow;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- 속성 바인딩 -->
    <img v-bind:src="imgSrc" alt="">
    <img :src="imgSrc" alt="">

    <hr>

    <!-- 클래스 바인딩 -->
    <div :class="{ active:isRed }">클래스 바인딩</div>
    <button @Click="toggleIsRed">toggle</button>

    <div :class="[activeRed, myBackground]">클래스 바인딩2</div>

    <hr>

    <!-- 스타일 바인딩 -->
    <ul>
      <li 
      :style="{ fontSize: fontSize + 'px' }"
      :class="{ active: todo.isActive }"
      >
        {{ todo.title }}
      </li>
    </ul>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data : {
        imgSrc: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHCBYWFRgWFhYZGBgaHSEaHRwaGhoaGhgeHh4aHBwcGhocIS4lHCErIRocJjgmKy8xNTU1GiQ7QDs0Py40NTEBDAwMEA8QHhISGjQkISExNDQxNDE0NDQ0NDQ0NDQ0MTQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDE0Pz80PzQ0Mf/AABEIAOEA4AMBIgACEQEDEQH/xAAbAAABBQEBAAAAAAAAAAAAAAAFAQIDBAYAB//EAEIQAAEDAQUFBgUCBAQFBQEAAAEAAhEDBBIhMVEFQWFx8AYigZGhsTJCwdHhE/FSYnKCByOishQzNDXCc3SSs+IV/8QAGQEAAwEBAQAAAAAAAAAAAAAAAQIDAAQF/8QAIREAAwEAAgMAAwEBAAAAAAAAAAECESExAxJBIjJREwT/2gAMAwEAAhEDEQA/ADfW/RKcv30Sn79ZpCProuI7B7W4daJQMP20Ssy6+yc3Lz1RQCF468OShAx/dWnN5+uiguY+fWaBhCz66/dK4Y9fdOP30+yV+fX2TAGPYMPxqr1gsZeQAMz9+CG2m0Fl2GzJj5sOMAfbmtF2SrF7nS2LoOsZwM+G5PC1iU8Re/8A5LgMB14IVtOwOYASNd3BbRee/wCJW3iy5Z6Toe6S4jNoOAA0J9lWksJKnoKttspscWlwvfwiCdxxAy8UCt1qdVMDuM8i5VqNnDROZOJJxJUNe3BuWWsT5armqteI6pnFrJq7WtbA9DHss9bamcE8iZB4hT1toXzDXE8In1Viy7NvkFw9/qslj5C3xwAQX1BcxzwJ3BPpWG6ccROYj6rSWuyhgAa2AMJwx5qjSu3oOB44eoKd1nQqnex9mYIyPr9EtQlu4xxyP0V6jZmu3Yjdv8Coq9n0OGm8eGiT20f1wgstuLHAgkdZfgrebJt4qMnCd+XP6Lzp9PcQiGz7W9hljoPoYyBG8dbkNBS4PRmR1GvLipGZ/vxGiD9n9sNtDD8r24PZJ7pykY4tMZoo0T0NJ+iYQUmej90sY/twOqYwYn8fZTD4v35LBGvGX415cU1ww60jVOdmB1lG/kE13XvolMitPWCd11gkYMko6z1QCPGR/KUZefWaawYdajVObl+2qKMzrv101TXDHz3n6KQc+p4Jrsz+VgHY6nzcmv34nrmUsdeKRwz/ABqmARu5/wC3UK5Zbc+nNx0TngN2W7iqbj14jRK8mD+dVlwBoJWntNUpsc9xENaXGW6TovMqVufaa761TFzu8dNAB4YIr27t9yi2kD3qhx1utMn1j1QzYNGGE7yqOmp0RJeyQ/aFa61CrNs41zjJHvy4Ke3tL61zc2J49Yea1exLGAFHcR0payHZvZ5jAIaB1qjNHZLRuRGjTVllNJrKqUCauyWkZSs5tTs4Bi3BegNpKK02YEZLazOUzzOysd8B+IfCeP5U20KJLWvGBOB5/nD1R7aGzrrrw3GVBaKcsIjKPdw9lhGsMlVZeE7x6jdzhOs3qPor1ehBw6GnWqpMEPA1RYjEp2o2a0srA9x5h2hBgPHs7nGi9OYOsdV5ntKheoHVneG892QY8JW52Hab9mpPwJLBJ1IEH1aVTdWk8xhGmJP78tU8Yk/jf4pKPWXNOacT1pwWMNOfXDTxTHnHl9PFSAieuOvNRHOOtNEoURjrNNjqEoXEdYaJWMOZ1knsPXjwTaaexFAE636pCMU4BNIx8tETfTmdZapam/8AK5nXmlf1mihX2QP6z1CR4w/ZK/76cEL7SbRFCzvfPePdZl8R3+Ak+CKAzEdobX+vanEYsp9wcYJnzcSjWxDgRwn1BWTsLMB/MZPsPr5rTWJ1x7eOHsm8nCSB4+W2TWazzVe7V32Wr2eyAso2u9r3FrC4TuCN7M2w2Q14LToVJo6ZZqKLVbY1VaFQHJWr4GJQwfSYBNeFQrbapswJ9FE3b9I4YhbGD2wZtCmgVobg7l90atNrY8YFCWwSR1vSvgL5M9XMs4wY55qCxUw9wcTAiSdBv8cwFLaW3LwPyOv82zj9UzZjmtc8OIhhvAT8X8I444lNhJlyqyXOBbBiLuHdECBhwhWuw9Uig+kc6by3+0kOG7i7yVaTevHeff8AZP2BVu2mozdUYH+LO7/5z4FNL7QjNdTOH7pzDgetRqohl19SnMy/beB9VgHN39dZJhzP55p7Pz9UwdZLGI1x6yXNySx14pRhzD14KRvWajanjrNFGHBMlLCaM/JHQDm9Z6rnpRmmPTCkTz9dF5n2t2t/xFa4wyxkgaOPzO+nII32w7QxNnpHvHB7hu1aI36+SyVns8CSqRP0ndfC9sujeexvnyGKPOZ329ZKHYNlhjnnfgOW8q7QZLydBh44DripeWtop454IqO0nCp+mxl9xcRiQBmd/giFK1MrEsey69pgHNpIzuP35HDgTkqlm2ef1HPyJdIMTHWKs2fYDWkulwdevggDB2YOXHJb8cL+tGh2HWJ7pOWCKWwSIQrYLO+5GbUyQUjY6AdR9JmL7virdi2pZ3iGuYd0d2fJDalAi/LO+Wua18juSIwnLnmhNj2I6H/qsaZaWtuhsgkgh0gNiN2idJZuitvcw1tejTePhbzGHshFazXDhkm7Ks1ZguudeaMBPxAc96LVmSIKk2UUmR2u0X2/zgs8xh6oGyzveA5jXOLWwQM8MjGZWh7RUwAOJw4IVs60OZUDgcyCYyM/F7pl0Sc/lhbouvMB3wD7FUq1qFO1UnnK+GHk+BP+o+SKlzS9134XOMc5g/RZ3tVTw4mMeIB+wTeP9sJXwekzh+yka7u9fZA+zG1f+Is7Hk99vcf/AFNiT4iD4o07L9+SLWMHY7d+3JRh2H7clxdh+yY52GaBjmJwCjaVI0pBhWp4TKae0oox0dQk3rioq9oawF73BrRmT1iiAmlYrtP2sAmlZzJyc8btQw/VUO0fad9YmnRlrMifmdz0HBDbBsz5nK0x9ZK6/hQsFKSSUQbTkgDelr0wx+GTvQjPzEeRU2y8arBoQVVvETXLNQ+mGMa0ZCGj6n3XUKd1o44pa3ecBxhM2taBTZeOAb7Li7Z2rgNWRghWLRgFUsFWQCFNtB0M54LIq+i5sRkAu1RNrpVTZtdhpgjKEv6uMjJFhlcFipZ2nMKL/hAFPTfKc8oBSK5pgKnaXwFZqvQi3VUB3wZ/btSXAfw4nzQuzsxDhuBHqY90XrsF17zjJjkAqraUFrdO87mUxCv6Pswho4O9x+yr9qrMXUg4cMfbrkr9BmLm6yR/bdKsbUoh1F7eH5HqFpeUmRrlMxHZfbRs1Xvk3Hm68aDGH64E+S9TL5AIIIOIIyxG4rxW207rvRa3sZ2gi7Z6rojBjicsfhJO7TTJdFz9IzXw3r3Ydc1C5/WK57+uSjc7rFRKomZkntTGBPCQI5qeEwfdc+o1jS5xhrRJOgAxWRiG22xlJhe90NHmTuAG8rzXbe3H2l90YM3NG4fUqLtFtt9pqYSGNwY36niVc2Ls0NAe4LoiM5ZG7+IdsrZcAOKKvAAhShyr2h0BVJAjaeIMZjEcx1Hiodi1JfI0664Jba9Vdj1P84DXH7oV+rDPZuKTpc08R6qt2sp3qThrh7KKxvNzHd7HL1RG0RVpkbxn91ydM691A7sbbyaTWuzZ3D4ZekLV1XMd3TB4LA2Qmz1gT8DsDoNCtDtV5uiox10jA6EcUz5elJ5xGgsOzw3JzoJynBE6FgY34RE4mMjxWNsW1q7RBbeG7I/ZFqW36gi9SPoPqgdL/wCe0tNERCZUeh9ntVR/eLLreJ73gArDnJSWtcEdZyA7ZtbaTHvccGifsOZOCM2mqAF5v23txe5lMHuklx4xgPUponWTqsQzZtEvffeT/GRJjWI8loLC0mScyfoqNhYGsMZmPIY9c0WswwWrsTeBGGH0+JPqAFPtJ0MeOA9v3Vaue+z+WP8AUfx6p22nRLcrwidMM/ZCeaQtdGCttO+8xkN+6fwqFemWmQjdRl3ujCMIVOqwOXYcvRpuy/aS+BSqnvDBrifi/lcddDv99O568kqUywyFruz3aC/FOoe9k1xnH+Vx14qNRnKKzWm6angYprE8KBU4LM9uraWUm0wY/UJnk2MPMjyWnCx/+IrO5Sdo5w8wD/4p4/ZC3+pkNj2W/VA3DFbJ7IGG5Z3s02HudwWkqPwXUc5VL4UFZ8hdaKoaJcQ0alCrRtho+Bt7icAtpkitbjpiq2yGOFoYSCBJzB3ghXHbTq5m4OENHnIJVjZNd1SuwECBJJAgQAdDGceaSm8Y0zyaKzMgEf0j1yVmmwtgjkfsuZg4DcMTzOAHqSrD2wwefmZXMy6Ae1WY3dzsW8DopOzlsvg035tMcxu9o8E63slnIuhZx9odStAe3UyNcjHqmXIU8Z6PS2QPlcRwRGhs5rcT3jxVLY+1mVGAg+BzCJ1LWxokkIM6v9KzNJHOhULTag3eq9faN7Bgn2VdlnJxdiUpMir1HPxODdNVhdttL7RO5oA8ZMrfWs3WErGsoXnucdxHnmfp5Iy8FpF2zfADpH0ReznBDLM3BzesMVbpvwjeEGKiSs2X8x6gyF3aR0Ma/h7hOr5McNzhPI/ul28wPoPb8zAHRwBz900/shL6MdVeHDPEZcR+FTGaY+p1zTqR7y60crCT7HfZxQCvSLHLYWIYKjtuwyC4ZotGTPRWp7SmNTwuE6xzc1n+3FC/ZXGMWOa71un/AHI+Tiq9vswqU3sPztLeUjAoy8egpajzDs/aYMeB+h60K0FotIY0ucYA6hYuzvcx5BwIOPPeI81JXtb3uJJMey7DmwntNZ9V155uN3A5xwaBJPHJIHsaIa4TrH0Cqg7znxXNbK2BJ8DPfmdGmeGMrYdndj/osL3/ABvEY/K3OI13kcBoVT7MbIECrUi6MWjU6/bxOk6djy84DDJo3QoXfxFZn6R0W96dzRP2njvUVreSMMzh16K1UaGgjcM+JVGtUjvu/tb91EoQ28gNA4+fBZ21WeX+JPXkjBcXEvcZj33BV3jvT1mEdCkWdnWLAI1ZrLrPinWCz90FEWMhAqkOoUAFO5qawptatAQGBW16mEeJ8ECszO5O90n1wV7adW9OpwQ+pUhzWjICFidck1Aw/nCvGhBvDIjFUWYkHjKNMyCzFRExki7y95Q/tJtD9KqyIm7BG4jeDwjPmi1NmJHl4ErI9rxeqXiNzhnmMBu8PIqniWsn5HwB9pUw269n/LfN3eWx8TD/ADD1wO9QWZ2KlsL796kfhfET8r/lfwzIPAqOyMIeWkQQYPAhdaOZmksTzCuPbeaQd6o2YK9ehpTCmwATrqAs7RN3sPg4H3AUze0VPex4/wDifqvO07/Vhe4ZTiENZt+kc74/t+xS1tv0Gsc8uPdBMXXYxuyTIVo867W2MMtdSIhxvgDdeAJnxnzQZqmt1rdUqPqPPeeST9hwGXgopXZPRzvseRgOU+qK7E2d+q+HDuNxdx0BPW9CWmSB0dBgt/suxClR0mSTzxPPD6JPJXqgytZJVq3jdHwjcPLwn2RTZwAlx3Ax7T6lDmUruJzzPXp4KyypDnN/kAHguUvgy01d+4evRQyq4udHh45+ysVnYKq4wJ3/AHxKwSKu4fCMh66kplNsuaFI1nmrljs8OGpI90GPKDuyR3I0KI3FVsTLpI4q/CyKEDmQh9dpceCI1nKAU8FjAHaFKChL2d4IxtXAjNVP05KwjIKQgozZ3YKg6nCvUBAHksLpNWqQQNf3WU2u6/SD97HYnfBvA/QwtLbX95kcj4yJ8481lK5c1loDsO+I4y8kekqsIjRnKz4gZGc50Mj3RSs8F7X5X2yeYJafQA+KHVO80A8cd+GWPLBOtZLWUccYcfAugD/QV1IgzT2XJOt1cNaUI2XtQRDs1T2ttG9gDn14fbmmENEIToUU8CnBy809MfCE9oK91gYPmMnkPz7IoFldsVr9R2OA7o8M/WVTwztEvLWSVC5deTQUhK7Tk0N9mLLfq3yJazdqTgBPW5bpjr7g0YtGM/xAGAY/mdJ5BZLY/cpATBdJJ3ic/IQOeK0NjtNwXjhw0GQA5fdcvkesvC4CdtAaPT0xPWiGveQ8u3D8/QpLRWLiOJPscB1uTw3DjAn0UmsHG1BmmPZl14qS7u65Jh72SwyG0WS6AjFkod9vMeiqbMpS8iMmz6wjNgp4ygOixTZ341H3+6sNdOWYz4JlnALydwhs+pPgrloYBBay4DzxzxxC2hdc4UnMSvEBSEKnbXk90b8+ARCZ/ar77zGQUNB0hp8FLaW4uVNj4KAlF2pi4N1z5DFOfVyA5nxyUbH4lx0UDKhxO8nREnpZrklsjMIF2lb3JA7ju8f6hHqBe80esrxN128wJ3yJhVatmxfQdk4EsO7keSeHj0WlpiWU5uCcg4zwlRbSqS6NGgR/DH7lT1TcF2McWxvwLpHnHmq1u+J3M+W7rguo5yvTqkAjXohVg6Tr1wU7RiUlDB96JjHHLgj0DNZuwwJSxRBx0Tg/gvNPSI7WSxjnyO6J+3qsW4rRdorVDAze4yeQ/MeSzUrs8E5O/wBOTzVzgoViw07zxOQxPIdR4quEUsNM91jJvPMk6AZcsZPkq08RFLkLUHSC92Dc+QG7jqfyibnTcbjJd44C99kFqhz6jaTPgZBedxI1PWKOMeL90ZnEnfuBjQYeK56XJeS42nEE5+gn65BS0WprMtBu4/gKWzOF4DeVNjImFLuPdlAKbsazXj/aT+yKPoXWOYfmEg64QVR2GcAQdxCOB3gbs9sVCMQS276k5b8loqdldEGBhMj4nDgEN2UAKpLmzkPDFahtNhi66CMp/KpM6gOsZQYxrRF1wA3xPiVzxIF03h7eHgrradYTAa6dDl7HLmlFnMSGETg6RB8BOCb0TB7tA+rSgYuE6cet6qOshGIh2pByOiMUrKASTTLuMfdI2y4XmsgzkQUrhBXkZlatgm9JAMj1QG0U4PJbqzWcySGT3hzwjLisztygW1HyInGFNzg3toJY+Y54qcU4CrOpn0RCzC8wnfhKUBX2zQJpG7mIOmRmRxTtnWg2ijJ/51IgyPm0P9wBB4oiGh4uTjEjkgez2mjaho/unkQ4j1EeATz0LXYL7WWcCoHA4PF5vGcwfH3Czlozx6nH6ra9s2AsJObHAjk8QfULFVHTguiHskaXJXOSVhXFJMFO0CXjNsHpb6bdKpbUtP6dMnecG8zv8F50pt4jvp4tYB2zab9Vx3Dujw/MqgkcUkr0JWLDz6rXo9q1GxqN1jqm+Lo4ZyfE+xWUa7FaWz2qKTowAiNB3QBHiZS30NBKy0gPaxuV4EwYvOnMnSfPyRyzUxec7XPkJw9SshswF9ZgGt6OAOZ8h5rS2ytDQxu8xzy+seqlax4Ul8FyvbABeJwyEb92CF2a3E1GS6GueG4bhMEzwJ36KvtWtF1u4SfLBvuShVerBg4BvdEagAzP9UrTOmdYeuVXODLlU5fC8ZcJ/h9kN7PkNe5p4kDdgjvZ22ttVkp1DElsPEZPbg71HqEDFIU65IGAOWmKFLGGXpoLLQ7zjoQPVaFllaUHsGIcdX+10e8o/TKeEJTGNsp3FI9j+ce6tNKexUE0Hh75yPkqtqrua08zuRyEL2li4Dx8ktIaXyU7Kx0DPASecQsJt7aIqVX3SD+mQJG8j4gj3bXtGLLR/TYf86rIEfI3Jzz7DieC8+2Rg0z8xd6AT6ykpYhpfIYruAAIUtAQZGRVeqYDRxA9lPfhuJyw+gUCoNttqfTrX4N0DA7u7ucN0gu5+GBa1sa/9Os3KQTwn8geqp20TdfHdMNeM84DXeeHiNE/ZJutfRdN0YA8yRh/pKpvAmcgrtlaO60Zl8DkBJn2WQKL9qa5NVrT8rY8QTPuEHldELJRKnyImuSkpspxTa3ysrti2334fC3AcdT1orG0NsulzGgAYtvb9DGiCkrn8Pic8st5vInwhVySVxK6CApKv2CqXMfT3luHGD+fRDilpVS1wcMx0Qg1pk8NT2fpBjHPObiKY5DPrgn7Rrw+loXN/wB0+8KGxVw6iHNnCpiDmJEZ7/iUG2SXMY8fKY8j9481HNrksn+JHbqpL2TkQB64qjaqsufoXH1P4U1WoHXXDKZ5TmPNDnb+f3VEhKZuv8ONvfoPdRe4XKmLTPwvwHgHARzAWzPevPzlwA4yZPuF5Lsxlwh7sAMtSeC9G7L7SFdzaZc2+wEhoMEifig7x+UlrXwNLxGz2SzutHWG/wAx6o2wqhY6d1vh5cArjCmlYJT0sAqZhVcFSsKfAExWW7S7cp2Zjqj8TBuNGbiMo4alR9rO21CygsDg+t/A0/Dxefl5Zrxrau2alpBqVXlxLxlg1ggw0DcM/wApWgoi2ltWpXquqPdeLj4AAwGt0EAeaN2Qw+IyZJ8T91lrJSLnhu4n03+i0tnqxefve4MaP5WnE+yn5B5DNb5eBB8sUP21aLjWjjj4D8q45+XHD0/CBdqHEiB/EPWT9FKVtJFG+DR0RfpRucLvg7D0Lh5KmKjhUaDkGOvcXR9wU/ZloH6bY0w82j3hUrbUio8D+O7zxJMe39xRz4DQF2sb/mteMnsDvEEtPo1qFThKL9ohLWEfLebPkfe8gwK6Y6RGuxCmuCeU0phSvK5ICuRALK5JK5YxxKaSlTSsYKbKtl280/C7XKeOk67iAr7q7IdeJuOOIIktdvxGEFZ0J4qEZEpXOjKsQSdRLCS1zXMO6Rj+eIUD64BlgunmT5KmXlJK2A9i0LW/XHWBPmustqex7ajHFr2m8HDMFV2NJIAEk4ADEkrRUuz76QY+q0Oe912nQzc52r4yaN48MFsNrN/2X/xBbUN203aT82uJhjhGrsjM4LcUNpU3AEPYZyIc0zGJjHHBeAbTpVP+JDHOlwc2mHBoDGkEAtaMrrS6IWssnZ+nbKb2FraVroEscWANZUObHOaBk4CJEb1sCegbW7bWOzg3qoe7+Cn33eMYN8SF5x2m/wASK9ollGaFM6H/ADHc3D4eQ81i7TRcxzmvaWOaS0tIiCNxUCJiQVDMnE5yZknU6q3SMse3UBw/tP8A+vRUmhXrNRjEmBr9kGBFnZFLvOee6A047hOExylXLHaA97TBDRDWtOgmCeOPmh9ttguhjBdbnxOkpNnPh7STvnwAw9VOp1aOnhqX1pdT0vEehCHdoDjz7p4Oa78qOnaYa0TiCXeRBPpKt25jS666Yd3hpeAgieMKaWPR29RPs54YwE5MbPlj6uhDrK9xc6o75RnvJOJ5ax/KoLfULmBnwNBE47oMEnw0TBUDgGAwxvee6fl4njkBnjuTyvoGyLaru4GnPPliwe95CgVNbrVfeSMt3LFQSqysRJvkUlNKcmlExWSrlyIBFy5csYU5JhXLljCrly5YBy4LlywQt2X/AOqo/wBf0K3bP+7U/wD0Pq5cuQYUZq2/8+j/AO7q/wD201uNgf8Ac7V/RT9ly5YJif8AEP8A69/Jv+0LLFKuWAShW6nxHkFy5BhRWKs2X4hy+y5cg+g/SzSyZ/UfZE9oZU/6vqFy5TY66YN2l8PiPZNtX/TH+sf7QuXJpFYIZkFI1cuVBDly5csY/9k=',
        isRed: false,
        activeRed: 'active',
        myBackground: 'my-background-color',
        todoList: [
          { id:1, title: '여진님 퀴즈에 답하기', isActive: false },
          { id:1, title: '보충 수업하기', isActive: true },
        ],
        fontSize: '48px',
      },
      methods: {
        toggleIsRed: function() {
          this.isRed = !this.isRed
        },

      }, 
    })
  </script>
</body>
</html>

 

 

v-model

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <!-- 1. input = > data -->
    <h1> input => data</h1>
    <p>{{ message }}</p>
    <input @input="onInput" type="text">

    <!-- 2. input <=> data -->
    <h1> input <=> data</h1>
    <p>{{ message2 }}</p>
    <input v-model="message2" type="text">

    <!-- 3. CheckBox -->
    <!-- input id와 label의 for 는 같아야한다. -->
    <h1>CheckBox</h1>
    <input type="checkbox" id="checkbox" v-model="checked">
    <label for="checkbox">{{ checked }}</label>


  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message:'',
        message2:'',
        checked:false,
      },
      methods: {
        onInput: function(event){
          //console.log(event)
          this.message = event.target.value
        },
      },
    })
  </script>
</body>
</html>

 

 

computed 와 methods 의 차이

<!DOCTYPE html>
<html lang="en">
<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>
  <div id="app">
    <p>{{ message }}</p>
    <p>{{ reversedMessageComputed }}</p>
    <p>{{ reversedMessageMethods() }}</p>
    <input type="text" v-model="message">

    <p>{{ count }}</p>
    <button @click="onClick">증가!</button>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        count: 0,
        message: '안녕하세요!'
      },
      computed: {
        reversedMessageComputed: function() {
        // 1. 캐싱됨
        // 2. 반드시 리턴 필요
        // 3. 종속 대상이 바뀔때만 호출
          return this.message.split('').reverse().join('')
        },
      },
      methods: {
        reversedMessageMethods: function() {
          this.count += 1
          // ...
          console.log('methods실행됨.')
          return this.message.split('').reverse().join('')
        },
        onClick: function() {
          this.count += 1
        },
      },
    })
  </script>
</body>
</html>

 

 

watch

 

 

filters

말그대로 필터

 

 

Lifecycle Hooks

태어났을떄 자동으로 호출되게하기

반드시 함수호출 ( 메소드랑 같은 라인에 적어주기)

 

728x90

'SSAFY > Django' 카테고리의 다른 글

[Django] Dog api(댕댕이 랜덤 추출기) html 만들기!  (0) 2021.05.03
[Django] 게시판, 좋아요, 댓글, 계정 기능 종합  (0) 2021.05.02
Dom 실무?  (0) 2021.04.29
[Django] Dom  (0) 2021.04.28
[Django] swagger  (0) 2021.04.27