20200406のvue.jsに関する記事は8件です。

意外と難しい?Vuetifyのv-slot=activator="{ on }"について解説!

こんにちは。ゲームを作って学ぶプログラミング学習サービスプロアカを開発しているアカネヤです。

一部のVuetifyのコンポーネントでは、Vueのスロットの機能を利用します。
これが意外と複雑ですので、解説します。

内容としては、Vueの名前付きスロットスコープ付きスロットになります。

例えば、v-menuコンポーネントの使い方は下のようになります。

<v-menu>
  <template v-slot:activator="{ on }">
    <v-btn v-on="on">
      メニューを開く
    </v-btn>
  </template>
  <v-list>
    <v-list-item>
      メニューの項目1
    </v-list-item>
  </v-list>
</v-menu>

v-on="on"を指定したHTML要素をクリックすると、v-listの部分が表示されます。

ここではVueの名前付きスロット機能と、スコープ付きスロットの両方を使用しています。

このコードの中で、普段あまり使わない文法は

<template v-slot:activator="{ on }">

の部分だと思います。

これは、この<template>activatorというnameに対するスロットであることを指定しています。
また、スロットプロパティとして、デフォルトスロットを表示するためのイベントハンドラを受け取っています。
そのイベントハンドラは、スロットプロパティのうちonというキーで<v-menu>コンポーネントから渡されるため

<template v-slot:activator="{ on }">

となるのです。

詳しく知りたい方は、スロットについてのVue公式ドキュメントを全部読むことをおすすめします。
https://jp.vuejs.org/v2/guide/components-slots.html

終わりに

私が開発しているゲームを作って学ぶプログラミング学習サービスプロアカでは無料体験も行っています。ぜひご覧下さい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

岡山県版新型コロナウイルス対策サイトを開発・運用している話

ogp.png

はじめに

岡山県版新型コロナウイルス対策サイト(非公式)の運用のルサカです。
今回は岡山県版新型コロナウイルス対策サイトを開発・運用の過程についてQiitaに投稿しました。

開発開始

岡山県版作るのに東京都のコロナウイルス対策サイトGitHubのリポジトリを活用し作成しました。以下のようにふじしゃんこと藤原出帆さん(Twitter)と役割を分担し開発をしました。
ふじしゃん → 東京都版の部分を岡山仕様にするなどなど
ルサカ → ロゴやOGP画像などを独自の岡山仕様にするなど
その結果、約18時間で開発を終え、公開することができました。

さくらインターネットさんとの出会い

もともとは、Netlifyで公開していましたが、転送量の上限が100GBと万が一アクセスが増えた場合対応ができなくなるため、さくらインターネットさんが新型コロナウイルス関連で提供してくれているサーバーを利用することにしました。本当にさくらインターネットさんありがとうございます!!!
詳細↓
https://www.sakura.ad.jp/information/pressreleases/2020/03/23/1968203129/

オープンソースで開発へ

開発開始からしばらくの間はふじしゃんの僕のみでGitHubのプライベートリポジトリにて開発をしていましたが、岡山県版新型コロナウイルス対策サイトをよりよい物にし、多くの方に活用していただくためにオープンソースで開発することにしました。

最後に

岡山県版新型コロナウイルス対策サイトの運営の誰がいつ新型コロナウイルスに感染するかもわからないため特定の人に依存することのない運用を目指しています。
さらに、岡山県版新型コロナウイルスをより良いものにするためには沢山の人の力が必要です。

岡山県版新型コロナウイルス対策サイトに力を貸してください!!!

岡山県版新型コロナウイルス対策サイト↓
https://okayama.stopcovid19.jp/
GitHubリポジトリ↓
https://github.com/stopcovid19-okayama/covid19
Twitter↓
https://twitter.com/covid19_okayama
Slack↓
https://join.slack.com/t/okayama-stopcovid19/shared_invite/zt-d86r1ajq-ba1w0w71DGcX_fed6lufog

よろしくお願いします!!!

リンク

[東京都新型コロナウイルス対策サイト]
https://stopcovid19.metro.tokyo.lg.jp/
[さくらクラウド]
https://cloud.sakura.ad.jp/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsでスライダーを導入してみた【vue-awesome-swiper】

はじめに

人材系ベンチャーでシステムの開発をしている私ですが、「UI/UX色々変えちゃおうぜ!!」ってなったので
その一つを紹介していきますううううう:stuck_out_tongue::stuck_out_tongue:
ちなみにフロントはNuxtでバックエンドはRailsAPI使ってますううううう:stuck_out_tongue::stuck_out_tongue:

環境

  • MacOS
  • yarn 1.21.1
  • node 12.0.0
  • vue 2.6.1
  • vue-awesome-swiper 2.1.3
  • docker

解決したい問題

以前のデザイン

スクリーンショット 2020-04-03 21.23.14.png
スクリーンショット 2020-04-03 22.52.33.png

新デザイン

ダウンロード.gif
ダウンロード (1).gif

「案件の数がトップページで4つしか出ないのは微妙だなー」
「スマホでの冗長化えぐいなあ」
って思っていました。
これを解決するには「スライダーの導入や!!!」となり、実装するに至りました。

※ついでに中のカードのデザインも変えちゃいました(笑)

vue-awesome-swiperの導入

ターミナル
yarn add vue-awesome-swiper

今回はvue-awesome-swiperを使用しましたー

github
公式ドキュメント

pluginに追加

plugins/vue-slider-component.js
import Vue from 'vue'
import VueSlider from 'vue-slider-component'

Vue.component('VueSlider', VueSlider)

pluginフォルダーの中にvue-slider-component.jsを作成しましょう。
コードの中身は"Vue"とか「"Vue-slider"を読み込んで、VueSliderとしてプラグインを使用します」みたいな感じです。

nuxt.config.jsに追記

nuxt.config.js
module.exports = {
  css: [
    'vue-slider-component/theme/default.css',
  ],
  plugins: [
    { src: '~plugins/vue-slider-component.js' }
  ],
  build: {
    vendor: [
      'vue-awesome-swiper'
    ]
  }
}

こんな感じですね。

index.vueに記載

index.vue
<template>
  <div>
    <swiper>
      <swiper-slide>スライダー1</swiper-slide>
      <swiper-slide>スライダー2</swiper-slide>
      <swiper-slide>スライダー3</swiper-slide>
    </swiper>
  </div>
</template>

swiper-slide(スライドさせたい子要素)をswiper(親要素)で囲う感じですね。

index.vue
<template>
  <div>
    <swiper>
      <swiper-slide>
        <img
          src="~/assets/images/top-sample1.png"
          alt="sample1">
      </swiper-slide>

      <swiper-slide>
        <img
          src="~/assets/images/top-sample2.png"
          alt="sample2">
      </swiper-slide>

      <swiper-slide>
        <img
          src="~/assets/images/top-sample3.png"
          alt="sample3">
      </swiper-slide>
    </swiper>
  </div>
</template>

画像をスライドさせたいならこんな感じです。

optionを追加する

ここからがvue-awesome-swiperの凄さが実感できます。

index.vue
<template>
  <div>
    <swiper
      :options="swiperOption">
      <swiper-slide>スライダー1</swiper-slide>
      <swiper-slide>スライダー2</swiper-slide>
      <swiper-slide>スライダー3</swiper-slide>
    </swiper>
  </div>
</template>

<script>
export default {
  data() {
    return {
      swiperOption: {
        speed: 1000,//スライドの切り替わりスピード
        spaceBetween: 30,//各スライドの余白
        centeredSlides: true,//スライダーを真ん中に
        loop: true, //無限ループ
        autoplay: { //スライドの自動切り替え
          delay: 5000,//スライドの自動切り替えの秒数
          disableOnInteraction: false//何らかのアクション後の自動切り替えを再開
        }
      }
    }
  }
}
</script>

よくあるスライドだとこんな感じです。
data内のswiperOptionにあれこれ記載してくだけでスライダーをカスタマイズできるんですね。
素晴らしい:clap::clap:
カスタマイズ(パラメーター)はここでは説明しきれないくらいたくさん種類があるので、是非公式を見て試してみてください。
公式ドキュメント

ページネーションとナビゲーション

index.vue
<template>
  <div>
    <swiper
      :options="swiperOption">
      <swiper-slide>スライダー1</swiper-slide>
      <swiper-slide>スライダー2</swiper-slide>
      <swiper-slide>スライダー3</swiper-slide>
    </swiper>
    <div
      slot="pagination"
      class="swiper-pagination"/>
    <div
      slot="button-prev"
      class="swiper-button-prev"/>
    <div
      slot="button-next"
      class="swiper-button-next"/>
  </div>
</template>

<script>
export default {
  data() {
    return {
      swiperOption: {
        ~省略~
      },
        pagination: { //ページネーション設定
          el: '.swiper-pagination',
          clickable: true
        },
        navigation: { //ナビゲーション設定
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev'
        }
      }
    }
  }
}
</script>

ページネーションとかナビゲーションもめちゃめちゃ簡単につけられます。
ちなみに<swiper>の中に入れることもできるのでお好みでどうぞ。
スクリーンショット 2020-04-04 3.21.45.png

レスポンシブ対応

index.vue
<script>
export default {
  data() {
    return {
      swiperOption: {
          ~省略~
        },
        pagination: { 
          ~省略~
        },
        navigation: { 
          ~省略~
        },
        breakpoints: {
          1200: {
            slidesPerView: 2
          },
          600: {
            slidesPerView: 1.2,
            spaceBetween: 0
          }
        }
      }
    }
  }
}
</script>

レスポンシブも超簡単です。
画面サイズごとに表示するスライド数や、スペース間隔を設定できます。swiperOptionにbreakpointsを追加し、画面サイズ毎に定義します。
例えば1200px以下になると「スライド数が2つ」、600px以下になると「スライド数が1つ」「スライドの余白ゼロ」にするみたいな感じでできます。

(補足)v-forでAPIデータをスライドさせる

※このセクションは今回の私の実装例の話ですので、簡単なスライダーを使いたいだけという方は飛ばしてください。

index.vue
<template>
  <div>
    <swiper>
      <swiper-slide
        v-for="project in projects"
        :key="project.id">
        <JobCard
          :project="project" />
      </swiper-slide>
    </swiper>
  </div>
</template>

<script>
import JobCard from '~/components/parts/JobCard.vue'

export default {
  components: {
    JobCard
  },
  computed: {
    projects() {
      return this.$store.state.projects
    }
  },
  async mounted() {
    ~省略~
  }

</script>

今回の実装ではAPIで取得したprojectsデータをv-forで展開してます。
つまりprojectsの配列に入っている値の数だけswiper-slideが作られる感じですね。
そのデータを今回はJobCardコンポーネントに入れて、カードを作っています。
ここは状況によってかなり異なるので各自カスタマイズしてください。

おわりに

こんな感じでvue-awesome-swiperを使ってスライダーの実装を行いました!!!
社内でも「デザイン良くなった!!」と言われて喜んでます:santa::santa:
フリエンというフリーランスエンジニアの案件サイトを作っているので興味があったら覗いてみてください(宣伝しても給料がアップするわけではありませんが、、、:money_mouth::money_mouth:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】Nuxt + Vuetify でSSR時だけ一部のUIが機能しなくなる問題

現象

Vuetifyの <v-expansion-panel> を使用しているページで、
SSR時のみ他のUIが動作しなくなる現象が発生したのでメモ。

再現コード

最小の再現コードを探った結果、どうやら、<v-expansion-panel-header> の中で、<div><v-btn> を使用していると発生するらしい。

<v-expansion-panel-header>
  <div>
    <span>title</span>
    <v-btn>Button</v-btn>
  </div>
</v-expansion-panel-header>

対応

<div>の中に<v-btn>という条件下のみ発生するようなので、

<p><section>に置き換えると問題は解決した。
<v-expansion-panel-header>
  <section>
    <span>title</span>
    <v-btn>Button</v-btn>
  </section>
</v-expansion-panel-header>

あるいは、SSR時限定の現象なので、<client-only>を使うことでも回避できる。

<v-expansion-panel-header>
  <div>
    <span>title</span>
    <client-only><v-btn>Button</v-btn></client-only>
  </div>
</v-expansion-panel-header>

<client-only>で回避しておくのが安全か。

コンソールにもサーバー側のログにもエラーが出ないので原因を特定するのに困った。
……なんだコレ?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsのinput or Vutifyのtext-fieldで数値を入力したのにv-modelのバインド先では文字列になってる問題

結論

  • v-model.number="numberData"で解決
  • Vuetifyは関係無い
  • type="number"しても数値にはならない
  • Vue.jsの修飾子に解決策がある

解決: Numberに自動変換する修飾子.number

ご覧の通りVuetifyは関係ありません。

下記のリンクで確認ください
Vue.js/フォーム入力バインディング/修飾子/Number

<template>
  <!-- 色々と省略 -->
  <!-- vue.jsならこう -->
  <div>
    <input v-model.number="numberData"/>
  <div>
  <!-- Vuetifyのtext fieldならこう -->
  <div>
    <v-text-field v-model.number="numberData"/>
  <div>
</template>

余談: 数字 + 文字列を入力してみた

まずは数字だけ入力

ちゃんとNumberになってていいですね!
スクリーンショット 2020-04-06 16.27.17.png
スクリーンショット 2020-04-06 16.27.30.png

文字列を含んで入力

ちょっと嫌がらせで色んな文字列を入力してみました。
うまく数字だけバインドされているみたいです!素晴らしい!!
スクリーンショット 2020-04-06 16.28.58.png
スクリーンショット 2020-04-06 16.29.13.png

その他のテスト

間に文字列

"100 hoge 100" → Number 100
のように微妙な位置に数字を入れてもバインドされた値は変わりませんでした。

↑の先頭100を200に書き換え

"100 hoge 100"を"200 hoge 100"にしようとした所
バインドの結果がNumber 2 に一度切り替わって無事200と入力することができました。

ソースを追いかけてはいませんが、おそらく数字に変換できるものが入力された時だけバインドしているのだと思います。

余談: 空白を取り除く修飾子.trim

https://jp.vuejs.org/v2/guide/forms.html#trim
Vue.jsには入力から自動的に空白を取り除くトリミング機能まであるとは!
最近の開発はVue.js様様ですね!!

<template>
  <!-- 色々と省略 -->
  <div>
    <input v-model.trim="text"/>
  <div>
</template>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsのinput or Vuetifyのtext-fieldで数値を入力したのにv-modelのバインド先では文字列になってる問題

結論

  • v-model.number="numberData"で解決
  • Vuetifyは関係無い
  • type="number"しても数値にはならない
  • Vue.jsの修飾子に解決策がある

解決: Numberに自動変換する修飾子.number

ご覧の通りVuetifyは関係ありません。

下記のリンクで確認ください
Vue.js/フォーム入力バインディング/修飾子/Number

<template>
  <!-- 色々と省略 -->
  <!-- vue.jsならこう -->
  <div>
    <input v-model.number="numberData"/>
  <div>
  <!-- Vuetifyのtext fieldならこう -->
  <div>
    <v-text-field v-model.number="numberData"/>
  <div>
</template>

余談: 数字 + 文字列を入力してみた

まずは数字だけ入力

ちゃんとNumberになってていいですね!
スクリーンショット 2020-04-06 16.27.17.png
スクリーンショット 2020-04-06 16.27.30.png

文字列を含んで入力

ちょっと嫌がらせで色んな文字列を入力してみました。
うまく数字だけバインドされているみたいです!素晴らしい!!
スクリーンショット 2020-04-06 16.28.58.png
スクリーンショット 2020-04-06 16.29.13.png

その他のテスト

間に文字列

"100 hoge 100" → Number 100
のように微妙な位置に数字を入れてもバインドされた値は変わりませんでした。

↑の先頭100を200に書き換え

"100 hoge 100"を"200 hoge 100"にしようとした所
バインドの結果がNumber 2 に一度切り替わって無事200と入力することができました。

ソースを追いかけてはいませんが、おそらく数字に変換できるものが入力された時だけバインドしているのだと思います。

余談: 空白を取り除く修飾子.trim

https://jp.vuejs.org/v2/guide/forms.html#trim
Vue.jsには入力から自動的に空白を取り除くトリミング機能まであるとは!
最近の開発はVue.js様様ですね!!

<template>
  <!-- 色々と省略 -->
  <div>
    <input v-model.trim="text"/>
  <div>
</template>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuetifyのv-btnのアルファベットが大文字になるのを抑制する

課題

vuetifyで用意されているボタン、v-btnでボタン名がアルファベットの場合は、必ず大文字となります。

このようにv-btnSend Emailというボタン名にすると、以下の図のように大文字となります。
これをそのまま表示するようにしたい。

      <v-card class="mb-5 mt-5">
        <v-card-actions>
          <v-btn>Send Email</v-btn>
        </v-card-actions>
      </v-card>

2020-04-06_09h52_57.png

解決法

個別CSSのスタイルを適用する

style="text-transform: none"
      <v-card class="mb-5 mt-5">
        <v-card-actions>
          <v-btn style="text-transform: none">Send Email</v-btn>
        </v-card-actions>
      </v-card>

2020-04-06_09h54_50.png

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue-slickでスライドの増減に対応する

先ずはvue-slickのREADMEを元に作成します。
スライドの数を監視し変化のあった際reInitメソッドを呼び出しています。

<template>
  <div>
    <div>
      <button @click="plus">
        plus
      </button>
    </div>
    <div>
      <button
        v-if="slideCount>0"
        @click="minus"
      >
        minus
      </button>
    </div>
    <slick
      ref="slick"
      :options="slickOptions"
      @reInit="handleReInit"
    >
      <div
        v-for="(item,index) in slideCount"
        :key="index"
      >
        <img :src="'https://placehold.jp/3d4070/ffffff/150x150.png?text='+index">
      </div>
    </slick>
  </div>
</template>

<script>

import Slick from 'vue-slick'

export default {
  components: {
    Slick
  },
  data: function () {
    return {
      slideCount: 0,
      slickOptions: {
        slidesToShow: 5
      }
    }
  },
  created () {
    this.slideCount = 5
  },
  watch: {
    slideCount () {
      this.reInit()
    }
  },
  beforeCreate () {
  },
  methods: {
    plus () {
      this.slideCount++
    },
    minus () {
      this.slideCount--
    },
    next () {
      this.$refs.slick.next()
    },

    prev () {
      this.$refs.slick.prev()
    },
    reInit () {
      this.$nextTick(() => {
        this.$refs.slick.reSlick()
      })
    }
  }
}
</script>

上記コードだとスライドの減少には対応できました。しかしスライドの増加が上手くいきません。

そこでshowSlideというステータスを追加します。
さらにreInitの中身を変更slickコンポーネントにv-ifを追加します。
これでスライドの数が変わる度にスライダーを再描写することで増減に対応できました。

<template>
  <div>
    <div>
      <button @click="plus">
        plus
      </button>
    </div>
    <div>
      <button
        v-if="slideCount>0"
        @click="minus"
      >
        minus
      </button>
    </div>
    <slick
      v-if="showSlide"
      ref="slick"
      :options="slickOptions"
      @reInit="handleReInit"
    >
      <div
        v-for="(item,index) in slideCount"
        :key="index"
      >
        <img :src="'https://placehold.jp/3d4070/ffffff/150x150.png?text='+index">
      </div>
    </slick>
  </div>
</template>

<script>

import Slick from 'vue-slick'

export default {
  components: {
    Slick
  },
  data: function () {
    return {
      showSlide: true,
      slideCount: 0,
      slickOptions: {
        slidesToShow: 5
      }
    }
  },
  created () {
    this.slideCount = 5
  },
  watch: {
    slideCount () {
      this.reInit()
    }
  },
  beforeCreate () {
  },
  methods: {
    plus () {
      this.slideCount++
    },
    minus () {
      this.slideCount--
    },
    next () {
      this.$refs.slick.next()
    },

    prev () {
      this.$refs.slick.prev()
    },
    reInit () {
      this.showSlide = false
      this.$nextTick(() => (this.showSlide = true))
    }
  }
}
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む