테스트
블로그 테스트 1
이미지 출처(https://vuejs.org/images/logo.png)
실무에서 웹뷰 작업을 하면서 iOS의 Segment UI를 자주 사용하여서 Vue로 된 컴포넌트 파일 하나를 만들어 두려고 한다.
1 | <!-- Segment.vue --> |
1 | <template> |
img태그 사용시 특정 retina 디스플레이에서 2배수, 3배수 이미지가 적용되지 않았음.
기존 retina 디스플레이의 이미지 대응을 위해서 img태그의 srcset
이라는 어트리뷰트를 아래와 같이 사용하고 있었다.
1 | <img src="testSrc.png" |
하지만 특정 디스플레이에서 제대로 적용되지 않음을 발견하였고, 그 이유가 srcset속성은 IE, Android 5.0 미만의 버전에서 지원하지 않는다고 한다. (링크)
리서칭 결과 3가지 정도의 방안을 찾았다.
세가지 다 작은 단점들이 조금씩 존재하였지만 결론부터 말하면 3번 방향으로 해결하였다.
1번의 경우 이미지 하나를 표현하기 위해 여러개의 요청을 발생시키게 되는 문제가 생길 수 있고, 2번은 IE8 미지원 및 이미지화(?)되어 버린 리소스들은 다시 작업이 필요하였고 3번은 retina가 아닌 디스플레이에서는 더 큰 용량의 이미지를 사용하여야 했다.
고민해본 결과, 매우 큰 이미지는 잘 사용하지 않는 편이여서 2배수 or 3배수 이미지를 default로 사용하기로 하였다.
1 | <img src="testSrc@2x.png" |
추후 리소스 정리를 진행한다면, 모바일 기반 제품들은 svg로 갈아타면 좋을듯하다.
결국 제작한 라이언을 캡쳐하여 썸네일로 사용해 보았는데, 저작권 문제 있지 않을지 조금 걱정이..
제목에서 언급하였듯 심심해서 만들어 보았다.
SVG쪽을 나중에 해봐야지 해봐야지 하고 미루어만 둔 상태이었는데, 어떤 문법을 가지고 있는지 기초 정도만 알아보자라는 생각으로 시작하게 되었다.
라이언의 얼굴까지는 상당히 쉽다고 느끼며 코드를 작성하였으나 몸통 부분에서 path
를 사용하면서 부터 조금 어려움을 느낀것 같다. ( 몸통은 하지말까 라는 생각을 중간에 하기도.. )
뭔가 조금 어색하지만 나름 라이언 비슷(?)하게 생긴 결과물이 나와서 만족
javascript 변경해서 특정 이벤트를 등록하거나, css 애니메이션을 입혀보는 작업도 재미있을듯 하다.
이미지 출처(https://vuejs.org/images/logo.png)
이전 글에서 예제로 사용한 카운트 앱을 통하여 학습해봅시다.
카운트 앱을 2가지로 분리할 예정입니다.
첫째로 value가 표시되는 영역, 두번째로 value값을 조정하는 영역입니다.
기존 예제 ( App.vue )
1 | <template lang="html"> |
위와 같던 예제를…
1 | <template lang="html"> |
이렇게 만들 예정입니다. 일단 App.vue 를 위처럼 수정해주세요.
컴포넌트와 컨테이너를 담을 폴더들을 생성합니다. 전체적인 디렉토리 구조는 아래와 같이 작성하였습니다.
components
countValue.vue
countController.vue
containers
count.vue
강조된 부분이 기존 vue-cli에서 생성해주지 않은 부분으로 직접 생성해야하는 폴더, 파일 입니다.
Count 라는 컨테이너(page)부터 살펴보도록 합시다.
Count 앱의 모든 기능은 이 컨테이너 안으로 들어가져 있습니다.
1 | <template lang="html"> |
13번 라인을 보면 components
가 있습니다.
이는 이 count라는 컨테이너에서 사용할 컴포넌트들을 정의하는 부분입니다.
윗줄에서 import로 불러온, countValue와 countController 2가지의 컴포넌트들을 사용한다고 정의한 것이지요.
정의한 컴포넌트들은 html 영역인 template에서 사용됩니다.
3, 4번 라인이 해당하는 부분입니다.
중요한 내용은 아니지만, 저는 camel case(대문자로 연결) 방식을 사용하였으나 kebab case(하이픈으로 연결)를 권장한다는 글을 본거 같아서 언급해봅니다.
다시 예제의 컴포넌트를 봅시다.
현재 카운트 앱의 데이터 및 행동들은 모두 count라는 컨테이너가 가지고 있습니다. 우리는 이것들을 각 자식 컴포넌트에게 props
를 통하여 넘겨주어야 합니다.
3번 라인, :cv="num"
cv라는 이름으로 num 데이터를 자식 컴포넌트에게 넘겨주고 있습니다. 자식 컴포넌트인 countValue는 cv를 props를 통하여 받아와야 합니다.
1 | <template lang="html"> |
Vue.js - Component(컴포넌트) 1 에서 설명했던 props 사용법과 동일합니다.
이제 count.vue의 4번라인을 봅시다.
이 부분도 이전에 설명했던 부분입니다. Vue.js - Component(컴포넌트) 2 - 부모 자식간 통신의 예제에서 언급했던 기능이지요.
컴포넌트를 통해 커스텀 이벤트를 정의한 뒤, 자식 컴포넌트에서 $emit
을 사용하여 부모의 이벤트를 발생시키는 방법입니다.
1 | <template lang="html"> |
싱글 파일 컴포넌트를 사용한 Vue 앱을 만들어보았습니다.
포스트도 오랜만이고, 글을 며칠을 나누어 쓰다 보니, 앞뒤의 내용도 헷갈리고 많이 어렵네요. ㅠ
그래도.. 현재 포스트까지의 내용을 이해하실 수 있다면 다른 vue를 사용하여 여러 가지 시도를 해보시기 충분하지 않을까 합니다.
앞으로 Router와 Vuex를 활용하는 방법까지 배우신다면 실무에서도 무리가 없지 않을까 생각해봅니다.
이미지 출처(https://vuejs.org/images/logo.png)
이번에는 vue-cli가 만들어준 Vue 프로젝트를 살펴보도록 하겠습니다.
그전에 한가지 짚고 가야 할 점이 있습니다.
vue-cli는 각 컴포넌트를 .vue
확장자를 가진 싱글 파일 컴포넌트
로 만들어주기 때문에 지금부터는 기존까지의 Vue 코딩 방식과는 다른 방식으로 코딩하겠습니다.
문법 자체는 거의 동일하다보니 큰 문제없이 잘 진행할 수 있을 것입니다.
그래서 싱글 파일 컴포넌트가 무엇 인가?
.vue 확장자를 파일을 Webpack 또는 Browserify와 같은 도구를 이용하여 빌드하여 Vue.js를 사용하는 것 입니다.
우리가 만든 app이라는 프로젝트의 /src/App.vue
를 살펴봅시다.
1 | <template> |
마크업과 스크립트 그리고 css를 모두 한 파일에 작성합니다.
해당 컴포넌트의 마크업을 작성하고 스크립트에서 설정한 데이터 및 메서드 등을 연결시켜 줍니다.
컴포넌트의 데이터, 메서드, 라이프사이클 등 이전 까지 Vue 생성자에서 사용한 부분들을 이곳에서 작성합니다. 그리고 만들어진 컴포넌트를 반환해줍니다.
해당 컴포넌트의 css를 정의합니다. 이 style태그에 scoped
라는 속성을 추가하면 해당 컴포넌트에 css가 종속됩니다.
앞으로는 이 싱글 파일 컴포넌트 방식으로 Vue 앱을 작성하겠습니다.
App.vue의 모든 코드를 지우고 맛보기를 위해 간단한 카운트 앱을 만들어 보려 합니다.
1 | <template lang="html"> |
우선 기본 틀(?)을 생성 합시다.
(제가 사용하는 에디터는 Vue.js 관련된 문법 플러그인과 같은 기능을 추가하여서 단축키로 쉽게 기본 틀을 작성할 수 있습니다. 자신의 사용하는 에디터에서 한번 찾아보시는 것을 추천합니다.)
이제 카운트 앱의 기능을 생각 해봅시다.
카운트 앱은 기준이 되는 숫자, 증가 행위, 감소 행위가 있을 수 있습니다.
1 | <template lang="html"> |
한번 확인해 보시길 바랍니다. 기존 Vue.js와 거의 비슷하지요?
게다가 webpack에서 babel이 기본으로 셋팅되어 있어서 es5이상의 문법을 사용 할 수 있습니다.
자 이제 데이터와, 기능(메서드)를 만들었으니 이벤트를 연결 합니다. 이 또한 기존 Vue.js와 동일합니다.
1 | <template lang="html"> |
카운트 앱의 모든 기능이 완성 되었습니다.
이제 npm run dev
를 사용하여 실행해봅시다. 이미 실행 되어있다면 웹 페이지를 띄워봅시다. 기본적으로 핫 로딩을 지원하기 때문에 바로 적용되어 있을 것 입니다.
모든 기능이 잘 동작하는데 뭔가 조금 아쉽네요. 스타일을 입혀봅시다.
1 | <template lang="html"> |
이제 우리는 Vue.js 프로젝트 생성도 해보았고 하나의 앱을 만들어 보았습니다.
하지만 아직 모든 부분을 살펴본게 아니기 때문에 다음장까지는 이어서 vue-cli가 만들어준 프로젝트를 살펴보겠습니다.
이미지 출처(https://vuejs.org/images/logo.png)
여태까지 Vue.js에 대한 아주아주 기본적인 문법들을 살펴보았습니다. 이제 Vue.js를 사용하여 프로젝트를 구성해보려고 합니다.
프로젝트를 구성해보기 앞서 vue-cli
라는 것을 설치 하겠습니다.
vue-cli는 vue 프로젝트를 매우 간편하게 구성하도록 도와주는 보일러 플레이트 입니다. 리액트를 사용해보셨다면 create-react-app과 같은 기능을 도와준다고 생각하면 되겠습니다.
1 | npm i -g vue-cli |
vue-cli설치가 완료 되었다면 이제 vue프로젝트를 생성해봅시다.
실행문법은 다음과 같습니다.
1 | vue init <template-name> <project-name> |
템플릿 네임은 해당 프로젝트를 어떠한 환경으로 설정 할 것인지 정하는 것 이고, 프로젝트 네임은 해당 프로젝트의 이름을 입력합니다.
프로젝트 네임은 사용자가 원하는 이름으로 설정하면 되지만 템플릿 네임은 vue-cli에서 제공하는 몇가지 안을 보고 선택해야 합니다.
위 와같은 템플릿을 제공하고 있으며 각 템플릿 별 자세한 설명은 vue-cli 깃헙을 확인해보시길 바랍니다.
저희가 사용할 템플릿은 webpack-simple 입니다. 이름을 보면 유추할 수 있겠지만 webpack을 사용하는 프로젝트를 생성해줍니다.
1 | vue init webpack-simple app |
명령어를 입력하면 몇 가지 환경에 대한 질문을 합니다. 가벼운 연습 예제로 사용할 예정이니 전부 엔터로 넘어갑니다.
모든 질문이 끝나면 첫 번째 vue 프로젝트가 생성되었습니다.
위 vue-cli 버전은 2.9.2 입니다.
자 이제 프로젝트도 만들었으니 실행을 시켜보아야겠지요?
1 | cd app |
방금 만든 app 프로젝트로 들어가서 package.json에 명시된 모듈들을 설치해줍시다.
설치가 완료되었다면
1 | npm run dev |
명령어를 실행하면 자동으로 웹 브라우저에 프로젝트가 실행될 것 입니다.
이제 Vue.js 프로젝트를 시작할 모든 준비가 완료되었습니다.
이미지 출처(https://vuejs.org/images/logo.png)
지난 시간에 이어 컴포넌트를 사용하는 몇가지 방법을 더 알아보고자 합니다.
조금 더 쉽게 템플릿을 만드는 방법과 각 컴포넌트의 통신 방법을 예제를 들어 설명 하도록 하겠습니다.
1 | <div id="app"> |
1 | Vue.component('test-component', { |
template
기능을 이용하면 복잡한 마크업의 컴포넌트를 생성할 수 있습니다.
사용방법은 위 예제와 같이 template: '#templateId'
형태로 html의 template 태그의 id와 template 속성의 값을 매핑 시켜줍니다. 템플릿 내부는 기존 배워왔던 Vue.js의 문법과 동일하게 사용 가능합니다.
1 | <div id="app"> |
1 | Vue.component('parent', { |
기본적으로 데이터는 부모에서 자식으로 향하는 단방향 데이터 흐름을 가지고 있습니다.
위 예제는 자식 컴포넌트에서 부모의 데이터를 수정하는 예제입니다.
자식은 1끼에 500 칼로리를 섭취하지만 부모는 1끼에 800칼로리를 섭취합니다. 각각 부모와 자식은 칼로리라는 데이터를 가지고 있으며 자식이 밥을 먹을때만 부모도 함께 먹습니다.
밥을 먹는 이벤트를 발생시키는 트리거(버튼)는 자식이 가지고 있습니다. 이 트리거는 childEat라는 메서드를 실행 시켜줍니다. 이 메서드는 자식의 칼로리를 500 증가시켜주며 $emit()
을 사용하여 eat
이라는 이벤트를 발생시킵니다. eat은 child 컴포넌트를 사용(?)하는 부분에서 찾아볼 수 있습니다.
@eat="parentEat"
이런식으로 말이지요.
eat이라는 이벤트가 감지(발생)되면 parentEat이라는 메서드를 실행하게 되는 것 이지요.
이 parentEat은 부모의 칼로리를 800 증가 시켜줍니다. 이로써 자식 컴포넌트에서 부모의 데이터를 접근 할 수 있게 되었습니다.
이해가 잘 안된다면 아래 이미지를 한번 살펴봅시다.
부모와 자식이 아닌 관계에서도 컴포넌트간의 통신이 필요할 때 가 있을 수 있습니다. 다음 예제는 빈 Vue 인스턴스를 이벤트 버스로 이용한 예제 입니다.
1 | <div id="app"> |
1 | Vue.component('component1', { |
input에 값을 입력 후 버튼을 눌러봅시다. input에 들어간 값이 텍스트로 출력 되는 것을 확인 할 수 있습니다.
이 방식 또한 위의 부모 자식간의 통신과 비슷합니다.
컴포넌트1에서 $emit()
을 이용하여 이벤트 트리거를 생성 한 후 컴포넌트2 에서 $on()
을 이용하여 이벤트를 감지하는 방법입니다. 단지 전역에 있는 eventBus라는 통로를 이용한다는 점이 다를 뿐 이지요.
html5의 스펙인 Geolocation을 이용하여 현재 위치의 날씨를 알려주는 기능을 만들어 볼까 합니다.
service worker와 firebase에서 제공하는 fcm 을 이용하여 웹앱 형태로 추 후 만들어 볼 예정이기도 합니다.
React를 이용한 무언가를 만들어 보아야지 하고 결심하고 시작한 작업이지만 만들다 보니 React의 중요성이 크지 않게 되었네요.
1 | npm i -g create-react-app |
create-react-app 도구를 사용하여 react 프로젝트를 생성합니다.
작업이 끝나면 이러한 형태의 구조를 가지게 됩니다. ( firebase와 ServiceWorker 관련 파일은 무시해주세요. 아직 진행 중.. )
핵심인 App.js 정도만 살펴보려 합니다.
App.js
1 | import React, {Component} from 'react'; |
각 api요청을 위한 axios, 순차적인 비동기 작업이 필요하여 bluebird(Promise)를 사용하였습니다.
각 api요청 및 상태 작업을 살펴보도록 하겠습니다.
1 | navigator.geolocation.getCurrentPosition((p) => { |
html5 스펙에서 추가된 geolocation 입니다. 현재 위치의 위도 경도 값을 구할 수 있습니다. 이제 이 좌표를 이용하여서 google map에서 현 위치를 표시 해 줄 것 입니다.
1 | axios.get('https://freegeoip.net/json/').then((res) => { |
ip, 좌표, 지역 등의 값을 제공해줍니다. geolocation에 비해 좌표가 정확하지 않아 날씨 api에서 필요한 지역 정보만 사용하였습니다.
1 | axios.get(`http://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=${weatherConfig.key}&q=${data.city.toLowerCase()},${data.countryCode.toUpperCase()}`).then((res) => { |
지역정보를 통하여 해당 지역의 날씨에 대한 정보를 가져옵니다. 위의 freegeoip와 지역 네이밍 규칙이 비슷하더군요.
이 데이터를 가공하여 사용자에게 정보를 보여줍니다.
1 | const geocoder = new window.google.maps.Geocoder; |
google의 geoCoder 를 이용하여 상세한 지역 정보를 가져옵니다. (우편번호, 구, 군 등..)
위의 freegeoip를 사용하지 않고 이 정보를 잘 가공만 한다면 문제없이 사용 가능하지 않을까 합니다. ( 코드 분량과 수고가 좀 필요할 것 같아서 분리 하였습니다. )
더보기를 누르면 state.weatherDate 값이 증가하며 그 다음날의 날씨를 불러올 수 있습니다. 해외에서 제공하는 api때문인지 날씨가 묘하게 다른감이 없지 않아 있더군요. 개인 연습용으로 작업하는 것이라 무시하고 진행하였습니다.
날씨 : 링크
지역(freegeoip) : 링크
지도 : api 링크, 외부 컴포넌트 링크
firebase에서 제공하는 메세징 서비스(fcm)와 service worker를 추가하여 웹앱 형태로 동작하도록 추가적인 작업을 진행 해보려합니다.
제 검색능력이 부족한지 자료를 구하기가 많이 힘드네요. 현재 많은 삽질을 겪고 있습니다. 가끔 시간을 내어서 완성시켜 봐야겠습니다.
가끔 웹페이지를 둘러보면 라디오 버튼과 같은 기능을 가지고 있으면서도 스크립트를 사용하여 기능 구현을 하는 경우를 보았습니다. 대부분 흔히 알고 있는 동그란 라디오 버튼과 모양이 많이 달라서 스크립트를 사용한 것 같더군요. 최근 작은 프로젝트를 진행하면서 라디오 버튼을 커스터마이징 해야 할 일이 생겨서 작업한 코드를 남겨볼까 합니다.
우선 예제의 코드펜 링크입니다.
https://codepen.io/small/pen/BwoMRM?editors=1010
1 | <p>grid css 1</p> |
label의 명시적 연결을 통해 스크립트의 사용 없이 충분히 원하는 모양으로 커스터마이징이 가능합니다. <input type="file">
등 다른 input 요소들 또한 같은 방법으로 커스터마이징을 많이 하곤 합니다.
1 | @mixin ie8 { |
sass 를 사용하였습니다. 아래 코드펜에서 compiled css를 확인해주세요. (scss 영역에 마우스 올리면 view compiled 버튼이 생깁니다.)
핵심 키워드는 label의 명시적 연결과 css의 선택자의 조합입니다.
이 방법을 스크립트의 사용 없이 IE9 까지 정상적으로 지원이 가능합니다.
scss 하단을 보시면 ie8의 경우 :checked
가 아닌 .checked
를 사용한 것을 보실 수 있습니다.
IE8의 경우는 :checked
css selector가 지원되지 않기 때문에 간단한 클래스 추가 삭제의 기능이 필요합니다. (여기서부터는 글의 제목과 조금 상이해지네요.)
1 | <!--[if IE 8]><html class="ie ie8" lang="ko"><![endif]--> |
우선 조건부 주석을 사용하여 html 요소에 ie8 클래스를 입력하고, 기본으로 체크가 되어있는 라디오 버튼들에게 checked 클래스를 줍니다. 그리고 하단의 javascript를 이용하여 checked클래스 토글 기능을 등록합니다.
1 | // util function |
요약해보면 ie8일 경우 자신에게 checked 클래스를 추가하고 기존의 checked 클래스를 삭제하는 이벤트를 등록하였습니다. 간단한 코드인데도 꽤나 길어지네요. DOM 라이브러리를 사용하시기를 추천합니다.