Vue에서 Vuetify를 사용하는 방법js

지금 http://jauyeung.net/subscribe/에 내 이메일 목록을 구독하십시오.
트위터에 팔로우 해주세요.
기사 더 보기 https://medium.com/@hohanga
기사 더 보기 http://thewebdev.info/
Vue에서는 Material Design에 대한 지지도가 높습니다.js.Vue에서 사용할 수 있는 라이브러리 중 하나입니다.js는Vuetify입니다.그것은 너의 Vue에 쉽게 녹아들는다.js 응용 프로그램의 결과가 사용자의 눈길을 끌었다.
본 논문에서 우리는 뉴욕타임스 API 데이터를 표시하는 응용 프로그램을 구축할 것이다.API 키는 https://developer.nytimes.com/에 등록할 수 있습니다.이후에 우리는 응용 프로그램을 구축할 수 있다.
애플리케이션 구축을 시작하려면 Vue CLI를 설치해야 합니다.우리는 다음과 같은 작업을 수행합니다.
npm install -g @vue/cli
노드Vue CLI를 실행하려면 js 8.9 이상 버전이 필요합니다.Windows 버전의 Node와 함께 Vue CLI를 실행하지 못했습니다.js.Ubuntu에서 Vue CLI를 실행하는 데 문제가 없습니다.
그런 다음 다음,
vue create vuetify-nyt-app
프로젝트 폴더를 만들고 파일을 만듭니다.마법사에서 기본 옵션 대신 수동 선택 기능을 선택합니다.스페이스 바를 눌러 옵션 목록에서 Babel, RouterVuex를 선택합니다.녹색이면 선택된 것입니다.
지금 우리는 몇 개의 라이브러리를 설치해야 한다.HTTP 클라이언트를 설치해야 합니다. 하나는 날짜를 포맷하는 라이브러리이고, 하나는 대상에서 GET 조회 문자열을 생성하는 데 사용되며, 다른 하나는 폼 검증에 사용됩니다.
그 밖에 우리는 Vue Material 라이브러리 자체를 설치해야 한다.우리는 다음과 같은 작업을 수행합니다.
npm i axios moment querystring vee-validate
axios는 저희 HTTP 클라이언트입니다. moment는 날짜를 처리하는 데 사용되고, querystring는 대상에서 조회 문자열을 생성하는 데 사용되며, vee-validate는 Vue의 추가 패키지입니다.js가 검증을 진행합니다.
그런 다음 템플릿 파일vuetify을 추가해야 합니다.우리는 운행vue add vuetify을 통해 이 점을 실현한다.이것은 저희 프로그램에서 라이브러리와 인용을 코드에 해당하는 위치에 추가합니다.
현재 우리는 이미 모든 라이브러리를 설치했기 때문에, 우리는 우리의 응용 프로그램을 구축하기 시작할 수 있다.
우선, 우리는 구성 요소를 만들 것이다.views 폴더에 Home.vueSearch.vue를 만듭니다.이것들은 우리 페이지의 코드 파일이다.그리고 mixins 폴더를 만들고 nytMixin.js라는 파일을 만듭니다.
mixin은 Vue에 직접 병합할 수 있는 코드 세그먼트입니다.구성 요소에 있는 것처럼 js 구성 요소를 사용합니다.그리고 필터를 추가합니다.
필터는 Vue입니다.한 가지 일에서 다른 일로 비치는 js 코드입니다.우리는 filters 폴더를 만들고 capitalize.jsformatDate.js를 추가합니다.components 폴더에 SearchResults.vue라는 파일을 만들었습니다.components 폴더에 Vue가 포함되어 있습니다.페이지의 js 구성 요소가 아닙니다.
구성 요소 간의 데이터 전달을 더욱 쉽고 조직적으로 하기 위해 우리는 Vuex를 사용하여 상태 관리를 한다.vue create를 실행할 때 Vuex를 선택했기 때문에 프로젝트 폴더에 store.js가 있어야 합니다.없으면 만듭니다.store.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    searchResults: []
  },
  mutations: {
    setSearchResults(state, payload) {
      state.searchResults = payload;
    }
  },
  actions: {}
})
state 객체는 스토리지 상태의 위치입니다.mutations 대상은 우리가 우리의 상태를 조종할 수 있는 곳이다.
코드에서 this.$store.commit(“setSearchResults”, searchResults)를 호출할 때 searchResults가 정의되었다고 가정하면 state.searchResultssearchResults로 설정됩니다.
그리고 우리는 this.$store.state.searchResults를 사용하여 결과를 얻을 수 있다.
응용 프로그램에 샘플 코드를 추가해야 합니다.우선 필터를 추가합니다.capitalize.js:
export const capitalize = (str) => {
    if (typeof str == 'string') {
        if (str == 'realestate') {
            return 'Real Estate';
        }
        if (str == 'sundayreview') {
            return 'Sunday Review';
        }
        if (str == 'tmagazine') {
            return 'T Magazine';
        }
        return `${str[0].toUpperCase()}${str.slice(1)}`;
    }
}
이것은 우리로 하여금 우리의 《뉴욕타임스》란의 이름을 대문자로 써서 New York Times developer pages에 열거할 수 있게 한다.그리고 formatDate.js에서 우리는 다음과 같이 주장했다.
import * as moment from 'moment';
export const formatDate = (date) => {
    if (date) {
        return moment(date).format('YYYY-MM-DD hh:mm A');
    }
}
우리의 날짜를 인간이 읽을 수 있는 형식으로 포맷합니다.main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { formatDate } from './filters/formatDate';
import { capitalize } from './filters/capitalize';
import VeeValidate from 'vee-validate';
import Vuetify from 'vuetify/lib'
import vuetify from './plugins/vuetify';
import '@mdi/font/css/materialdesignicons.css'
Vue.config.productionTip = false;
Vue.use(VeeValidate);
Vue.use(Vuetify);
Vue.filter('formatDate', formatDate);
Vue.filter('capitalize', capitalize);
new Vue({
  router,
  store,
  vuetify,
  render: h => h(App)
}).$mount('#app')
위의 파일에는 Vue에서 사용하는 라이브러리를 등록해야 합니다.Vue.usejs를 호출하면 프로그램 템플릿에서 사용할 수 있습니다.
우리는 변수 오른쪽에 파이프와 필터 이름을 추가하는 방법으로 필터 함수 Vue.filter 를 호출합니다.
그리고 router.js에서 우리는 다음과 같이 주장했다.
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue';
import Search from './views/Search.vue';
Vue.use(Router)
export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/search',
      name: 'search',
      component: Search
    }
  ]
})
이렇게 하면 나열된 URL을 입력할 때 페이지에 들어갈 수 있습니다.mode: ‘history’는 기본 URL과 라우팅 사이에 해시 기호가 없음을 나타냅니다.
만약 우리가 프로그램을 배치한다면, 모든 요청이 index.html 로 바뀌도록 웹 서버를 설정해야 합니다. 그러면 프로그램을 다시 불러올 때 오류가 발생하지 않습니다.
예를 들어, Apache에서는 다음을 수행합니다.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>
NGINX:
location / {
  try_files $uri $uri/ /index.html;
}
웹 서버에서 같은 조작을 어떻게 하는지에 대한 정보는 웹 서버의 문서를 참조하십시오.
현재, 우리는 우리의 구성 요소를 위해 코드를 작성합니다.SearchResult.vue:
<template>
  <v-container>
    <v-card v-for="s in searchResults" :key="s.id" class="mx-auto">
      <v-card-title>{{s.headline.main}}</v-card-title>
<v-list-item>
        <v-list-item-content>Date: {{s.pub_date | formatDate}}</v-list-item-content>
      </v-list-item>
      <v-list-item>
        <v-list-item-content>
          <a :href="s.web_url">Link</a>
        </v-list-item-content>
      </v-list-item>
      <v-list-item v-if="s.byline.original">
        <v-list-item-content>{{s.byline.original}}</v-list-item-content>
      </v-list-item>
      <v-list-item>
        <v-list-item-content>{{s.lead_paragraph}}</v-list-item-content>
      </v-list-item>
      <v-list-item>
        <v-list-item-content>{{s.snippet}}</v-list-item-content>
      </v-list-item>
    </v-card>
  </v-container>
</template>
<script>
export default {
  computed: {
    searchResults() {
      return this.$store.state.searchResults;
    }
  }
};
</script>
<style scoped>
.title {
  margin: 0 15px !important;
}
#search-results {
  margin: 0 auto;
  width: 95vw;
}
</style>
Vuex 스토어에서 검색 결과를 가져와 표시하는 곳입니다.
응용 프로그램 this.$store.state.searchResults 속성의 함수에서 computed 을 되돌려줍니다. 그러면 상점 searchResults 상태가 업데이트될 때 검색 결과가 자동으로 갱신됩니다.md-card는 상자에 데이터를 표시하는 데 사용되는 카드 소부품이다.v-for 순환 그룹 항목에 사용되며 모든 내용을 표시합니다.md-list는 목록의 항목을 페이지에 가지런히 표시하는 데 사용되는 목록의 작은 위젯입니다.{{s.pub_date | formatDate}}formatDate 필터를 사용하는 곳이다.
이어서 우리는 우리의 믹스를 썼다.Mixin에서 HTTP 호출에 코드를 추가합니다.nytMixin.js:
const axios = require('axios');
const querystring = require('querystring');
const apiUrl = 'https://api.nytimes.com/svc';
const apikey = 'your api key';
export const nytMixin = {
    methods: {
        getArticles(section) {
            return axios.get(`${apiUrl}/topstories/v2/${section}.json?api-key=${apikey}`);
        },
searchArticles(data) {
            let params = Object.assign({}, data);
            params['api-key'] = apikey;
            Object.keys(params).forEach(key => {
                if (!params[key]) {
                    delete params[key];
                }
            })
            const queryString = querystring.stringify(params);
            return axios.get(`${apiUrl}/search/v2/articlesearch.json?${queryString}`);
        }
    }
}
HTTP가 각 함수에서 기사를 가져오도록 요청한 약속을 반환합니다.searchArticles 함수에서 전송된 대상을 검색 문자열에 전달하고 요청에 전달합니다.
애플리케이션의 API 키를 상수apiKey에 배치하고 다음을 포함하여 정의되지 않은 항목을 삭제해야 합니다.
Object.keys(params).forEach(key => {
  if (!params[key]) {
     delete params[key];
  }
})
Home.vue:
<template>
  <div>
    <div class="text-center" id="header">
      <h1>{{selectedSection | capitalize}}</h1>
      <v-spacer></v-spacer>
      <v-menu offset-y>
        <template v-slot:activator="{ on }">
          <v-btn color="primary" dark v-on="on">Sections</v-btn>
        </template>
        <v-list>
          <v-list-item v-for="(s, index) in sections" :key="index" @click="selectSection(s)">
            <v-list-item-title>{{ s | capitalize}}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
      <v-spacer></v-spacer>
      <v-spacer></v-spacer>
    </div>
    <v-spacer></v-spacer>
    <v-card v-for="a in articles" :key="a.id" class="mx-auto">
      <v-card-title>{{a.title}}</v-card-title>
      <v-card-text>
        <v-list-item>
          <v-list-item-content>Date: {{a.published_date | formatDate}}</v-list-item-content>
        </v-list-item>
        <v-list-item>
          <v-list-item-content>
            <a :href="a.url">Link</a>
          </v-list-item-content>
        </v-list-item>
        <v-list-item v-if="a.byline">
          <v-list-item-content>{{a.byline}}</v-list-item-content>
        </v-list-item>
        <v-list-item>
          <v-list-item-content>{{a.abstract}}</v-list-item-content>
        </v-list-item>
        <v-list-item>
          <v-list-item-content>
            <img
              v-if="a.multimedia[a.multimedia.length - 1]"
              :src="a.multimedia[a.multimedia.length - 1].url"
              :alt="a.multimedia[a.multimedia.length - 1].caption"
              class="image"
            />
          </v-list-item-content>
        </v-list-item>
      </v-card-text>
    </v-card>
  </div>
</template>
<script>
import { nytMixin } from "../mixins/nytMixin";
export default {
  name: "home",
  mixins: [nytMixin],
  computed: {},
  data() {
    return {
      selectedSection: "home",
      articles: [],
      sections: `arts, automobiles, books, business, fashion, food, health,
    home, insider, magazine, movies, national, nyregion, obituaries,
    opinion, politics, realestate, science, sports, sundayreview,
    technology, theater, tmagazine, travel, upshot, world`
        .replace(/ /g, "")
        .split(",")
    };
  },
  beforeMount() {
    this.getNewsArticles(this.selectedSection);
  },
  methods: {
    async getNewsArticles(section) {
      const response = await this.getArticles(section);
      this.articles = response.data.results;
    },
  selectSection(section) {
      this.selectedSection = section;
      this.getNewsArticles(section);
    }
  }
};
</script>
<style scoped>
.image {
  width: 100%;
}
.title {
  color: rgba(0, 0, 0, 0.87) !important;
  margin: 0 15px !important;
}
.md-card {
  width: 95vw;
  margin: 0 auto;
}
#header {
  margin-bottom: 10px;
}
</style>
이 페이지 구성 요소는 우리가 선택한 부분의 글을 가져오는 곳입니다. 기본값은 home 부분입니다.다음 항목을 추가하여 보려는 섹션을 선택할 수 있는 메뉴도 있습니다.
<v-menu offset-y>
   <template v-slot:activator="{ on }">
     <v-btn color="primary" dark v-on="on">Sections</v-btn>
   </template>
   <v-list>
      <v-list-item v-for="(s, index) in sections" :key="index" @click="selectSection(s)">
        <v-list-item-title>{{ s | capitalize}}</v-list-item-title>
      </v-list-item>
   </v-list>
</v-menu>
약속 코드에서 asyncawait 키워드를 사용하지 않고 then 를 사용합니다.
그것은 훨씬 짧다. then, await, async 사이의 기능이 비슷하다.그러나 Internet Explorer에서는 지원되지 않습니다.beforeMount 블록에서 웹 페이지를 불러올 때 글을 얻기 위해 this.getNewsArticles를 실행합니다.
Vuetify 라이브러리는 Vue 기능의 슬롯을 사용합니다.광범히네스트된 요소(예: v-slot 도구)는 다음과 같습니다.
<v-menu offset-y>
  <template v-slot:activator="{ on }">
     <v-btn color="primary" dark v-on="on">Sections</v-btn>
  </template>
  <v-list>
    <v-list-item v-for="(s, index) in sections" :key="index" @click="selectSection(s)">
       <v-list-item-title>{{ s | capitalize}}</v-list-item-title>
     </v-list-item>
  </v-list>
</v-menu>
자세한 내용은 Vue.js guide를 참조하십시오.Search.vue:
<template>
  <div>
    <form>
      <v-text-field
        v-model="searchData.keyword"
        v-validate="'required'"
        :error-messages="errors.collect('keyword')"
        label="Keyword"
        data-vv-name="keyword"
        required
      ></v-text-field>
      <v-menu
        ref="menu"
        v-model="toggleBeginDate"
        :close-on-content-click="false"
        transition="scale-transition"
        offset-y
        full-width
        min-width="290px"
      >
        <template v-slot:activator="{ on }">
          <v-text-field
            v-model="searchData.beginDate"
            label="Begin Date"
            prepend-icon="event"
            readonly
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker
          v-model="searchData.beginDate"
          no-title
          scrollable
          :max="new Date().toISOString()"
        >
          <v-spacer></v-spacer>
          <v-btn text color="primary" @click="toggleBeginDate = false">Cancel</v-btn>
          <v-btn
            text
            color="primary"
            @click="$refs.menu.save(searchData.beginDate); toggleBeginDate = false"
          >OK</v-btn>
        </v-date-picker>
      </v-menu>
      <v-menu
        ref="menu"
        v-model="toggleEndDate"
        :close-on-content-click="false"
        transition="scale-transition"
        offset-y
        full-width
        min-width="290px"
      >
        <template v-slot:activator="{ on }">
          <v-text-field
            v-model="searchData.endDate"
            label="End Date"
            prepend-icon="event"
            readonly
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker
          v-model="searchData.endDate"
          no-title
          scrollable
          :max="new Date().toISOString()"
        >
          <v-spacer></v-spacer>
          <v-btn text color="primary" @click="toggleEndDate = false">Cancel</v-btn>
          <v-btn
            text
            color="primary"
            @click="$refs.menu.save(searchData.endDate); toggleEndDate = false"
          >OK</v-btn>
        </v-date-picker>
      </v-menu>
      <v-select
        v-model="searchData.sort"
        :items="sortChoices"
        label="Sort By"
        data-vv-name="sort"
        item-value="value"
        item-text="name"
      >
        <template slot="selection" slot-scope="{ item }">{{ item.name }}</template>
        <template slot="item" slot-scope="{ item }">{{ item.name }}</template>
      </v-select>
      <v-btn class="mr-4" type="submit" @click="search">Search</v-btn>
    </form>
    <SearchResults />
  </div>
</template>
<script>
import { nytMixin } from "../mixins/nytMixin";
import SearchResults from "@/components/SearchResults.vue";
import * as moment from "moment";
import { capitalize } from "@/filters/capitalize";
export default {
  name: "search",
  mixins: [nytMixin],
  components: {
    SearchResults
  },
  computed: {
    isFormDirty() {
      return Object.keys(this.fields).some(key => this.fields[key].dirty);
    }
  },
  data: () => {
    return {
      searchData: {
        sort: "newest"
      },
      disabledDates: date => {
        return +date >= +new Date();
      },
      sortChoices: [
        {
          value: "newest",
          name: "Newest"
        },
        {
          value: "oldest",
          name: "Oldest"
        },
        {
          value: "relevance",
          name: "Relevance"
        }
      ],
      toggleBeginDate: false,
      toggleEndDate: false
    };
  },
  methods: {
    async search(evt) {
      evt.preventDefault();
      if (!this.isFormDirty || this.errors.items.length > 0) {
        return;
      }
      const data = {
        q: this.searchData.keyword,
        begin_date: moment(this.searchData.beginDate).format("YYYYMMDD"),
        end_date: moment(this.searchData.endDate).format("YYYYMMDD"),
        sort: this.searchData.sort
      };
      const response = await this.searchArticles(data);
      this.$store.commit("setSearchResults", response.data.response.docs);
    }
  }
};
</script>
이것은 우리가 문장을 검색하는 데 쓰이는 표다.우리는 시작과 끝 날짜를 설정하기 위해 두 개의 날짜 선택기를 표시합니다.검색의 의미를 찾기 위해 날짜를 오늘 또는 그 이전으로만 제한합니다.
이 구역에서:
<v-text-field
  v-model="searchData.keyword"
  v-validate="'required'"
  :error-messages="errors.collect('keyword')"
  label="Keyword"
  data-vv-name="keyword"
  required
></v-text-field>
필요한 검색 키워드 필드가 작성되었는지 확인하려면 vee-validate를 사용합니다.그렇지 않으면 오류 메시지가 표시되고 질의가 계속되지 않습니다.
또한 SearchResults 구성 요소를 Search 페이지 구성 요소에 중첩합니다.
components: {  
  SearchResults  
}
템플릿의 script 태그와 <SearchResults /> 사이에 있습니다.
마지막으로, 우리는 App.vue에 다음과 같은 내용을 추가하여 위쪽 표시줄과 메뉴를 추가합니다.
<template>
  <v-app>
    <v-navigation-drawer v-model="drawer" app>
      <v-list nav dense>
        <v-list-item-group v-model="group" active-class="deep-purple--text text--accent-4">
          <v-list-item>
            <v-list-item-title>New Yourk Times Vuetify App</v-list-item-title>
          </v-list-item>
<v-list-item>
            <v-list-item-title>
              <router-link to="/">Home</router-link>
            </v-list-item-title>
          </v-list-item>
<v-list-item>
            <v-list-item-title>
              <router-link to="/search">Search</router-link>
            </v-list-item-title>
          </v-list-item>
        </v-list-item-group>
      </v-list>
    </v-navigation-drawer>
<v-app-bar app>
      <v-toolbar-title class="headline text-uppercase">
        <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
        <span>New York Times Vuetify App</span>
      </v-toolbar-title>
      <v-spacer></v-spacer>
    </v-app-bar>
<v-content>
      <v-container fluid>
        <router-view />
      </v-container>
    </v-content>
  </v-app>
</template>
<script>
export default {
  name: "app",
  data: () => {
    return {
      showNavigation: false,
      drawer: false,
      group: null
    };
  }
};
</script>
<style>
.center {
  text-align: center;
}
form {
  width: 95vw;
  margin: 0 auto;
}
.md-toolbar.md-theme-default {
  background: #009688 !important;
  height: 60px;
}
.md-title,
.md-toolbar.md-theme-default .md-icon {
  color: #fff !important;
}
</style>
왼쪽 네비게이션 서랍이 있는 맨 윗줄을 원한다면, 위의 코드 구조를 엄격히 따라야 한다.

좋은 웹페이지 즐겨찾기