Skip to content

Vuetify

Vuetify Packages (list)

  • Vuetify.js
  • $vuetify
  • internationalization
  • v-alert
  • v-app
  • v-app-bar
  • v-app-bar-nav-icon
  • v-app-bar-title
  • v-autocomplete
  • v-avatar
  • v-badge
  • v-banner
  • v-bottom-navigation
  • v-bottom-sheet
  • v-breadcrumbs
  • v-breadcrumbs-divider
  • v-breadcrumbs-item
  • v-btn
  • v-btn-toggle
  • v-calendar
  • v-calendar-daily
  • v-calendar-monthly
  • v-calendar-weekly
  • v-card
  • v-card-actions
  • v-card-subtitle
  • v-card-text
  • v-card-title
  • v-carousel
  • v-carousel-item
  • v-carousel-reverse-transition
  • v-carousel-transition
  • v-checkbox
  • v-chip
  • v-chip-group
  • v-click-outside
  • v-col
  • v-color-picker
  • v-combobox
  • v-container
  • v-content
  • v-data-footer
  • v-data-iterator
  • v-data-table
  • v-data-table-header
  • v-date-picker
  • v-dialog
  • v-dialog-bottom-transition
  • v-dialog-top-transition
  • v-dialog-transition
  • v-divider
  • v-edit-dialog
  • v-expand-transition
  • v-expand-x-transition
  • v-expansion-panel
  • v-expansion-panel-content
  • v-expansion-panel-header
  • v-expansion-panels
  • v-fab-transition
  • v-fade-transition
  • v-file-input
  • v-flex
  • v-footer
  • v-form
  • v-hover
  • v-icon
  • v-img
  • v-input
  • v-intersect
  • v-item
  • v-item-group
  • v-layout
  • v-lazy
  • v-list
  • v-list-group
  • v-list-item
  • v-list-item-action
  • v-list-item-action-text
  • v-list-item-avatar
  • v-list-item-content
  • v-list-item-group
  • v-list-item-icon
  • v-list-item-subtitle
  • v-list-item-title
  • v-main
  • v-menu
  • v-menu-transition
  • v-mutate
  • v-navigation-drawer
  • v-overflow-btn
  • v-overlay
  • v-pagination
  • v-parallax
  • v-progress-circular
  • v-progress-linear
  • v-radio
  • v-radio-group
  • v-range-slider
  • v-rating
  • v-resize
  • v-responsive
  • v-ripple
  • v-row
  • v-scale-transition
  • v-scroll
  • v-scroll-x-reverse-transition
  • v-scroll-x-transition
  • v-scroll-y-reverse-transition
  • v-scroll-y-transition
  • v-select
  • v-sheet
  • v-simple-checkbox
  • v-simple-table
  • v-skeleton-loader
  • v-slide-group
  • v-slide-item
  • v-slide-x-reverse-transition
  • v-slide-x-transition
  • v-slide-y-reverse-transition
  • v-slide-y-transition
  • v-slider
  • v-snackbar
  • v-spacer
  • v-sparkline
  • v-speed-dial
  • v-stepper
  • v-stepper-content
  • v-stepper-header
  • v-stepper-items
  • v-stepper-step
  • v-subheader
  • v-switch
  • v-system-bar
  • v-tab
  • v-tab-item
  • v-tab-reverse-transition
  • v-tab-transition
  • v-tabs
  • v-tabs-items
  • v-tabs-slider
  • v-text-field
  • v-textarea
  • v-theme-provider
  • v-time-picker
  • v-timeline
  • v-timeline-item
  • v-toolbar
  • v-toolbar-items
  • v-toolbar-title
  • v-tooltip
  • v-touch
  • v-treeview
  • v-virtual-scroll
  • v-window
  • v-window-item

Material Component Framework for Vue.js 2

Categories

Dark theme

기본 설정은 라이트 테마이며 dark 속성을 추가하여 변경할 수 있다.

// src/plugins/vuetify.js

import Vue from 'vue'
import Vuetify from 'vuetify/lib'

Vue.use(Vuetify)

export default new Vuetify({
  theme: { dark: true },
})

Presets

다음 명령으로 추가할 수 있다.

  • vue add vuetify-preset-basil
  • vue add vuetify-preset-crane
  • vue add vuetify-preset-fortnightly
  • vue add vuetify-preset-owl
  • vue add vuetify-preset-rally
  • vue add vuetify-preset-reply
  • vue add vuetify-preset-shrine

TypeScript 코딩 준비

Vue#TypeScript 코딩 준비를 우선적으로 적용.

컴포넌트 임포트 에러 해결 방법

다음과 같이 임포트시

import VForm from 'vuetify/lib/components/VForm';

다음과 같은 에러가 출력된다면:

TS7016: Could not find a declaration file for module 'vuetify/lib/components/VForm'. '/home/your/Project/answer-plugin-vms/fe/node_modules/vuetify/lib/components/VForm/index.js' implicitly has an 'any' type.   If the 'vuetify' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module 'vuetify/lib/components/VForm';`

tsconfig.json의 컴파일러 옵션에 "noImplicitAny": false를 추가해야 한다.

{
  "compilerOptions": {
    "skipLibCheck": true,
    "noImplicitAny": false,
    "typeRoots": [
      "node_modules/@types",
      "node_modules/vuetify/types"
    ],
    "types": ["vuetify"]
  }
}

Layouts

Vuetify에는 v-appv-main의 두 가지 기본 레이아웃 구성 요소가 있습니다. v-app 구성 요소는 애플리케이션의 루트이며 기본 Vue 진입점인 <div id="app">를 직접 대체합니다. v-main 구성 요소는 기본 HTML 요소와 애플리케이션 콘텐츠의 루트에 대한 의미론적 대체입니다. Vue가 DOM에 마운트되면 레이아웃의 일부인 Vuetify 구성 요소는 현재 높이 및/또는 너비를 프레임워크 코어에 등록합니다. 그런 다음 v-main 구성 요소는 이러한 값을 가져와 컨테이너 크기를 조정합니다.

<v-app>
  <v-app-bar app></v-app-bar>

  <v-main>
    <v-container>
      Hello World
    </v-container>
  </v-main>
</v-app>

화면의 가로/세로 중심 배치

<template>
  <v-main>

    <!-- The card in the center of the screen. -->
    <v-container fluid class="fill-height">
      <v-row align="center" justify="center">
        <v-col class="max-content-width">

          <!-- Main Content -->
          <v-card>
              <!-- ... -->
          </v-card>

        </v-col>
      </v-row>
    </v-container>

  </v-main>
</template>

<style lang="scss" scoped>
.max-content-width {
  max-width: 480px;
}
</style>

그리고, 메인 컨텐츠는 최대 너비 480px로 적용된다.

Customizing item-text

다음과 같이, item의 요소로서 다음과 같이 사용할 수 있다.

:item-text="text"

매뉴얼에 따르면 다음과 같다.

item-text tye can be: string | array | function

따라서 다음과 같이 람다로 추가할 수도 있다.

methods: {
  text: item => item.name + ' — ' + item.description
}

SVG Path 직접 그리는 방법

@mdi/js 와 같은 패키지를 다운받으면 v-icon 컴포넌트를 사용해 그리는데, 직접 컴포넌트를 그린다면 다음과 같이 그리면 된다.

<template>
          <svg class="grid-view--table-body-row-drag"
               xmlns="http://www.w3.org/2000/svg"
               viewBox="0 0 24 24"
               role="img"
               aria-hidden="true"
          >
            <path :d="icons.dragVertical"></path>
          </svg>
</template>

<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
import {mdiDragVertical} from '@mdi/js';

@Component
export default class GridView extends Vue {
  readonly icons = {
    dragVertical: mdiDragVertical
  };
}
</script>

<style lang="scss" scoped>
.grid-view--table-body-row-drag {
  width: 10px;
  height: 32px;
  fill: currentColor;
}
</style>

색상의 악센트 추가하는 방법

deep-purple accent-4와 같이 색상 이름 이후, 공백을 주고 악센트 레벨을 주면 된다:

<v-progress-linear color="deep-purple accent-4"></v-progress-linear>

테마에 자동으로 변경되는 커스텀 스타일 적용 방법

스타일 적용

그냥 템플릿에 style 속성을 바인딩 하여 직접 색상을 지정할 수 있다. 가장 좋지 않은 방법이다.

<template>
  <div class="fill-width" :style="contentStyle"></div>
</template>

<script lang="ts">
import {Vue, Component, Prop, Watch} from 'vue-property-decorator';

@Component
export default class ViewPort extends Vue {
  get contentStyle() {
    return {'background-color': '#ffffff'};
  }
}
</script>

Vuetify의 colors 클래스 사용 방법

vuetify/lib/util/colors를 import 하면 된다.

<template>
  <div class="fill-width" :style="contentStyle"></div>
</template>

<script lang="ts">
import {Vue, Component, Prop, Watch} from 'vue-property-decorator';
import colors from 'vuetify/lib/util/colors'

@Component
export default class ViewPort extends Vue {
  get contentStyle() {
    if (this.$vuetify.theme.dark) {
      return {'background-color': colors.grey.darken1};
    } else {
      return {'background-color': colors.grey.lighten5};
    }
  }
}
</script>

Vuetify의 styles.sass를 사용하는 방법

scss를 사용하여, $material-dark$material-light 에 있는 text.secondary 색상을 폰트 색상으로, 테마에 따라 적용하는 컴포넌트이다:

<template>
  <p class="text-subtitle-2 font-weight-bold mb-1" :class="textColorClass">
    <slot></slot>
  </p>
</template>

<script lang="ts">
import {Vue, Component, Prop} from 'vue-property-decorator';

@Component
export default class SubtitleBold extends Vue {
  @Prop({type: String})
  readonly value!: string;

  get textColorClass() {
    if (this.$vuetify.theme.dark) {
      return 'text-color-dark';
    } else {
      return 'text-color-light';
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~vuetify/src/styles/styles.sass';

.text-color-light {
  color: map-get(map-get($material-light, 'text'), 'secondary');
}

.text-color-dark {
  color: map-get(map-get($material-dark, 'text'), 'secondary');
}
</style>

CSS Selector 사용 방법

Vuetify의 v-app 문서를 보면 "응용 프로그램 변형 (dark/light)을 자식 구성 요소에 전파"1 한다고 나와있다. 저 v-app 은 최종 HTML은 다음과 같이 적용된다:

<div data-app="true" class="v-application v-application--is-ltr theme--dark" id="app">
   <!-- ... -->
</div>

그리고 Vuetify의 많은 구성요소(컴포넌트)는 다음과 같은 CSS Selector를 통해 배경색상이 전파된다:

.theme--dark.v-application {
    background: #121212;
    color: #FFFFFF;
}

눈여겨 볼 점은 theme--darktheme--light 클래스가, Vuetify의 다크테마(this.$vuetify.theme.dark) 참/거짓 여부에 따라 바뀐다.

따라서 위의, 클래스 셀렉터를 사용하여 하위 컴포넌트의 CSS Selector를 지정하면 된다.

<template>
  <div class="grid-view"></div>
</template>

<style lang="scss" scoped>
.grid-view {
}

.theme--light.v-application .grid-view {
  background: red;
}
.theme--dark.v-application .grid-view {
  background: blue;
}
</style>

이렇게 하면 javascript를 사용하지 않고 테마를 변경에 대한 특수화를 지정할 수 있다.

주의할 점은 다음과 같이 Deep Selector를 사용할 경우,

.theme--light.v-application::v-deep .grid-view {
  background: red;
}

다음과 같이 컴파일된다.

.theme--light.v-application[data-v-eb074e2a] .grid-view {
  background: red;
}

이렇게 되면, 루트 엘리먼트를 찾을 수 없으므로 Deep Selector를 사용해선 안된다.

참고로 Deep Selector를 사용하지 않으면 다음과 같이 컴파일된다.

.theme--light.v-application .grid-view[data-v-eb074e2a] {
  background: red;
}

Troubleshooting

TypeScript Error: Could not find a declaration file for module 'vuetify/lib’

TypeScript 적용시 아래와 같은 에러가 발생될 수 있다.

ERROR in C:/workspace/inhasite/general/ctlt_apply/english_clinic/src/plugins/vuetify.ts
2:21 Could not find a declaration file for module 'vuetify/lib'. 'C:/workspace/inhasite/general/ctlt_apply/english_clinic/node_modules/vuetify/lib/index.js' implicitly has an 'any' type.
  Try `npm install @types/vuetify` if it exists or add a new declaration (.d.ts) file containing `declare module 'vuetify/lib';`
    1 | import Vue from 'vue';
  > 2 | import Vuetify from 'vuetify/lib';
      |                     ^
    3 | import 'vuetify/src/stylus/app.styl';
    4 |
    5 | Vue.use(Vuetify, {
Version: typescript 3.2.2, tslint 5.11.0

tsconfig.json 파일의 compilerOptions.types"vuetify"를 추가하면 된다.

"compilerOptions": {
    "types": ["vuetify"],
}

Icon 출력 오류

우선, 종속성을 추가한다.

$ yarn add @mdi/font -D
// OR
$ npm install @mdi/font -D

vuetify.js 파일에 다음과 같이 수정한다.

import Vue from "vue";
import Vuetify from "vuetify/lib";
import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader

Vue.use(Vuetify);

export default new Vuetify({
  icons: {
    iconfont: 'mdi',
  },
});

언어 변경시 다른 컴포넌트의 언어 변경이 적용되지 않는 현상

Vue I18n#Troubleshooting 항목 참조.

v-text-fielderrorBuckets 이 언어 변경시 적용되지 않는 현상

v-text-field 항목 참조.

Using / for division is deprecated

: Using / for division is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($grid-gutter, 3)

More info and automated migrator: https://sass-lang.com/d/slash-div

63 │     'md': $grid-gutter / 3,
   │           ^^^^^^^^^^^^^^^^
    node_modules/vuetify/src/styles/settings/_variables.scss 63:11  @import
    node_modules/vuetify/src/styles/settings/_index.sass 1:9        @import
    node_modules/vuetify/src/styles/styles.sass 2:9                 @import
    node_modules/vuetify/src/components/VIcon/_variables.scss 1:9   @import
    node_modules/vuetify/src/components/VIcon/VIcon.sass 2:9        root stylesheet

Quick fix devDependencies in package.json:

  • "sass": "~1.32.8"
  • "sass-loader": "10"

Translation key "dataTable.ariaLabel.****" not found in fallback

VDataTable 같은 컴포넌트를 사용할 때 위와 같은 경고가 브라우저에 출력된다면 Vuetify 플러그인 생성시 다음과 같이 초기화 한다:

import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';
import en from 'vuetify/lib/locale/en';
import ko from 'vuetify/lib/locale/ko';

Vue.use(Vuetify);

export default new Vuetify({
  lang: {
    locales: {en, ko},
    current: 'en',
  },
});

언어 변경은:

this.$vuetify.lang.current = this.$recc.lang;

vue-i18n의 언어변경과 다르므로 각각 해줘야 한다:

this.$i18n.locale = this.$recc.lang;

See also

Favorite site

Guide

Reference