脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

Nuxt.js Tips

nuxt.jsのtipsです
f:id:portaltan:20190305115710p:plain

componentに値を渡す場合

送る側
<template>
  <MyComponent />
</template>

<script>
import MyComponent from "~/components/MyComponent.vue"

export default {
  components: {
    MyComponent
  }
}
</scipt>
受け取る側(MyComponet.vue)
<script>
export default {
  props: {
    aaa, bbb, ccc
  }
}
</script>
型チェックをしたい場合
<script>
export default {
  props: {
    aaa: String, 
    bbb: Boolean,
    ccc: Array
  }
}
</script>

propsに直接文字列を入れる場合

<MyComponent :myprop="StringDayo" />

とすると

Raw expression: :myprop="StringDayo"

となる

解決策
<MyComponent myprop="StringDayo" />
or
<MyComponent :myprop="'StringDayo'" />

props等の変数をhtmlの要素にいれたい

<template>
  <nuxt-link to="this.link">
    Link Dayo
  </nuxt-link>
</template>

<script>
export default {
  props: {
    link: String
  }
}
</script>

これだとpropsのlinkが呼ばれずに/this.linkというリンクが参照されてしまう
解決策としては変数を使いたいときには要素の前に:をつける

<nuxt-link :to="this.link">

画像をpropsとして読み込む

<template>
  <div>
    <img :src="image_src" />
  </div>
</template>

<script>
export default {
  props: {
    filename: String,
  },
  data() {
    return {
      image_src: require(`~/assets/img/${this.filename}`)
    }
  }
}
</script>

methodsを追加する場合

<template>
  <div class="foobar" @mouseover="mouseOn()" @mouseout="mouseOut()">
    hogefuga
  </div>
</template>

<script>
export default {
  methods: {
    mouseOn() {
      document.getElementById(foobar).style.color = "red";
    },
    mouseOut() {
      var img = document.getElementById(foobar);
      img.style.color = "gray";
    }
  }
}
</scrip>

ページ読み込み時に処理を行いたいとき

<script>
export default {
  mounted() {
    alert('foobar');
  }
}
</script>

jsonファイルを読み込んで表示する

/static/json/test.json

{
  "aaa": true
  "bbb": false
  "ccc": "hogehoge"
}

/pages/test.vue

<script>
export default {
  data() {
    return {
      json: require(`static/json/test.json`)
    }
  }
}
</script>

▼v-for
要素を繰り返えしたいときに使う
上のjsonファイルを使う

<template>
  <div>
    <ol>
      <li v-for"(value, index) in json" property1="index" property2="value"></li>
    </ol>
  </div>
</template>

<script>
export default {
  data() {
    return {
      json: require(`static/json/test.json`)
    }
  }
}
</script>

v-bind:class

クラス属性を条件分岐で設定するしないを分ける

<template>
  <div>
    <ol>
      <li v-for"(value, index) in json" v-bindclass="{ active: aaa }"></li> // 描画される(aaa === true)
      <li v-for"(value, index) in json" v-bindclass="{ active: bbb }"></li> // 描画されない(bbb === false)
    </ol>
  </div>
</template>

<script>
export default {
  data() {
    return {
      json: require(`static/json/test.json`)
    }
  }
}
</script>

nuxt generateで動的ルーティングもbuild対象にする

nuxtは_foobar.vueといったアンダースコアで始まるvueファイルを作ることで動的にルーティングすることができる。
しかしこの動的ルーティングはデフォルトでnuxt generateの静的ファイルビルドの対象外となっている
以下のようにnuxt.config.jsで明示的に指定してやることで静的なルーティングがビルドされる

module.exports = {
  generate: {
    routes:[
      '/hogehoge',
      '/fuga/fuga'
    ]
  }
}

また、ファイル数が多くなって直接編集が面倒になったときは、以下のようにもできる
staticファイル以下のjsonファイルを読み込んでroutingに設定している

const fs =require('fs')
const filename = fs.readdirSync("./static/").map(x => x.match(/(.*)(?:\.([^.]+$))/)[1])

module.exports = {
  generate: {
    routes: filenames
  }
}

ホットリロードで開発サーバをたてる

npm run dev

listen portを開ける

上記のnpm run devでデバッグサーバをたてることが可能になるが、デフォルトではlocalhostからしかアクセスできない。
なのでnuxt.config.jsで以下のように指定する

module.exports = {
  server: {
    host: '0.0.0.0'
  }
}

rss.xmlを設定する

nuxt generate時にrss.xmlを更新する方法
まずstatic/rss.xmlを作る

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>My Home Page</title>
<link>https://my-home-page.com/</link>
<description>このページはぼくのホームページぃぃぃ!!!</description>
<lastBuildDate>${generate by modules}</lastBuildDate>
<language>ja</language>
<item>
<title>日記</title>
<link>https://my-home-page/blog/</link>
<description>はじめての日記</description>
<pubDate>Fri, 01 Mar 2019 18:00:00 +0900</pubDate>
</item>
</channel>

このstaticファイルの内容はコンパイルされずにそのままdist以下に配置されるので、
nuxt generateが終わった時点で${generate by modules}のところを書き換えてやればよい
modules/hook/generate.js

require('date-utils')
const fs = require ('fs')
const now = new Date()
const rss = fs.readFileSync("static/rss.xml", "utf-8").replace("<lastBuildDate>${generate by modules}</lastBuildDate>", `<lastBuildDate>${now.toFormat('DDD, DD MMM YYYY HH24:MI:SS +0900')}</lastBuildDate>`)

module.exports = function () {
  this.nuxt.hook('generate:done', async generator => {
    fs.writeFileSync("dist/rss.xml", rss);
  })
}

moduleを書いたら、nuxt.config.jsで指定する

module.exports = {
  modules: [
    '@/modules/hook/generate'
  ]
}

bootstrapを読み込む際に二重で読み込まれるのを防ぐ

nuxt.config.js
modules.exports = {
  modules: [
    ['bootstrap-vue/nuxt', { css: false }]
  ]
}

v-if/v-else-if/v-else

コンポーネント等の表示切替をv-if等を使って切り替えることができる

<template>
  <div>
    <img v-if="this.type==='image'" :src="src"></img>
    <video v-else-if="this.tyep==='movie'" :src="src" autoplay loop muted></video>
    <p v-else>missing media</p>
  </div>
</template>

<script>
export default {
  props: {
    type: String,
    link: String
  },
  data() {
    return {
      src: require(`~/assets/img/${this.link}`)
    }
  }
}
</script>

v-for内でv-ifを使う

v-forとv-ifを同じ要素内で使うことは推奨されていない

<template>
  <div>
    <div v-for="(value, index) in objects">
      <div v-if="value">aaa</div>
      <div v-if="index===0">bbb</div>
    </div>
  </div>
</template>

外部リソースを読み込む(bootstrapとかjqueryとか)

<script>
export default {
  head () {
    return {
      script: [
        { src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js' },
        { src: 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js' }
      ],
      link: [
        { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' }
      ]
    }
  }
}
</script>

custom layoutを読み込む

<script>
export default {
  layout: 'custom'
  }
}
</script>

▼404ページの作成
pages/404/index.vueに作成する

▼動的ルーティングで値を受け取る
pages/_id.vue

<template>
  <div>
    {{parameter}}
  </div>
</template>

<script>
export default {
  asyncData({ params }) {
    return {
      parameter: params.id
    }
  }
}
</script>