JSFiddle - React, Tailwind, and code Playground
by flourscent
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.min.js"></script>
<div id="app">
<nav v-cloak>
<router-link to="/top">최상위 페이지</router-link>
<router-link to="/users">사용자 목록 페이지</router-link>
<router-link to="/users/new?redirect=true">신규 사용자 등록</router-link>
<router-link to="/login" v-show="!Auth.loggedIn()">로그인</router-link>
<router-link to="/logout" v-show="Auth.loggedIn()">로그아웃</router-link>
</nav>
<router-view></router-view>
</div>
<!-- 사용자 목록 페이지 템플릿 -->
<script type="x-template" id="user-list">
<div>
<div class="loading" v-if="loading">로딩 중...</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-for="user in users" :key="user.id">
<router-link :to="{ path: '/users/' + user.id }">{{ user.name }}</router-link>
</div>
</div>
</script>
<!-- 사용자 상세 정보 페이지 템플릿 -->
<script type="x-template" id="user-detail">
<div>
<div class="loading" v-if="loading">로딩 중...</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-if="user">
<h2>{{ user.name }}</h2>
<p>{{ user.description }}</p>
</div>
</div>
</script>
<!-- 신규 사용자 등록 페이지 템플릿 -->
<script type="x-template" id="user-create">
<div>
<div class="sending" v-if="sending">Sending...</div>
<div>
<h2>신규 사용자 등록</h2>
<div>
<label>이름: </label>
<input type="text" v-model="user.name">
</div>
<div>
<label>설명: </label>
<textarea v-model="user.description"></textarea>
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div>
<input type="button" @click="createUser" value="등록">
</div>
</div>
</div>
</script>
<!-- 로그인 페이지 템플릿 -->
<script type="x-template" id="login">
<div>
<h2>Login</h2>
<p v-if="$route.query.redirect">
로그인이 필요합니다
</p>
<form @submit.prevent="login">
...
CSS
[v-cloak] {
display: none
}
JavaScript
// 예제 애플리케이션에 사용할 더미 인증 모듈
var Auth = {
login: function (email, pass, cb) {
// 더미 데이터를 사용한 가짜 로그인
setTimeout(function () {
if (email === '[email protected]' && pass === 'vue') {
// 로그인 성공시 로컬 스토리지에 token을 저장
localStorage.token = Math.random().toString(36).substring(7)
if (cb) { cb(true) }
} else {
if (cb) { cb(false) }
}
}, 0)
},
logout: function () {
delete localStorage.token
},
loggedIn: function () {
// 로컬 스토리지에 token이 있으면 로그인 상태로 간주함
return !!localStorage.token
}
}
// 더미 데이터 정의. 원래는 이 정보가 데이터베이스에 있고 API를 통해 받아와야 함
var userData = [
{
id: 1,
name: 'Takuya Tejima',
description: '동남아시아에서 일하는 엔지니어입니다.'
},
{
id: 2,
name: 'Yohei Noda',
description: '아웃도어, 풋살이 취미인 엔지니어입니다.'
}
]
// 가짜 API를 통해 정보를 받아온 흉내를 냄
var getUsers = function (callback) {
setTimeout(function () {
callback(null, userData)
}, 1000)
}
var getUser = function (userId, callback) {
setTimeout(function () {
var filteredUsers = userData.filter(function (user) {
return user.id === parseInt(userId, 10)
})
callback(null, filteredUsers && filteredUsers[0])
}, 1000)
}
// 가짜 API를 통해 정보를 수정한 흉내를 냄.
// 실제 웹 애플리케이션이면 이 부분에서 서버에 POST 요청을 보냄
var postUser = function (params, callback) {
setTimeout(function () {
// id가 추가될 때마다 자동으로 increment 됨
params.id = userData.length + 1
userData.push(params)
callback(null, params)
}, 1000)
}
// 로그인 컴포넌트
var Login = {
template: '#login',
data: function () {
return {
email: '[email protected]',
pass: '',
error: false
}
},
methods: {
login: function () {
Auth.login(this.email, this.pass, (function (loggedIn) {
if (!loggedIn) {
this.error = true
} else {
// redirect 파라미터가 있으면 해당 경로로 이동
this.$router.replace(this.$route.query.redirect || '/')
}
}).bind(this))
}
}
}
// 사용자 목록 컴포넌트
var UserList = {
template:...