- 投稿日:2020-04-06T22:24:52+09:00
意外と難しい?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終わりに
- 投稿日:2020-04-06T21:34:24+09:00
岡山県版新型コロナウイルス対策サイトを開発・運用している話
はじめに
岡山県版新型コロナウイルス対策サイト(非公式)の運用のルサカです。
今回は岡山県版新型コロナウイルス対策サイトを開発・運用の過程について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/
- 投稿日:2020-04-06T18:57:34+09:00
Nuxt.jsでスライダーを導入してみた【vue-awesome-swiper】
はじめに
人材系ベンチャーでシステムの開発をしている私ですが、「UI/UX色々変えちゃおうぜ!!」ってなったので
その一つを紹介していきますううううう
ちなみにフロントはNuxtでバックエンドはRailsAPI使ってますううううう環境
- MacOS
- yarn 1.21.1
- node 12.0.0
- vue 2.6.1
- vue-awesome-swiper 2.1.3
- docker
解決したい問題
以前のデザイン
新デザイン
「案件の数がトップページで4つしか出ないのは微妙だなー」
「スマホでの冗長化えぐいなあ」
って思っていました。
これを解決するには「スライダーの導入や!!!」となり、実装するに至りました。※ついでに中のカードのデザインも変えちゃいました(笑)
vue-awesome-swiperの導入
ターミナルyarn add vue-awesome-swiper今回はvue-awesome-swiperを使用しましたー
pluginに追加
plugins/vue-slider-component.jsimport 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.jsmodule.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にあれこれ記載してくだけでスライダーをカスタマイズできるんですね。
素晴らしい
カスタマイズ(パラメーター)はここでは説明しきれないくらいたくさん種類があるので、是非公式を見て試してみてください。
公式ドキュメントページネーションとナビゲーション
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>
の中に入れることもできるのでお好みでどうぞ。
レスポンシブ対応
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を使ってスライダーの実装を行いました!!!
社内でも「デザイン良くなった!!」と言われて喜んでます
フリエンというフリーランスエンジニアの案件サイトを作っているので興味があったら覗いてみてください(宣伝しても給料がアップするわけではありませんが、、、)
- 投稿日:2020-04-06T15:58:57+09:00
【メモ】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>
で回避しておくのが安全か。コンソールにもサーバー側のログにもエラーが出ないので原因を特定するのに困った。
……なんだコレ?
- 投稿日:2020-04-06T14:41:45+09:00
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>余談: 数字 + 文字列を入力してみた
まずは数字だけ入力
文字列を含んで入力
ちょっと嫌がらせで色んな文字列を入力してみました。
うまく数字だけバインドされているみたいです!素晴らしい!!
その他のテスト
間に文字列
"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>
- 投稿日:2020-04-06T14:41:45+09:00
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>余談: 数字 + 文字列を入力してみた
まずは数字だけ入力
文字列を含んで入力
ちょっと嫌がらせで色んな文字列を入力してみました。
うまく数字だけバインドされているみたいです!素晴らしい!!
その他のテスト
間に文字列
"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>
- 投稿日:2020-04-06T09:56:34+09:00
Vuetifyのv-btnのアルファベットが大文字になるのを抑制する
課題
vuetifyで用意されているボタン、
v-btn
でボタン名がアルファベットの場合は、必ず大文字となります。このように
v-btn
でSend Email
というボタン名にすると、以下の図のように大文字となります。
これをそのまま表示するようにしたい。<v-card class="mb-5 mt-5"> <v-card-actions> <v-btn>Send Email</v-btn> </v-card-actions> </v-card>解決法
個別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>参考URL
- 投稿日:2020-04-06T03:18:15+09:00
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>