반응형
Access to XMLHttpRequest at 'http://localhost:3000/memos' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

CORS오류 NodeJS에서 해결하는 방법 말고 Vue3에서는 proxy로 해결하는 방법이 있습니다.

 

 

해결방법

 

vue.config.js ( 없으면 생성해줍니다. 프로젝트 최상단 )

module.exports = {
  devServer: {
    proxy: {
      "/api": {
        target: "http://localhost:3000",
        changeOrigin: true
      }
    }
  }
}

 

vue

setup() {
    const url = '/api';
    
    axios.get(url + '/memos')
    .then(res => {
        console.log(res);
    })
}

 

반응형
반응형
Parsing error: No Babel config file detected for /Users/junhyeok/project/new/vue_crud/frontend/src/components/Main/MainComponent.vue. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files

Vue3 파싱 오류입니다. eslint에서 인식하는 부분에서 나타나는 오류거나, 프로젝트 루트 디렉토리에 .eslintrc.json파일이 없으면 ESLint가 작업 디렉토리를 자동으로 찾지 못할 수 있다고 합니다.

 

 

해결방법

F1 -> setting -> 드래그 내용을 추가합니다.

"eslint.workingDirectories": [
    {"mode": "auto"}
],
반응형
반응형

vuejs.github.io 가이드 바로가기

 

[vue/no-multiple-template-root]
The template root requires exactly one element.eslint-plugin-vue

 

Vue3로 프로젝트를 생성하고 section을 하나 만들었더니 위같은 오류가 발생했습니다.

 

찾아보니 Vetur는 기본적으로 package.json을 찾을 수 없기 때문에 vue 버전을 파악하지 못해서 생기는 오류라고 합니다.

그래서 Vetur에 package.json 위치를 알리기 위해 아래와 같은 방법을 사용한다고 합니다.

 

 

해결방법

프로젝트 내에 vetur.config.js 파일을 생성합니다.

생성한 파일 안에 아래 코드를 넣어줍니다.

그리고 에디터를 재실행해줍니다.

// vetur.config.js
/** @type {import('vls').VeturConfig} */
module.exports = {
    // **optional** default: `{}`
    // override vscode settings
    // Notice: It only affects the settings used by Vetur.
    settings: {
      "vetur.useWorkspaceDependencies": true,
      "vetur.experimental.templateInterpolationService": true
    },
    // **optional** default: `[{ root: './' }]`
    // support monorepos
    projects: [
        './packages/repo2', // Shorthand for specifying only the project root location
        {
            // **required**
            // Where is your project?
            // It is relative to `vetur.config.js`.
            root: './packages/repo1',
            // **optional** default: `'package.json'`
            // Where is `package.json` in the project?
            // We use it to determine the version of vue.
            // It is relative to root property.
            package: './package.json',
            // **optional**
            // Where is TypeScript config file in the project?
            // It is relative to root property.
            tsconfig: './tsconfig.json',
            // **optional** default: `'./.vscode/vetur/snippets'`
            // Where is vetur custom snippets folders?
            snippetFolder: './.vscode/vetur/snippets',
            // **optional** default: `[]`
            // Register globally Vue component glob.
            // If you set it, you can get completion by that components.
            // It is relative to root property.
            // Notice: It won't actually do it. You need to use `require.context` or `Vue.component`
            globalComponents: [
            './src/components/**/*.vue'
            ]
        }
    ]
}
반응형
반응형
ERROR  ~/.vuerc may be outdated. Please delete it and re-run vue-cli in manual mode.

 

Vue3로 프로젝트를 새로 만드려고 하는데 갑작스레 이런 오류가 발생했습니다.

 

에러 내용에서 vue-cli가 오래되었다고 해서 vue-cli vue 등등 제거하고, 캐시까지 지우고 나서 다시 깔았는데도 문제는 사라지지 않았습니다.

그래서 .vuerc 파일을 지우고 vue 프로젝트를 생성해보니 정상 작동되는 것을 확인할 수 있었습니다.

 

 

해결방법

.vuerc가 있는 폴더로 이동해 .vuerc를 제거 -> 다시 프로젝트 생성합니다.

반응형
반응형

data.js

const main = [
    {
        num: '01',
        title: 'Section1',
        description: '내용 입력하기',
        href: '#article1'
    },
    {
        num: '02',
        title: 'Section2',
        description: '내용 입력하기',
        href: '#article2'
    },
    {
        num: '03',
        title: 'Section3',
        description: '내용 입력하기',
        href: '#article3'
    },
    {
        num: '04',
        title: 'Section4',
        description: '내용 입력하기',
        href: '#article4'
    },
    {
        num: '05',
        title: 'Section5',
        description: '내용 입력하기',
        href: '#article5'
    },
    {
        num: '06',
        title: 'Section6',
        description: '내용 입력하기',
        href: '#article6'
    },
    {
        num: '07',
        title: 'Section7',
        description: '내용 입력하기',
        href: '#article7'
    },
    {
        num: '08',
        title: 'Section8',
        description: '내용 입력하기',
        href: '#article8'
    },
    {
        num: '09',
        title: 'Section9',
        description: '내용 입력하기',
        href: '#article9'
    },
];

export default main

 

 

View.vue ( views )

<script setup>
import Header from '@components/Main/Header.vue'
import main from '@/assets/js/data.js'

</script>

<template>

    <Header />
    
    <section id="parallax_contents">
        <article :id="'article' + (index + 1)" class="content_item" v-for="(item, index) of main" :key="'a' + index">
            <span class="content_item_num">{{item.num}}</span>
            <h2 class="content_item_title">{{item.title}}</h2>
            <figure class="content_item_img_wrap">
                <div class="content_item_img"></div>
            </figure>
            <p class="content_item_description">{{item.description}}</p>
        </article>
        <!-- // article1 -->
    </section>
</template>

<style lang="scss" scoped>
    #parallax_contents {
        width: 100%;
        max-width: 1600px;
        margin: 0 auto;
        overflow: hidden;
        font-family: 'NEXONLv1Gothic';
        font-weight: 400;
    }
    .content_item {
        position: relative;
        width: 100%;
        max-width: 70vw;
        margin: 10vw 0;
        text-align: right;
        padding-top: 10vw;
        &:nth-child(even) {
            margin-left: auto;
            text-align: left;
            .content_item_num {
                right: auto;
                left: -5vw;
            }
            .content_item_description {
                margin-right: 0;
                margin-left: -3vw;
            }
        }
        &:nth-child(1) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(2) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(3) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(4) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(5) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(6) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(7) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(8) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
        &:nth-child(9) .content_item_img {
            background-image: url(https://images.unsplash.com/photo-1653559260394-ee10e61e0155?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80);
        }
    }
    .content_item_num {
        position: absolute;
        font-size: 25vw;
        font-family: 'Lato';
        opacity: 0.07;
        right: -5vw;
        top: -5vw;
    }
    .content_item_title {
        padding-bottom: 1vw;
        font-size: 2vw;
    }
    .content_item_img_wrap {
        position: relative;
        width: 100%;
        padding-bottom: 56%;
        background-color: #000;
    }
    .content_item_img {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-repeat: no-repeat;
        background-size: cover;
        filter: saturate(0%);
        transition: all 1s;
        &:hover {
            filter: saturate(100%);
        }
    }
    .content_item_description {
        position: relative;
        font-size: 4vw;
        line-height: 1.5;
        word-break: keep-all;
        margin-top: -6vw;
        margin-right: -3vw;
        z-index: 1;
    }
</style>

 

Header.vue ( component )

<script setup>
import main from '@/assets/js/data.js'

</script>
<template>
    <nav class="parallax_nav">
        <ul>
            <li v-for="(item, index) of main" :key="'a' + index" ><a :href="item.href" v-smooth-scroll>{{item.num}}</a></li>
        </ul>
    </nav>
</template>

<style lang="scss" scoped>
    a {
        text-decoration: none;
        color: #FFF;
    }
    .parallax_nav {
        position: fixed;
        top: 0;
        right: 0;
        width: 100%;
        overflow: hidden;
        transition: all 1s;
        z-index: 100;
        > ul {
            position: relative;
            top: 0px;
            transition: all 1s;
            display: flex;
            padding: 20px;
            background-color: #D2D2D2;
            > li {
                width: 40px;
                height: 40px;
                line-height: 40px;
                text-align: center;
                border-radius: 50%;
                margin-right: 10px;
                font-size: 16px;
                font-weight: 700;
            }
            .active { background-color: #FFF; a { color: #222; } }
        }
        .list_active { top: 0px; }
    }
    .hide {
        top: -100px;
    }
</style>

<script>
    export default {
        mounted() {
            window.addEventListener("scroll", scrollProgress);
        }
    }


    let nowScrollTop;
    let lastScrollTop = 0;

    function scrollProgress(){
        nowScrollTop = true;

        setTimeout(() => {
            if(nowScrollTop) {
                nowScrollTop = false;
                hasScroll();
            }
        }, 100);
    }

    function hasScroll() {
        let scrollTop = document.documentElement.scrollTop || window.scrollY || window.pageYOffset;

        if(scrollTop > lastScrollTop){
            document.querySelector(".parallax_nav").classList.add("hide");
        } else {
            document.querySelector(".parallax_nav").classList.remove("hide");
        }

        lastScrollTop = scrollTop;

    };

    
</script>

 

반응형
반응형

id값에 변수 추가하기

<div :id="'id명' + (index + 1)" v-for="(item, index) of main" :key="'a' + index"></div>

 

실제 예

<div :id="'box' + (index + 1)" v-for="(item, index) of main" :key="'a' + index"></div>
<!-- id="box1" -->

<div :id="'box' + index + 1" v-for="(item, index) of main" :key="'b' + index"></div>
<!-- id="box01" -->

<div :id="'box' + index" v-for="(item, index) of main" :key="'c' + index"></div>
<!-- id="box0 -->

1번부터 나오게 하기 위해서 첫번째처럼 괄호를 써서 표현을 했습니다.

 

:key값을 문자열을 추가하여 표기한 이유 바로가기

 

반응형
반응형

vite vue에서 js파일을 내보내는데 문제가 생겼다.

vue나 Nuxt에서 js파일을 내보낼때 module.exports로 내보낼수가 있었는데 vite에서는 module.exports로 내보내기가 작동하지 않았다.

 

:: 해결방법

Vite에서의 내보내기 ( export )

const array = [
    {
        num: 1,
        title: '내용'
    },
    {
        num: 2,
        title: '내용'
    },
    {
        num: 3,
        title: '내용'
    },
]

const array2 = [
    {
        num: 1,
        title: '내용'
    },
    {
        num: 2,
        title: '내용'
    },
    {
        num: 3,
        title: '내용'
    },
]

// 기본 내보내기
export default array

// 여러 변수를 내보내기
export { array, array2 }

 

Vite에서의 받기 ( import )

// 하나만 내보낸걸 받을 때
import array from '경로'

// 여러 변수를 내보낸걸 받을 때
import { array, array2 } from '경로'

 


 

Vue, Nuxt에서의 내보내기 ( export )

const array = [
    {
        num: 1,
        title: '내용'
    },
    {
        num: 2,
        title: '내용'
    },
    {
        num: 3,
        title: '내용'
    },
]

module.exports = {
    array: array
}

 

반응형
반응형

vue youtube 바로가기

 

npm install

$ npm install vue-youtube

 

js [ vue-youtube.js 생성 ]

import Vue from 'vue'
import VueYoutube from 'vue-youtube/dist/vue-youtube'

Vue.use(VueYoutube)

 

.vue

<youtube :video-id="videoId" :player-vars="playerVars" @playing="playing"></youtube>

 

script

data() {
    return {
      videoId: 'lG0Ys-2d4MA',
      playerVars: {
      	autoplay: 1
      }
    }
},
methods: {
    playing() {
      console.log('\o/ we are watching!!!')
    }
},

 

반응형
반응형

Props란 ?

부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용되는 단방향 데이터 전달 방식이다.

 

 

App.vue ( 부모 컴포넌트 )

html

<template>
  <input type="text" v-model="callProps" />
  <Header :msg="callProps" />
</template>

script

import Header from '@components/Main/Header.vue'
import { ref } from 'vue'

export default {
  data() {
    const callProps = ref('Hello')

    return {
      callProps
    }
  }
}

 

Header.vue ( 자식 컴포넌트 )

html

<template>
    <h1>자식 컴포넌트 확인하기</h1>
    <div>{{msg}}</div>
</template>

script

export default {
    props: {
        msg: String
    }
}

 

부모 컴포넌트(App.vue)에 input창에 텍스트를 입력하면 :msg="callProps"를 통해서 자식 컴포넌트로 보내지고 자식 컴포넌트(Header.vue)에 props를 통해 텍스트가 전달된다.

 

반응형
반응형

v-bind 디렉티브 : 단방향 결합을 지원

v-model 디렉티브 : 양방향 결합을 지원

 

단방향 결합 => 변수의 값이 템플릿으로만 결합되어 템플릿의 HTML태그가 변경한 값이 변수에 돌아오지 않는다.

양방향 결합 => 변수의 변경이 템플릿의 DOM에 영향을 미치는 것은 물론이고, 템플릿에서의 변경이 변수의 값을 변경시키기도 한다.

 

<template>
    <div>
        <input type="text" :value="abbr" />
        <input type="text" v-model="normal" />

        <hr />

        <abbr :title="normal">{{abbr}}</abbr>
        <br />
        <abbr :title="abbr">{{normal}}</abbr>
    </div>
</template>
import { ref } from 'vue'

export default {
    setup() {
        const abbr = ref('Project1')
        const normal = ref('Project2')
        return {
            abbr,
            normal
        }
    }
}

vue에서 먼저 ref 컴포지션 API함수를 불러왔다. setup함수는 Options API와는 다르게 반응형 변수를 선언하기 위해서는 ref함수로 값을 한번 감싸줘야 한다.

반응형

+ Recent posts