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>
Nuxt.js ヘッダ部やフッタ部をコンポーネント化
ヘッダ部やフッタ部をコンポーネント化
前回レイアウトディレクトリにレイアウト用のファイルを追加しレイアウトを切り替えられるようにしました。
ヘッダ部やフッタ部は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/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
レイアウトに関する記述がないのでデフォルトのレイアウトが適用される。
layoutsディレクトリにsample.vueを作成
/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
ページコンポーネントで指定したレイアウト(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
_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>
出力結果
/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
<!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
<!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>
想定通り静的ファイルが出力できました。
これでローカル環境で各種データを取得して静的ファイルを出力する環境ができました。