現役フリーランスエンジニアが運営するテックメディア。日々の業務で得た知識を発信していきます!

  1. フロントエンド
  2. 6045 view

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

最終更新日:2018/11/26

本記事では、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.
WINDII

WINDII

WINDII(ウィンディ)は、フリーランスエンジニアが運営するテックメディアです。 日々の業務で得た知見を、皆さんに役立つコンテンツにして発信していくので応援よろしくお願いします! また、Slackで無料コミュニティも運営しています。たくさんのエンジニアが参加していて、プログラミングの相談や雑談などをしている楽しいコミュニティなので、興味ある方はぜひお気軽にご参加ください。 Slackコミュニティはこちらから

1

2

フロントエンドの最近記事

  1. Nuxt.js + Contentful。HeadlessCMSでポータルサイトを作る

  2. IOSアプリをAppStoreに公開する手順書(Ionic)

  3. IonicAcademyでIonic&Angularでのアプリ開発を学ぶ

  4. Ionic4+firebaseで認証をする方法【ログイン、ログアウト機能の実装】

  5. ハイブリッドアプリ開発チュートリアル【Ionic4+OnsenUI】

関連記事

コメント

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

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

PAGE TOP