AB型技術系 主に備忘録

ほぼプログラム関連の備忘録

Nuxt.js components配下のコンポーネントでデーターを取得

共通コンポーネントでデータを取得して表示したい

共通コンポーネントでデータを取得したいので下記のように実装

/pages/sample_page.vue

<template>
    <Sample/>
</template>

/components/sample.vue

<template>
  <div>
    <b>{{data.data1}}</b><br>
    <b>{{data.data2}}</b>
  </div>
</template>
<script>
export default {
  async asyncData(context) {
    const data = await context.$axios.$get('http://localhost:3000/nuxt_test.json')
    return { data }
  }
}
</script>

/static/nuxt_test.json

{
    "data1":"データ1",
    "data2":"データ2"
}

http://localhost:3000/sample_page

エラーが発生しました。
原因はasyncDataがpages配下以外のコンポーネントが使えないから。

公式だと↓のページで詳しく説明されてました。
nuxtjs.org

このページには解決方法も記載されれていて、fetchフックを使えば解決できると記載されていました。

fetchフックの使い方を公式ページで調べると↓のページのサンプルがドンピシャでした。
nuxtjs.org

このページを参考にコンポーネントを修正しました。

/components/sample.vue

<template>
  <div>
    <b>{{data.data1}}</b><br>
    <b>{{data.data2}}</b>
  </div>
</template>
<script>
export default {data() {
      return {
        data: {}
      }
    },
    async fetch() {
      this.data = await fetch(
        'http://localhost:3000/nuxt_test.json'
      ).then(res => res.json())
    }
}
</script>

http://localhost:3000/sample_page

components配下のコンポーネントでデーターを取得して表示することができました。


Nuxt.js ヘッダ部やフッタ部をコンポーネント化

ヘッダ部やフッタ部をコンポーネント

前回レイアウトディレクトリにレイアウト用のファイルを追加しレイアウトを切り替えられるようにしました。

freelancer.hatenablog.jp

ヘッダ部やフッタ部はcomponents直下に配置してコンポーネント化したほうがよさそうなのでためしてみました。

header.vueとfooter.vueを追加

componentsディレクトリにheader.vueとfooter.vueを追加する。

/components/header.vue

<template>
    <header style="border-bottom:solid 1px #CCC;padding:10px">ヘッダ部(共通)</header>
</template>

/components/footer.vue

<template>
    <footer style="padding:10px">フッタ部(共通)</footer>
</template>

defaultvueを修正

/layouts/default.vue 修正前

<template>
    <div>
        <header style="border-bottom:solid 1px #CCC;padding:10px">ヘッダ部(デフォルト)</header>
        <div style="border-bottom:solid 1px #CCC">
            <nuxt/>
        </div>
        <footer style="padding:10px">フッタ部(デフォルト)</footer>
    </div>
</template>

/layouts/default.vue 修正後

<template>
    <div>
        <Header/>
        <div style="border-bottom:solid 1px #CCC">
            <nuxt/>
        </div>
        <Footer/>
    </div>
</template>

<コンポーネント名 />でコンポーネントの内容が表示されるようになります。
古いバージョンのNuxt.jsだとimport宣言が必要になりますが、新しいバージョンだとcomponents配下にあるコンポーネントは自動でインポートされます。

/layouts/default.vue inport宣言する場合

<template>
    <div>
        <Header/>
        <div style="border-bottom:solid 1px #CCC">
            <nuxt/>
        </div>
        <Footer/>
    </div>
</template>
<script>
import Header from '~/components/header.vue'
import Footer from '~/components/footer.vue'
export default {
  components: {
    Header,
    Footer
  }
}
</script>

/lnuxt.config.js 自動インポートの設定個所

// Auto import components: https://go.nuxtjs.dev/config-components
  components: true,

http://localhost:3000/layout_default


部品化したヘッダーとフッターが表示されるようになりました。
データ取得やレイアウトに関する機能はある程度ためせたので次回はコンポーネント間のデータのやりとりについて試してみます。


Nuxt.js レイアウトディレクトリを試してみる。

レイアウトディレクト

ページコンポーネントに各ページで共通になる部分(ヘッダ部、フッタ部)を記述するのが面倒。
Nuxtにはレイアウト作成の機能があり各ページに共通のレイアウト適用することが可能。

layoutsディレクトリにdefault.vueを作成

layoutsディレクト

/layouts/default.vue

<template>
    <div>
        <header style="border-bottom:solid 1px #CCC;padding:10px">ヘッダ部(デフォルト)</header>
        <div style="border-bottom:solid 1px #CCC">
            <nuxt/>
        </div>
        <footer style="padding:10px">フッタ部(デフォルト)</footer>
    </div>
</template>

レイアウトを指定しなかった時に適用されるデフォルトのレイアウト。
<nuxt/>がページコンポーネントが表示される部分。

/pages/layout_default.vue

<template>
    <div style="padding:10px">ボディ部</div>
</template>

<script>
export default {
  name: 'LayoutDefault'
}
</script>

http://localhost:3000/layout_default

http://localhost:3000/layout_default

レイアウトに関する記述がないのでデフォルトのレイアウトが適用される。

layoutsディレクトリにsample.vueを作成

layoutsディレクト

/layouts/sample.vue

<template>
    <div>
        <header style="border-bottom:solid 1px #CCC;padding:10px">ヘッダ部(個別)</header>
        <div style="border-bottom:solid 1px #CCC">
            <nuxt/>
        </div>
        <footer style="padding:10px">フッタ部(個別)</footer>
    </div>
</template>

ページコンポーネントで指定することによって適用されるレイアウト。

/pages/layout_sample.vue

<template>
    <div style="padding:10px">ボディ部</div>
</template>

<script>
export default {
  name: 'LayoutSample',
  layout: 'sample'
}
</script>

http://localhost:3000/layout_sample

http://localhost:3000/layout_sample

ページコンポーネントで指定したレイアウト(layout: 'sample')が適用される。

ヘッダ部やフッタ部は部品としてcomponents直下に作成した方がいいかも。
次回はこのあたりを試そうかと。


Nuxt.js 動的ルーティングを試してみる。

動的ルーティング

ある商品の詳細ページのようなページの構成は同じで商品毎に表示内容が変わるようなページを作りたい場合、Nuxt.jsではどうすればいいのか調べてみました。

url構成

/商品カテゴリー/商品コード

カテゴリー1に属する商品コードAのURL

/category1/shiohinA

カテゴリー1に属する商品コードBのURL

/category1/shiohinB

カテゴリー2に属する商品コードCのURL

/category2/shiohinC

カテゴリー2に属する商品コードDのURL

/category2/shiohinD

上記のURLに対応したファイル構成(静的)

  • /pages/category1/shiohinA.vue
  • /pages/category1/shiohinB.vue
  • /pages/category2/shiohinC.vue
  • /pages/category2/shiohinD.vue

これだとカテゴリーが増えたり商品が増える度にディレクトリやファイルを追加する必要があります。

上記のURLに対応したファイル構成(動的)

/pages/_category/_shiohin.vue

ファイル構成(動的)

先頭に_を付けるだけで動的にルーティングしてくれるようです。

/pages/_category/_shiohin.vue

<template>
    <div>
  <h1>category:{{ cate }}</h1>
  <h1>shohin:{{ cd }}</h1>
  </div>
</template>

<script>
export default {
  name: 'IndexPage',
  data() {
        return{
            cate: this.$route.params.category,
            cd: this.$route.params.shohin
        }
    } 
}
</script>

パラメータ部分は this.$route.params.パラメーター名で参照できます。

http://localhost:3000/category2/shiohinD

http://localhost:3000/category2/shiohinD

_categoryディレクトリと_shiohin.vueファイルを追加するだけで動的にページを表示することができました。

ここで気になったのは静的ファイルを出力するとどうなるかということ。

静的ファイルを出力


_categoryディレクトリと_shiohin.vueファイルを作成しただけでは静的ファイルは出力されませんでした。

/pages/_url_list.vue

<template>
    <div>
        <ul>
            <li><nuxt-link to="/category1/shiohinA">商品A</nuxt-link></li>
            <li><nuxt-link to="/category1/shiohinB">商品B</nuxt-link></li>
            <li><nuxt-link to="/category2/shiohinC">商品C</nuxt-link></li>
            <li><nuxt-link to="/category2/shiohinD">商品D</nuxt-link></li>
        </ul>
    </div>
</template>

動的に表示するページへのリンクを表示するだけのファイルを追加して出力してみます。


動的に表示するページのhtmlが出力されました。

/dist/_category1/shiohinA/index.html

<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/828bf5e.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/1a6e405.js" as="script"><link rel="preload" href="/_nuxt/e281cbe.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><h1>category:category1</h1> 
<h1>shohin:shiohinA</h1></div></div></div>
  

</body></html>

/dist/_category1/shiohinB/index.html

<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/828bf5e.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/1a6e405.js" as="script"><link rel="preload" href="/_nuxt/e281cbe.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><h1>category:category1</h1> 
<h1>shohin:shiohinB</h1></div></div></div>
  

</body></html>

/dist/_category2/shiohinC/index.html

<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/828bf5e.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/1a6e405.js" as="script"><link rel="preload" href="/_nuxt/e281cbe.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><h1>category:category2</h1> 
<h1>shohin:shiohinC</h1></div></div></div>
  

</body></html>

/dist/_category2/shiohinD/index.html

<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/828bf5e.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/1a6e405.js" as="script"><link rel="preload" href="/_nuxt/e281cbe.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><h1>category:category2</h1> 
<h1>shohin:shiohinD</h1></div></div></div>
  

</body></html>

次はlayoutに関連する機能を試す予定です。


Nuxt.js 静的ファイルを出力してみる

出力対象

出力対象

/pages/index.vue

<template>
    <div>
        <ul>
            <li>{{ text }}</li>
            <li>{{ data.data1 }}</li>
            <li>{{ data.data2 }}</li>
        </ul>
    </div>
</template>

<script>
export default {
  name: 'IndexPage',
  async asyncData(context) {
        const data = await context.$axios.$get('http://localhost:3000/nuxt_test.json')
        return { data }
    },
  data() {
        return{
            text: "テスト"
        }
    },
}
</script>

/pages/Sample.vue

<template>
    <Sample/>
</template>

/components/sample.vue

<template>
  <div><b>サンプル</b></div>
</template>

/pages/sub/subsample.vue

<template>
    <b>サブディレクトリサンプル</b>
</template>

出力コマンドを実行

npm run generate

※ データ(nuxt_test.json)取得のためサーバーを起動しないとエラーが発生。

出力結果

/dist/index.html

/dist/index.html
<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/679b7a7.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/43f5c2c.js" as="script"><link rel="preload" href="/_nuxt/3a451ff.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><ul><li>テスト</li> <li>データ1</li> <li>データ2</li></ul></div></div></div>
</body></html>

/dist/sample/index.html

/dist/sample/index.html
<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/679b7a7.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/43f5c2c.js" as="script"><link rel="preload" href="/_nuxt/9908c56.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><div><b>サンプル</b></div></div></div>
  

</body></html>

/dist/sub/subsample/index.html

/dist/sub/subsample/index.html
<!DOCTYPE html><html lang="ja"><head>
    <title>サンプル</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content=""><meta name="format-detection" content="telephone=no"><link rel="icon" type="image/x-icon" href="/favicon.ico"><link rel="preload" href="/_nuxt/679b7a7.js" as="script"><link rel="preload" href="/_nuxt/4cdfbd1.js" as="script"><link rel="preload" href="/_nuxt/43f5c2c.js" as="script"><link rel="preload" href="/_nuxt/21c14d6.js" as="script"><style>.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#000;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}</style>
  </head>
  <body>
    <div id="__nuxt"><!----><div id="__layout"><b>サブディレクトリサンプル</b></div></div>
  

</body></html>

想定通り静的ファイルが出力できました。
これでローカル環境で各種データを取得して静的ファイルを出力する環境ができました。