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:...