본문으로 건너뛰기

"vue" 태그로 연결된 9개 게시물개의 게시물이 있습니다.

모든 태그 보기

vee-validate3 모든 규칙 추가시 TS7053 오류

· 약 2분

3.0 버전이 되면서 HOC 기반으로 변경되며 rules를 상위 컴포넌트에서 확장하게 되었다. 문제는 typescript 기반에서 룰 전체 등록이 TS(7053) 에러를 발생시킨다.

import { ValidationProvider, ValidationObserver, extend } from "vee-validate";
import * as rules from "vee-validate/dist/rules";

Object.keys(rules).forEach((rule) => {
extend(rule, rules[rule]); // rules[rule] 에서 타입오류 발생
});
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof import(".../node_modules/vee-validate/dist/rules")'.
No index signature with a parameter of type 'string' was found on type 'typeof import(".../node_modules/vee-validate/dist/rules")'.ts(7053)

원인

import, export 의 모듈명은 string index 로 쳐지지 않아 발생한다.

해결방법

Object.entriesfor of를 사용해 타입에 안전하게 돌려주면 된다.

import { extend } from "vee-validate";
import * as rules from "vee-validate/dist/rules";

for (const [rule, validation] of Object.entries(rules)) {
extend(rule, {
...validation,
});
}

여담

  • 새로운 구문 (async/await, import/export)를 사용해 돌릴 땐 먼저 for of를 사용하는 습관을 들여야겠다.
  • 머지되어서 다음 사람의 삽질은 없을 듯 하다.

참조

Nuxt에 ThirdParty js (particles.js) 추가하기

· 약 3분

Nuxt Project 에 Particles.js 를 붙히고 싶었다. 어떻게하면 쉽게 붙힐 수 있을까 하다가 멀리 돌아오게 된 삽질기다.

시작

vue-plugin 사용

공식 문서 를 봤었고 Vue Plugin일 경우 너무나 쉽게 추가가 가능한 것처럼 보였다. 얼른 vue-particles 를 설치하고 플러그인을 만들어 등록했다.

만들고

vue-particles.js
import Vue from "vue";
import VueParticles from "vue-particles";

Vue.use(VueParticles);

등록했다.

nuxt.config.js
module.exports = {
plugins: ["~/plugins/vue-particles"],
};

그런데 화면에 Particle이 보이지 않는다.

no-ssr

구글링을 하니, 플러그인에 no-ssr 옵션을 주면 해결이 된다고 한다.

nuxt.config.js
module.exports = {
plugins: [
{
src: "~/plugins/vue-particles",
ssr: false,
},
],
};
Particles.vue
<template>
<no-ssr>
<vue-particles />
</no-ssr>
</template>

대충 이런식으로 코딩했더니 화면에서 볼 수 있게 되었다.

그런데... IE11에서는 스크립트 오류가 발생하기 시작했다.

IE 오류

vue-particles 자체에 const 구문을 사용하고 있기 때문에, no-ssr 옵션을 준다면 번들링 시 로직을 건너 뛰기에, 크롬에서는 실행이 되지만 IE에서는 실행되지 않는 치명적인 오류가 발생했다.

그래서 다른 방법을 시도해봤다.

script 삽입하기

nuxt.config.js 에서 head 태그를 이용하면 스크립트를 추가할 수 있고, window.particlesJS 처럼 전역 변수로 참조하면 될 줄 알았다.

하지만 번들링 시 window 객체가 없어 aframe 벤더가 필요하다고 오류가 발생했다. 쓸데 없는 리소스를 추가해야되니 여기서 멈추었다.

해결

process.browser

window-document-undefined 문서에 따르면 이런 참조 문제를 해결할 수 있다고 한다.

Particles.vue
<template>
<vue-particles />
</template>
<script>
if (process.browser) {
require("vue-particles");
}

export default {
mounted() {
if (window.particlesJS) {
window.particlesJS.load();
}
},
};
</script>

위와 같이 로직을 변경해주니 IE11 에서도 정상 작동하였다.

여담

vue-particles 의 문서엔 완벽한 nuxt 호환이라 되어있지만 예외적인 상황이 있는 듯 하다.

Vue - Laravel Pagination 연동

· 약 2분

Laravel에서 paginate 메소드를 json으로 받았을 시에 데이터는 다음과 같다.

response
{
"current_page": 1,
"data": [{}, {}, {}],
"from": 1,
"last_page": 1,
"next_page_url": null,
"path": "https://example.com/ajax/list",
"per_page": 15,
"prev_page_url": null,
"to": 8,
"total": 8
}

이 데이터를 blade에서 links 메소드로 쉽게 사용할 수 있는 것 처럼 Vue에서도 그럴 수는 없을까?

Laravel Vue Pagination 패키지를 활용하면 된다. SPA일 경우에는 다운 받고 Usage 탭에 적힌대로 바로 사용하면 되지만, Multi Page일경우는 직접 컴포넌트를 가져와야한다.

<ul>
<li v-for="post in response.data" v-text="post.title"></li>
</ul>

<nav>
<pagination
:data="response"
:limit="3"
@pagination-change-page="fetchPosts"
/>
</nav>

<script>
new Vue({
data: {
response: {
data: [],
},
},

methods: {
fetchPosts: function (page) {
var vm = this;
axios
.get("url", {
params: {
page: page || 1,
},
})
.then(function (response) {
vm.response = response;
});
},
},
});
</script>

예외처리

Component 소스template 부분을 보면 nav로 감싸져있지 않기에 Laravel 기본 템플릿과 일치시키려면 nav 태그로 감싸주면 된다.

Vue로 생성된 DOM에 Events를 붙여야할 때

· 약 1분

data 값이 변경되고 나서 .hover, .click과 같은 jQuery 이벤트를 붙여야할 때, DOM이 다시 그려진 완료 시점을 잡아야한다. Vue에서 nextTick 메소드로 이 시점을 잡을 수 있다. (ajax로 데이터를 가져오지 않고 그려지는 DOM은 mounted 메소드 안에 붙힐 Event 로직을 짜면 된다.)

new Vue({
data: {
members: [],
},

created: function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const vm = this;

axios
.get("/members")
.then(function (response) {
vm.members = response.data;

/* promise가 지원되는 환경에서 */
return vm.$nextTick();

// promise 미지원시
/* vm.$nextTick(function() {
$('.members').hover();
});
*/
})
.then(function () {
$(".members").hover();
});
},
});

인스턴스 메소드를 사용하고 싶지 않다면 Vue.nextTick으로 바꿔주면 된다.

Vue 선언된 data에 chiledren 추가시 렌더링이 안될 때

· 약 2분

data가 이미 정의 되어있고 나중에 데이터를 추가하면 observer가 생성되지 않아 데이터가 갱신이 되어도 DOM이 업데이트가 안 된다.

템플릿

<div id="memberList">
<div v-for="member in members">
{{ member.name }}
<ul v-if="member.logs && member.logs.length > 0">
<li v-for="log in member.logs"></li>
</ul>
</div>
</div>

JS

new Vue({
el: "#memberList",
data: {
members: [{ id: 1, name: "gracefullight" }],
},

mounted: function () {
/* member의 logs 데이터는 그냥 배열로 선언된다. */
this.members[0].logs = [];
/* 데이터를 넣어도 위 템플릿의 <li> 부분이 반복되지 않는다. */
this.members[0].logs = [
{ id: 1, message: "test action", created_at: "2017-11-22" },
];
},
});

해결

set 메소드 또는 $forceUpdate 메소드를 사용하면 된다.

/* 1안 */
const option = {
mounted: function () {
this.$set(this.members[0], "logs", []);
this.members[0].logs = [
// ...
];
},
};
/* 2안 */
const option = {
mounted: function () {
this.members[0].logs = [];
this.members[0].logs = [
// ...
];
this.$forceUpdate();
},
};

Vue에서 jquery와 bootstrap 전역으로 사용하기

· 약 1분

expose-loader의 설치가 필요 없는 방법을 사용해보자

Vuejs-kr에 좋은 내용이 있지만 웹팩을 통해 jquery를 꺼내는 방법이 더 간단하다.

$ yarn add jquery bootstrap

설정

webpack

build/webpack.base.conf.js
const webpack = require("webpack");

module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jquery: "jquery",
"window.jQuery": "jquery",
jQuery: "jquery",
}),
],
};

eslint

.enlintrs.js
module.exports = {
globals: {
$: true,
jQuery: true,
},
};

연동

src/main.js
import "bootstrap";

new Vue({});

Vue multi page app에서 코드가 미리보이는 현상 제거

· 약 1분

뷰에 데이터가 바인딩 되기전 {{태그}} 구문이 보일 때 다음과 같이 하면 된다.

v-cloak api에 자세하게 나와있다.

<!-- vue가 바인딩 될 영역에 v-cloak attribute를 추가한다 -->
<div id="vue_area" v-cloak></div>
[v-cloak] {
display: none;
}

더 멋진 방법

로딩시에 content 영역에 loading...이라는 문구를 찍어주는 방법으로 여기에 자세히 설명되어있다.

[v-cloak] > * {
display: none;
}
[v-cloak]::before {
content: "loading...";
}

Vee-Validate Custom Validation

· 약 1분

커스텀 validation을 추가해야할 때가 있다. created에 $validator 인스턴스를 확장해주면 된다.

const option = {
created: function () {
this.$validator.extend("customRule", {
getMessage: function (field, args) {
return "오류 메세지";
},

validate: function (value, args) {
// 체크 로직
return true;
},
});
},
};

모듈형태거나 전역설정이면 import { Validator } from 'vee-validate'; 후에 Validator.extend로 접근하면 된다.

사용법

추가한 룰 이름으로 v-validate 속성에 넣어주면 끝이다.

<input type="text" name="help" v-validate="'required|customRule'" />

스크립트 상에서 추가

attach 메소드로 붙히면 된다.

this.$validator.attach("help", "customRule");

다른 사용법은 공식문서를 참조하자

Vue Developer Tools 켜기

· 약 1분

Devtools inspection is not available because it's in production mode 란 메세지와 함께 Vue 개발자 도구가 표시되지 않을 경우에 script 상단에 아래 구문을 추가한다.

Vue.config.devtools = true;

개발자 도구에 Vue 탭이 없을 때

ctrl+shift+i 키를 Vue 탭이 보일 때 까지 반복해서 눌러준다.