안녕하세요 상훈입니다.

Vue.js 에서 라우팅을 정리해볼까합니다. 

 

Route, Routing...  Laravel 에서는 web.php가 그 역할을 가지고 있습니다. 


하지만 저는 Front Framework 부분에서 그 내용을 처리하는 것이 더 옳다고 생각하기 때문에 vue-route에도 신경을 써보았습니다.

처음에는 진짜 정말 ? ? ? 하는 순간에 파일이 휙휙 지나가고 내가 한 게 이게 무엇인가...나는 감자다 이랬는데 여러 번 반복하여 자료를 살펴보고 직접 세팅을 해보았으며 정리를 해보니 대략적인 감을 잡았습니다.

Vue.js 3 에서는 아직 적용해보지 않았고, 현재는 Vue.js 2 만 적용해본 상태입니다.

기본 구성은 이렇습니다.

기본 구성은 위와 같습니다. 

0. Vue project설치하고, vue-router를 설치합니다.

$ vue create '프로젝트명'
$ npm i -S vue-router
$ npm install 

1. router/index.js 생성
2. views/...  : vue 파일들 생성
3. main.js 수정
4. App.vue 수정

이렇게 진행하도록 하겠습니다.


1. router/index.js 생성

router 폴더와 그 안에 index.js를 생성하겠습니다. 그리고 아래와 같은 코드를 작성해줍니다.

import Vue from 'vue'
import VueRouter from 'vue-router'
import FirstPage from '@/views/first-page.vue'
import SecondPage from '@/views/second-page.vue'
import MainPage from '@/views/main-page.vue'

Vue.use(VueRouter)

const routes = [
        {
            path: '/', name: 'MainPage', component: MainPage
        },
        {
            path: '/FirstPage', name: 'FirstPage', component: FirstPage
        },
        {
            path: '/SecondPage', name: 'SecondPage', component: SecondPage
        },
    ]

const router = new VueRouter({
    mode: 'history',
    routes
})
export default router

vue route 관련한 내용을 import.

VueRouter를 사용한다고 선언.

routes의 경로를 직접 지정 저장. => Web.php가 하는 라우팅 역할

router를 출력(?) 내보내기(?) 느낌 실행


2. views/...  : vue 파일들 생성

views라는 폴더를 생성해주시고, 그 안에 해당되는 .vue파일들을 생성해줍니다.

3개의 .vue 파일을 router 이름과 동일하게 생성

 

여기서 잘 보시면 파일제목 <-> route 했던부분의 이름이 다른 것을 확인하실 수 있습니다.

바로 snake-casecamel-case를 지원하는 것인데요, 이에 대해서는 아시리라 생각하고 넘어가겠습니다.


3. main.js 수정

main.js

기존에 src/main.js 에 있던 파일을 살짝 수정하도록 하겠습니다.

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

변경된 부분은

1. import router from './router'
2. Vue 객체 내에 router 선언 
입니다.

이 곳에서 router를 호출하게 되고, app을 렌더링 시켜줍니다.


4. App.vue 수정

마지막으로 App.vue 수정입니다. 이곳에서는 쓸데없는 기존의 부분들을 모두 걷어내주고, 아래와 같이 작성합니다.

<template>
  <div id="app">
    <h1>Router Start</h1>
    <router-link to="/">Main Page</router-link> |
    <router-link to="/FirstPage">First Page</router-link> |
    <router-link to="/SecondPage">Second Page</router-link>
    <router-view />
  </div>
</template>

<script>

export default {
  name: 'App',
}
</script>

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

<router-link> </router-link>
<router-view />

두 가지만 잘 알고 있으면 됩니다. 나머지는 없애도 됩니다.

<router-link to="경로"> a 태그 라고 생각하세요 </router-link>

router link a 태그와 생김새가 동일합니다. 해당 태그를 클릭하면 (1)의 index.js에 의해 routing되어 해당되는 경로로 이동합니다. 

router-view 는 해당되는 view출력해줍니다. 대신 contents만 갈아끼워준다는 느낌이 강합니다.

 

 

[ F12 개발자모드 ] 를 켜서 확인해주시면 <div id="app"> 내의 태그들 reload 되기 때문입니다.

 

이제  $ npm run serve 를 통해 서버를 띄워주시면 아래의 결과가 나옵니다.

라우팅 어려운것,,,,

 

위의 내용 중에 오류잘못 서술한 부분이 있다면

코멘트 남겨주시면 감사하겠습니다.

 

뷰 초보자이지만 천천히 꾸준히 나아가려고 합니다. 감사합니다.

 

제가 정리한 전체적인 흐름입니다.

 

 

 

강의는 짐코더님의 Vuetify 강좌 중에서 반복적으로 연습해보았습니다.

 

 

동적 라우트 매칭 | Vue Router

동적 라우트 매칭 주어진 패턴을 가진 라우트를 동일한 컴포넌트에 매핑해야하는 경우가 자주 있습니다. 예를 들어 모든 사용자에 대해 동일한 레이아웃을 가지지만 하지만 다른 사용자 ID로 렌

router.vuejs.org

반응형

 

values / style.xml

style.xml 파일을 하나 만들어주세요.

<?xml version="1.0" encoding="utf-8"?>
<resources>

<!-- Base application theme. -->
    <style name="ThemeActionBar"
        parent="Widget.AppCompat.Light.ActionBar.Solid">
        <item name="android:background">@null</item>
        <!-- Support library compatibility -->
        <item name="background">@null</item>
    </style>
</resources>

해당 내용을 작성합니다. 

@null 로 처리하여 없애버립니다(투명하게)

 

2. themes / themes.xml 

이곳으로 이동해주세요
이 아래에 작성해주세요.

 

<!-- Customize your theme here --> 아래에 작성해주세요

 

<!-- actionbar -->
        <item name="android:actionBarStyle">@style/ThemeActionBar</item>
        <item name="android:windowActionBarOverlay">true</item>
        <!-- Support library compatibility -->
        <item name="actionBarStyle">@style/ThemeActionBar</item>
        <item name="windowActionBarOverlay">true</item>

 

Avd 재구동! ( 에뮬레이터 )

 

 

 

원래는 있던 ActionBar가 사라진 것을 알 수 있습니다.

 

 

이전 모습 비교:

 

[ Kotlin, Java ] 안드로이드 스튜디오 - 비디오 배경화면 설정하기

mainActivity.kt val videoUri = Uri.parse("android.resource://" + packageName + "/" + R.raw.first ); binding.videoView.setVideoURI(videoUri); binding.videoView.start(); binding.videoView.setOnComplet..

code-hoon.tistory.com

감사합니다.

 

 

참고

 

Material Design Transparent ActionBar

I'd like to know if anyone knows how to make an activity with transparent action bar, like the one you have in the new Google Play Store when you go to an app's page. I don't care about the scroll...

stackoverflow.com

 

 

How to change the color of Action Bar in an Android App? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

반응형

mainActivity.kt

val videoUri = Uri.parse("android.resource://" + packageName + "/" + R.raw.first );
        binding.videoView.setVideoURI(videoUri);
        binding.videoView.start();
        binding.videoView.setOnCompletionListener {
            binding.videoView.start();
        }

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"

        />
</RelativeLayout>

 

 

ConstraintLayout -> RelativeLayout으로 변경.

VideoView를 삽입하고, 해당 내용을 작성한다.

 

 

=> VideoView Layout 아래부터 코드를 작성하면 동영상 레이아웃이 가장 하단에 쌓여,

z-index가 가장 낮은 순위가 된다.

 

포토샵으로 보자면, 동영상 레이아웃을 가장 아래에 놓고 위에 다른 레이아웃들을 쌓는 형태이다.

 

 

 

 

How to create a video background for my app in Kotlin? setVideoURI and setVideoPath are not working - Stack Overflow

 

webcache.googleusercontent.com

 

반응형

 

java.lang.NullPointerException: Attempt to invoke virtual method 
'android.view.WindowInsetsController com.android.internal.policy.DecorView
.getWindowInsetsController()'on a null object reference

 

전체화면 적용 중에 

해당되는 에러가 발생하였다.

 

이 이유는 onCreate() 안에서 setContentView가 선언되기 전에 전체화면 적용하는 코드를 작성하였기 때문이다.

이와 같이 setContentView(binding.root)끝난 후에 해당 내용을 작성해주는 것으로 이동시키면 해결.

 

 

 

 

stackoverflow에서 발췌

 

How to set fullscreen in Android R?

I need to put a screen in fullscreen in my app. For this I am using this code: override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestWindowFeature(W...

stackoverflow.com

 

 

 

반응형
반응형

안녕하세요 상훈입니다.

Vue.js cli 를 이용하여 클론코딩을 하였습니다.

 

 

유튜버 분께서 타자가 엄청 빠르시니 적당히 멈추시면서 하세요!
(내용이 아주 좋습니다. 요점을 잘 잡고 간단하게 구현해주었습니다. )

 

 

$ vue create vue-weatherapp

으로 Vue 3 프로젝트를 생성해주었습니다.

그리고 바로 $ npm run serve 를 통하여 구동!

Component를 만들지 않고 오로지 App.vue에서 해당 내용을 작성하였습니다.

 

<template>

<template>
  <div id="App" :class="typeof weather.main != 'undefined' && weather.main.temp > 16 ? 'warm' : '' ">
    <main>
      <div class="search-box">
        <input 
          type="text" 
          class="search-bar" 
          placeholder="Search..."
          v-model="query" 
          @keypress="fetchWeather" 
        />
      </div>

      <div class="weather-wrap" v-if="typeof weather.main != 'undefined'">
        <div class="location-box">
          <div class="location">{{ weather.name }}, {{ weather.sys.country }}</div>
          <div class="date">{{ dateBuilder() }}</div>
        </div>

        <div class="weather-box">
          <div class="temp">{{ Math.round(weather.main.temp) }}</div>
          <div class="weather">{{ weather.weather[0].main }}</div>
        </div>

      </div>
    </main>
  </div>
</template>

 

<script>

<script>
export default {
  name: 'App',
  data() {
    return {
      api_key : 'd5297dac23efd490788f837861e52f62',
      url_base: 'https://api.openweathermap.org/data/2.5/',
      query: '',
      weather: {},
    }
  },
  methods: {
    fetchWeather (e) {
      if (e.key == "Enter") {
        fetch(`${this.url_base}weather?q=${this.query}&units=metric&APPID=${this.api_key}`)
          .then(res => {
            return res.json();
          }).then(this.setResults);
      }
    },
    setResults (results) {
      this.weather = results;
    },
    dateBuilder () {
      let d = new Date()
      let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
      let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

      let day = days[d.getDay()];
      let date = d.getDate();
      let month = months[d.getMonth()-1];
      let year = d.getFullYear();

      return `${day} ${date} ${month} ${year}`;
    }
  }
  
}
</script>

 

 

<style>

<style>
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body{
  font-family: 'montserrat', sans-serif;
}

#App{
  background-image: url('./assets/cold-bg.jpg');
  background-color: aquamarine;
  background-size: cover;
  background-position: bottom;
  transition: 0.4s;
}

#App.warm {
  background-image: url('./assets/warm-bg.jpg');
}

main{
  min-height: 100vh;
  padding: 25px;

  background-image: linear-gradient(to bottom, rgba(0,0,0,0.25), rgba(0,0,0,0.75));
}

.search-box{
  width: 100%;
  margin-bottom: 30px;
}

.search-box .search-bar {
  display:block;
  width: 100%;
  padding: 15px;

  color: #313131;
  font-size:20px;

  appearance: none;
  border: none;
  outline: none;
  background: none;

  box-shadow: 0px 0px 8px rgba(0,0,0,0.25);
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 0px 16px;
  transition: 0.4s;
}

.search-box .search-bar:focus{
  box-shadow: 0px 0px 16px rgba(0,0,0,0.25);
  background-color: rgba(255, 255, 255, 0.75);
  border-radius: 16px 0px;
}

.location-box .location {
  color: #FFF;
  font-size: 32px;
  font-weight: 500;
  text-align: center;
  text-shadow: 1px 3px rgba(0,0,0,0.25);
}

.location-box .date {
  color: #FFF;
  font-size: 20px;
  font-weight: 300;
  font-style: italic;
  text-align: center;
}

.weather-box {
  text-align: center;
}

.weather-box .temp{
  display: inline-block;
  padding: 10px 25px;
  color: #FFF;
  font-size: 102px;
  font-weight: 900;

  text-shadow: 3px 6px rgba(0,0,0,0.25);
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 16px;
  margin: 30px 0px;

  box-shadow: 3px 6px rgba(0,0,0,0.25);
}

.weather-box .weather {
  color: #FFF;
  font-size: 48px;
  font-weight: 700;
  font-style: italic;
  text-shadow: 3px 6px rgba(255, 255, 255, 0.25);
}
</style>

 

 

결과물입니다.

도시명을 작성하면 해당되는 api를 가져와 띄워줍니다.

 

아프리카는 28도네요 ㄷㄷ

 

이상입니다.

 

무료 기상 API 주소 입니다. 개발 공부에 참고하세요!!

 

Сurrent weather and forecast - OpenWeatherMap

Access current weather data for any location on Earth including over 200,000 cities! The data is frequently updated based on the global and local weather models, satellites, radars and a vast network of weather stations. how to obtain APIs (subscriptions w

openweathermap.org

클릭 시 새 창으로 이동 

 

반응형

안녕하세요 상훈입니다.

 

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

 

Vue.js , API, Fetch(), 비동기 통신 간에 에러가 발생하였습니다. 

 

이 에러가 처음에는 제가 오타를 내서 발생한 에러인줄 알았으나(근데 오타도 있었음), 

오타의 문제가 아니었습니다.

 

1. F12 -> Network 를 확인해주세요.

2. api를 가져올 때 주소를 잘못 작성한 것을 저는 확인하였습니다. 

HTTPS:// 를 붙여주지 않아 인터넷 접속을 하지 않고 발생한 에러

그리고 다시 url_base를 사용하니 원활히 출력되었습니다!

 

F12-Network 에서 `200 status`로 잘 얻어왔습니다.

주소 주의하세욤..

vue.js - weather clone-coding ing... 

 

 

이상입니다.

참고

 

React Js: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

I want to fetch my Json file in react js, for this I am using fetch. But it shows an error Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 What could be the error,...

stackoverflow.com

 

반응형

form
HTML5이후로 action을 작성하지 않아도 된다.
GET 방식과 POST방식이 있다.

====================
input : file

form에 enctype : multipart/form-data 를 무조건 추가.
=> 
form의 method = 무조건 post.
=> contents 를 주소로 보낼 수 없음

HTMLInputElement.files 속성은 선택한 파일(File) 목록을 FileList 객체로 반환합니다.

FileList는 배열처럼 행동하므로, 
length 속성을 사용해 현재 선택한 파일의 수를 알 수 있습니다.

name
파일 이름.
lastModified
파일을 마지막으로 수정한 시각을 나타내는 숫자. UNIX 표준시(1970년 1월 1일 자정)으로부터 지난 시간을 밀리초 단위로 나타낸 값입니다.
lastModifiedDate 
파일을 마지막으로 수정한 시각을 나타내는 Date 객체. 더 이상 사용하지 않아야 합니다. lastModified를 대신 사용하세요.
size
파일의 크기를 바이트 단위로 나타낸 값.
type
파일의 MIME 유형.
webkitRelativePath 
webkitdirectory 특성을 사용한 경우, 기준 디렉토리에 대한 파일의 상대적인 경로. 비표준 특성이므로 사용에 주의가 필요합니다.

accept 특성

반응형

+ Recent posts