テックブログ

  1. Nuxt
  2. 963 view

TypeScriptでNuxtアプリを作るチュートリアル【書籍検索システム】

本記事では、Nuxt+TypeScriptで書籍検索システムを構築する手順を説明します。GitHubにソースコードがあるのでそれとあわせてご覧ください!

作るもの

Google Books API というサービスを使います。

ソースコード

ソースコードはこちらからどうぞ

プロジェクト作成

Vue Cliなどのインストールがお済みでない方は以下の記事にやり方をまとめたので参考にしてください。

TypeScriptでNuxt入門【5分で環境構築】

vue init nuxt-community/typescript-template book-search-app
cd book-search-app
npm install
npm run dev

http://localhost:3000で立ち上がるので確認してみましょう。

Pug/Sassを使う設定

プリプロセッサを使うには?を参考にPug、Sassを使う設定をします。

npm install --save-dev [email protected] pug-plain-loader node-sass sass-loader

Bootrap Vueを使う

Bootstrap + Vue

こちらを参考に設定します。

# npm
npm i bootstrap-vue --save

# yarn
yarn add bootstrap-vue

nuxt.config.jsに以下の設定を追加しましょう。

modules: [
  "@nuxtjs/axios",
  "~/modules/typescript.js",
  "bootstrap-vue/nuxt", // 追加
],

画面を作る

UI系の設定が一通り済んだので画面を作っていきましょう。

layouts/default.vue

<template lang="pug">
  div
    b-navbar(toggleable="md",type="dark",variant="primary")
      b-navbar-brand(href="/") TypeScriptでNuxtに入門する
    nuxt
</template>

components/BookListItem.vue

<template lang="pug">
b-card.mb-2.card(title="ここにタイトルが入ります", :img-src='thumbnail', img-alt='Image', img-top='', tag='article', style='max-width: 20rem;')
  p.card-text ここに説明がはいりますここに説明がはいりますここに説明がはいりますここに説明がはいります
  router-link(to="books/1") 
    b-button(variant='primary') 詳細を見る
</template>

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


@Component({})
export default class BookListItem extends Vue {
  @Prop() book
  get id() {
    try {
      return this.book.id;
    } catch {}
    return ''
  }
  get title() {
    try {
      return this.book.volumeInfo.title;
    } catch {}
    return ''
  }

  get description() {
    try {
      if(this.book.volumeInfo.description && this.book.volumeInfo.description.length > 30) {
        return this.book.volumeInfo.description.substr(0,30) + '(...続きを読む)';
      }
      return this.book.volumeInfo.description
    } catch {}
    return ''
  }

  get thumbnail(): string | boolean {
    try {
        return this.book.volumeInfo.imageLinks.smallThumbnail;
    } catch {}
    return ''
  }
}
</script>
<style lang="sass">
.card
  min-width: 320px
  font-family: "Segoe UI", Tahoma, Geneva, Verdana,sans-serif
  padding: 1rem
  margin: 0.25rem
  border: 0.25rem solid gainsboro
</style>

components/BookDetailItem.vue

<template lang="pug">
div.card
  div.thumbnail
    b-img(:src="thumbnail",fluid,alt="Responsive image")
  div.content
    h2 ここにタイトルが入ります
    p.card-text ここに説明がはいりますここに説明がはいりますここに説明がはいりますここに説明がはいります
</template>
<script lang="ts">
import {
  Component,
  Prop,
  Vue,
} from "nuxt-property-decorator"


@Component({})
export default class BookDetailItem extends Vue {
  @Prop() book
  get id() {
    try {
      return this.book.id;
    } catch {}
    return ''
  }
  get title() {
    try {
      return this.book.volumeInfo.title;
    } catch {}
    return ''
  }

  get description() {
    try {
      return this.book.volumeInfo.description
    } catch {}
    return ''
  }

  get thumbnail(): string | boolean {
    try {
        return this.book.volumeInfo.imageLinks.smallThumbnail;
    } catch {}
    return ''
  }
}
</script>
<style lang="sass">
.card
  font-family: "Segoe UI", Tahoma, Geneva, Verdana,sans-serif
  padding: 1rem
  display:flex
  width: 100%
.thumbnail
  width: 30%
.content
  width: 60%
</style>

pages/index.vue

<template lang="pug">
  section
    b-container
      b-row.row
        b-col
          b-form
            b-input-group(size="lg")
              b-form-input(
                size="sm",
                class="mr-sm-2",
                type="text",
                placeholder="キーワードを入力してください。",
              )
              b-button(size="sm",class="my-2 my-sm-0",type="submit") 検索する
        b-col
      div.cards
        book-list-item
        book-list-item
        book-list-item
</template>

<script lang="ts">
import {
  Component,
  Vue,
} from "nuxt-property-decorator"
import BookListItem from "~/components/BookListItem.vue"

@Component({
  components: {
    BookListItem
  }
})
export default class extends Vue {

}
</script>
<style lang="sass">
.cards
  display: flex
  flex-wrap: wrap

.row
  padding: 8px 0
</style>

pages/books/_id.vue

<template lang="pug">
  section
    div.cards
      book-detail-item
</template>

<script lang="ts">
import {
  Component,
  Vue
} from "nuxt-property-decorator"
import BookDetailItem from "~/components/BookDetailItem.vue"

@Component({
  components: {
    BookDetailItem
  }
})
export default class BookDetail extends Vue {}
</script>
<style lang="sass">

.cards
  display: flex
  flex-wrap: wrap
  justify-content: flex-between

.row
  padding: 8px 0
</style>

こんな感じの画面ができたでしょうか?次のページではAPIをコールして実際のデータを表示します!

The following two tabs change content below.

riri

半年おきくらいにバックエンドとフロントエンドを行ったり来たり。 25歳。 将棋好き。

1

2

Nuxtの最近記事

  1. Nuxt.js+Firebaseでデプロイまでの流れ【簡単5分】

  2. NuxtでOAuth認証を導入する

  3. Vuetifyチュートリアル。CSSを書かないマテリアルデザイン

  4. Nuxt入門〜create-nuxt-appでお手軽開発

  5. NuxtでJWT認証を導入する

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。