- 投稿日:2021-03-15T23:30:59+09:00
Vuetify v-data-tableのslotの探検
デフォルトの表示
単純にデータを渡して、v-data-tableで表するとこのような表示になります
Slotの働き調査
item.<name> slotを使うことで表示を変更できます。試しに"AAA"を指定すると
manufactureの列がAAAになりました。<template> <div> <v-data-table :headers="headers" :items="desserts"> <template v-slot:item.manufacture> AAA </template> </v-data-table> </div> </template>特定の列の表示方法を変更する
試しに、メーカ名の前にiconを付加してみます。データの値は、
props.item.manufacture
に格納されています。
propsの部分は、v-slot:item.manufacture="XXX"
の"XXX" 部分と同じ文字にします。<template> <div> <v-data-table :headers="headers" :items="desserts"> <template v-slot:item.manufacture="props"> <v-icon>mdi-home</v-icon>{{props.item.manufacture}} </template> </v-data-table> </div> </template>データをEditできるようにする
Editできるようにする列のslotにv-edit-dialogを指定するとデータを編集できるようになります。
v-edit-dialogのinput slotに入力に使用するコンポーネントを指定する必要があります。
この例ではv-text-fieldを使い、type="Number"(数値入力用)を指定しいます。
v-model.number="props.item.quantity"
の様に.numberを付けておくと、入力値が数値して扱われるので、001のような入力をしても1に変換されるようになります。<template> <div> <v-data-table :headers="headers" :items="desserts"> <template v-slot:item.quantity="props"> <v-edit-dialog :return-value.sync="props.item.quantity" > {{ props.item.quantity }} <template v-slot:input> <v-text-field v-model.number="props.item.quantity" label="Edit" single-line type="Number" ></v-text-field> </template> </v-edit-dialog> </template> </v-data-table> </div> </template>
- 投稿日:2021-03-15T21:46:09+09:00
Nuxtでlocalhost:3000がなんかおかしい
- 投稿日:2021-03-15T18:47:24+09:00
【JavaScript】axiosでCSVを受け取りブラウザでファイルダウンロードに移行させる方法。
前提
サーバーサイドはLaravel、フロントはVue.jsです。
今回はJavaScriptの話がメインなのでPHPやLaravelが分からない方でも支障なく読んでいただけると思います。やりたかったこと
ユーザー目線:ブラウザに表示されているダウンロードボタンをクリックすると、CSVファイルをダウンロードできる。
僕目線:LaravelでCSVを吐き出すAPIを用意し、axiosを使ってAPIを叩きCSVをダウンロードできるようにする。
起こった問題
ブラウザの検索タブでエンドポイントに直接アクセスするとうまくダウンロードできるが、axiosを使ってエンドポイントにアクセスするとダウンロードできない。(CSVの内容はデータとして返ってくるが、ブラウザがダウンロード画面に移行しない。)
失敗した方法
CSVを返すAPIを単純に叩いてダウンロードできると思ったのですが、うまくいきませんでした。
※関係ない部分は色々省略してます。sample.jsdownloadCsv() { axios .get("/api/download/csv", { }) .catch((error) => { console.log(error.messagae); }); },CSVのデータはちゃんと返ってきますが、ブラウザがダウンロードに移行しません。(ユーザー目線だと何も起こらない。)
うまくいった方法
コードを下記のようにかえるとうまくダウンロードできました。
sample.jsimport saveAs from "file-saver"; // 省略 downloadCsv() { axios .get("/api/download/csv", { responseType: "blob", }) .then((res) => { let mineType = res.headers["content-type"]; const name = res.headers["content-disposition"]; const blob = new Blob([res.data], { type: mineType }); saveAs(blob, name); }) .catch((error) => { console.log(error.messagae); }); };追記部分を解説していきます。
リクエスト時の処理
sample.js.get("/api/download/csv", { responseType: "blob", })データをBLOBとして受け取ります。
BLOBとはBinary Large OBject
の略で、IT用語辞典では以下のように解説されています。BLOBとは、データベースのフィールド定義などで用いられるデータ型の一つで、テキスト(文字列)や整数のように既存のデータ型としては用意されていない任意のバイナリデータを格納するためのもの。
つまり、BlOBはテキストファイルだけではなく画像やPDFなどいろいろな形式のファイルを扱うことができる訳です。
そしてJavaScriptでは受け取ったデータをBOLBにするとこで、ファイルにすることが可能になります。
CSVはテキストデータなのでBLOBにする必要はないのでは?と思ったのですが、データをファイルにするために必要なようです。
レスポンスを受け取った後の処理
sample.js.then((res) => { let mineType = res.headers["content-type"]; const name = res.headers["content-disposition"]; const blob = new Blob([res.data], { type: mineType }); saveAs(blob, name); })
res.headers["content-type"]
にはLaravel側で設定した'text/csv'
が格納されています。今回は必ず'text/csv'
が返るようになっていますが、ダウンロード用のメソッドを色々な形式に対応できるようにするためにこのように書く必要がありますね。
res.headers["content-disposition"]
にはLaravel側で設定したファイル名が格納されています。
new Blob([res.data], { type: mineType });
JavaScriptのBlobオブジェクトのインスタンスを生成しています。
BlobオブジェクトはBLOBをJavaScriptで扱うためのオブジェクトです。
第一引数にファイルの内容の配列、第二引数にファイルの種類を指定して使います。
saveAs(blob, "file");
'file-server'
というライブラリを使ってファイルを保存しています。
詳しくは割愛しますが、ブラウザ間で異なるファイル保存の処理を1行で書けます。文字化けを修正
無事CSVをダウンロードすることができましたが、ファイルの内容が文字化けしていました。
はっきりとした原因は分かりませんでしたが、Laravel側でSJIS
形式に変換していた部分をUTF-8
に変換するように変更すると文字化けしなくなりました。sample.php// mb_convert_encoding($content, 'SJIS', 'auto'); mb_convert_encoding($content, 'UTF-8', 'auto');HTMLのmetaタグでUTF-8に指定しているのが原因なのか?
とりあえず、これで内容も分かるCSVファイルをダウンロードできるようになりました。めでたしめでたし。最後に
aixosを使ってファイルをダウンロードするにはひと手間いることが分かりました。
BLOBについては恥ずかしながら全然知らなかったです。今回はLaravel側でCSVを作成しましたが、データをJSON形式で送るようにしてVue側でCSVを作成することもできそうです。
他にもこんな方法があるとか、ここ間違ってるよとかあればご指摘等よろしくお願いします!
ではでは。
- 投稿日:2021-03-15T18:28:34+09:00
Vue.js コンポーネント
コンポーネント
templateのなかにHTML書く
Vue.jsVue.component('button-preference', { data() { return { count: 0 }; }, methods: { countUp() { this.count += 1; }, }, template: ` <button v-on:click="countUp"> {{ count }} いいね! </button> `, }); new Vue({ el: '#example', });グローバル登録
Vue.jsVue.component('button-preference', { template: ` <button>いいね!</button> ` }); Vue.component('button-empathy', { template: ` <button>そだねー</button> `, }); Vue.component('buttons-sns', { template: ` <div> <button-preference></button-preference> <button-empathy></button-empathy> </div> `, }); new Vue({ el: '#example', });#ローカル登録
ローカル登録するにはまず、コンポーネントをオブジェクトとして定義します。
プロパティ名はクォーテーションで囲ってください。
components
プロパティーを使うVue.jsconst buttonPreference = { template: ` <button>いいね!</button> `, }; const buttonEmpathy = { template: ` <button>そだねー</button> `, }; //上の二つのコンポーネントをしたで使う const buttonsSns = { components: { 'button-preference': buttonPreference, 'button-empathy': buttonEmpathy, }, template: ` <div> <button-preference></button-preference> <button-empathy></button-empathy> </div> `, };上記のbuttonsSnsコンポーネントをVueインスタンスで使う↓
vue.jsnew Vue({ el: '#example', components: { 'buttons-sns': buttonsSns, }, });一部省略<!DOCTYPE html> <body> <div id="example"> <buttons-sns></buttons-sns> </div> </body> </html>親から子にデータを渡す
new Vue{{...}}
== 親
butoon-sns
== 子vue.jsnew Vue({ el: '#example', components: { 'buttons-sns': buttonsSns, }, });
props
を使ってデータ渡す
このデータには、dataオプションのデータと同じようにアクセスできます。
つまり、this.ooo
でアクセス??? (定かではない)vue.jsconst buttonPreference = { props: ['initialCount'], template: ` <button> {{ initialCount }} いいね! </button> `, }; new Vue({ el: '#example', components: { 'button-preference': buttonPreference, }, });<body> <div id="example"> <button-preference initial-count="0"></button-preference> </div> <script src="main.js"></script> </body> </html>補足:名前のつけ方
javascriptでは
キャメルケース
(initialCount )
テンプレート(HTML)ではケバブケース
(initial-count)props
props: ['count', 'counts', 'value'],と複数指定可能
props: { count: { type: Number, required: true, }, counts: { type: Array, required: true, }, },↑とpropsのルール指定可能
公式 https://jp.vuejs.org/v2/guide/components-props.html#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3EXAMPLE
vue.jsconst buttonPreference = { props: { initialCount: { type: Number, required: true, }, }, template: ` <button> {{ initialCount }} いいね! </button> `, }; new Vue({ el: '#example', components: { 'button-preference': buttonPreference, }, });<div id="example"> <button-preference initial-count="0"></button-preference> </div>
initial-count='0'
でエラー(文字列だから)解決方法
<div id="example"> <button-preference v-bind:initial-count="0"></button-preference> </div>v-bindを使う
- 投稿日:2021-03-15T16:14:30+09:00
【Vue.js】Vue.js(Nuxt.js)とContentfullでブログ機能を実装
はじめに
弊社プロダクトでNuxt×Contentfullを使用したブログ機能を実装したので、ここに記しておきます〜
弊社で2年ほど運営しているオウンドメディアがあったのですが、
CVRも低く、SEOも下がり気味だったので、マーケとの協議の結果、
「本プロダクトに記事をがっちゃんこして、運営体制見直さね?」となったわけです!
ブログ用のAPIと管理画面作るの面倒だし、Contentfullイケてそうだなあ〜と思って実装に入りました!!環境
- MacOS
- yarn 1.21.1
- node 12.0.0
- vue 2.6.1
Contentfullの設定
まずはContentfullの設定をしていきましょう!
①Contentfullに新規登録・ログイン
Contentfullトップページからログインボタンを押してログイン画面へ。
アカウントを持っていない人はサインアップしてください。
(持っている人はそのままログインでOK)
必要情報を入力して新規アカウント作成!
英語なので少し読みづらいですね〜
②スペースの作成
新規登録・ログインができたらスペースを作成します。
スペースはプロジェクト単位で作成すると良いと思います!
初期設定では「The example project」というスペースが作成されているので、必要なければ削除してしまいましょう!
料金プランが選べるので、選択します。
プランによってDB容量やアカウントの管理権限設定が異なるようですが、まずはじめは無料で良いのかなと思います。
無料プランでは保存できる記事とアセット(画像など)の合計が5000個までなので、100記事くらいのメディアであれば無料で十分ですね。
ちなみに無料プランは各アカウントにつき1つしか作れないそうなので、無料プランを選択したい人は「The example project」を削除しておきましょう!③コンテンツモデルの作成
スペースができたらコンテンツの中身の設定をしていきましょう。
サイドバーから先ほど作ったスペースを選択します。
ヘッダーに出てきた「Content Model」を選択し、コンテンツモデルを作成。
任意の名前と詳細を入力します。
今回は記事コンテンツを作るため、「Post」という名前にしました。
④フィールドの追加
コンテンツモデル内にフィールドを追加していきます。
記事の入力項目ですね!
テキストや数字など様々選択できます。
「slug」を追加しました。urlになる文字列ですね。
今回は「slug」「title」「description」「thumbnail」「content」の5つを追加しました。
- 「slug」…urlになる文字列
- 「title」…記事のタイトル
- 「description」…記事の概要
- 「thumbnail」…サムネイル画像
- 「content」…コンテンツの内容
各フィールドごとに細かい設定も可能です。
「settings」から設定できます。
今回は入力必須のバリデーションを設定します。
他にも文字制限やユニーク制限もありますね。
これで一旦、Contentfull側の設定は完了です
Nuxt.jsの設定
dotenvの追加
アプリケーションにdotenvの追加
ターミナルnpm install --save @nuxtjs/dotenv もしくは yarn add @nuxtjs/dotenvルート直下に.envを作成
ターミナルtouch .envContentfullでSPACE_IDとACCESS_TOKENを確認する。
確認したSPACE_IDとACCESS_TOKEとPOST_TYPE_IDを.env内に記載する。
.env#CONTENTFUL CTF_SPACE_ID=xxxxxx CTF_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxnuxt.config.jsでdotenvを読み込み
nuxt.config.jsrequire("dotenv").config()Contentfullプラグインの追加
Contentfullプラグインを追加します。
ターミナルnpm install contentful もしくは yarn add contentfulpluginsフォルダにcontentful.jsを作成。
plugins/contentful.jsconst contentful = require('contentful') module.exports = contentful.createClient({ space: process.env.CTF_SPACE_ID, accessToken: process.env.CTF_ACCESS_TOKEN })nuxt.config.jsに諸々設定
nuxt.config.jsrequire("dotenv").config() const client = require("./plugins/contentful") // ~中略~ module.exports = { env: { // CONTENTFULの API_KEY を使う CTF_SPACE_ID: process.env.CTF_SPACE_ID, CTF_ACCESS_TOKEN: process.env.CTF_ACCESS_TOKEN }, } plugins: [ { src: '@/plugins/contentful' } ] // ~中略~ generate: { routes() { return client .getEntries({ content_type: 'column' }) .then(entries => { return entries.items.map(entry => { return { route: "/posts/"+entry.fields.slug, payload: entry } }) }) }プラグインや環境変数の読み込みをします。
またgenerateでslugをURLにする記載をしています。記事一覧ページ
pages配下にpostsフォルダーを作成し、その中にindex.vueを作成する。
これが記事一覧ページになります。
コードは参考までに、、、posts/index.vue<template> <section class="posts-lists-page"> <h1 class="title-h1 title-bottom">コラム一覧</h1> <div class="posts"> <nuxt-link v-for="(post, index) in posts" :to="'posts/'+post.fields.slug" :key="index" class="post"> <div class="post-thumb"> <img :src="post.fields.thumbnail.fields.file.url" class="post-thumb__img"> </div> <div class="post-text"> <p class="post-text__date">{{ formatDate(post.sys.createdAt) }}</p> <h2 class="post-text__title">{{ post.fields.title }}</h2> </div> </nuxt-link> </div> </section> </template> <script> import content from '~/plugins/contentful' export default { head() { return { title: this.title, meta: [ { hid: 'description', name: 'description', content: this.description }, { hid: 'og:url', name: 'og:url', content: `https://furien.jp${this.$route.path}` }, { hid: 'og:title', name: 'og:title', content: this.title }, { hid: 'og:description', name: 'og:description', content: this.description }, { hid: 'twitter:title', name: 'twitter:title', content: this.title }, { hid: 'twitter:description', name: 'twitter:description', content: this.description } ] } }, data() { const title = 'コラム一覧' return { title: title, description: `${title}|役立つ記事を沢山配信しています。` } }, methods: { formatDate(iso) { const date = new Date(iso) const yyyy = new String(date.getFullYear()) const mm = new String(date.getMonth() + 1).padStart(2, '0') const dd = new String(date.getDate()).padStart(2, '0') return `${yyyy}.${mm}.${dd}` } }, asyncData({ params }) { return content .getEntries({ content_type: 'column', order: '-sys.createdAt' }) .then(entries => { return { posts: entries.items } }) .catch(e => console.log(e)) } } </script> <style lang="scss" scope> .posts-lists-page { .posts { margin: 0 auto; padding: 10px; display: flex; flex-direction: row; flex-wrap: wrap; .post { width: calc(100% / 2 - 20px); margin: 10px; background: #fff; text-decoration: none; color: #111; border: 1px solid rgba(162, 162, 162, 0.5); @include sp-small { width: 100%; } &-thumb { width: 100%; padding-bottom: 75%; position: relative; overflow: hidden; &__img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 100%; } } &-text { padding: 1rem; &__date { font-size: 1.2rem; color: gray; } &__title { width: fit-content; font-size: 2rem; font-weight: bold; @include sp-small { font-size: 1.5rem; } } } } } } </style>スタイルや表示する内容は適宜変更してくださいね〜
こんな感じになりますね!記事詳細ページ
postsフォルダー内に_slugフォルダーを作成し、その中にindex.vueを作成する。
これが記事詳細ページになります。posts/_slug/index.vue<template> <article class="article-page"> <div class="article"> <BreadCrumbs :title="post.fields.title" /> <h1 class="article__title">{{ post.fields.title }}</h1> <p class="article__date">{{ formatDate(post.sys.createdAt) }}</p> <div class="article__content" v-html="toHtmlString(post.fields.content)"/> </div> </article> </template> <script> import { BLOCKS } from '@contentful/rich-text-types' import { documentToHtmlString } from '@contentful/rich-text-html-renderer' import content from '~/plugins/contentful' export default { head() { const ogImage = this.post.fields.thumbnail.fields.file.url return { title: this.post.fields.title, meta: [ { hid: 'description', name: 'description', content: this.post.fields.description }, { hid: 'og:url', name: 'og:url', content: `https://furien.jp${this.$route.path}` }, { hid: 'og:title', name: 'og:title', content: this.post.fields.title }, { hid: 'og:description', name: 'og:description', content: this.post.fields.description }, { hid: 'og:image:secure_url', name: 'og:image:secure_url', content: ogImage }, { hid: 'twitter:title', name: 'twitter:title', content: this.post.fields.title }, { hid: 'twitter:description', name: 'twitter:description', content: this.post.fields.description }, { hid: 'twitter:image', name: 'twitter:image', content: ogImage } ] } }, methods: { formatDate(iso) { const date = new Date(iso) const yyyy = new String(date.getFullYear()) const mm = new String(date.getMonth() + 1).padStart(2, '0') const dd = new String(date.getDate()).padStart(2, '0') return `${yyyy}.${mm}.${dd}` }, toHtmlString(obj) { const options = { renderNode: { [BLOCKS.EMBEDDED_ASSET]: ({ data: { target: { fields } } }) => `<img src="${fields.file.url}"/>` } } return documentToHtmlString(obj, options) } }, asyncData({ params, error, payload }) { if (payload) return { post: payload } return content .getEntries({ content_type: 'column', 'fields.slug': params.slug }) .then(entries => { return { post: entries.items[0] } }) .catch(e => console.log(e)) } } </script> <style lang="scss" scope> .article-page { .article { margin: 0 auto; padding: 1rem; color: #222; &__title { margin: 5% 0; font-size: 3rem; font-weight: bold; @include sp-small { font-size: 2rem; } } &__date { font-size: 1.4rem; color: $dark-gray; } &__content { //〜中略〜 } } } </style>ここでのポイントはコンテンツをリッチテキストにしている点と画像の処理方法ですね!
コンテンツをリッチテキストにしたのは移行の際に、マーケがコピペで記事を移行できるようにするためです
いろんなやり方があると思いますので、試してみてください!サーバー(heroku)の環境変数
あとは本番環境にも.envに設定した環境変数を設置してあげればOKです!!
完成!!
![]()
これで完成です!!!
細かい設定、表示内容やスタイルなどは各々カスタマイズしていただければOKです!
Contentfull公式も結構丁寧に解説してくれてるので、一読してみてくださいね〜おわりに
最近わりと大きなプロジェクトのPMを任されていて、なかなかコードをかけない日々を送っています
時間を見つけてコード書けるように精進していきます〜参考
ContentfulとNuxtの連携の仕方①
https://izm51.com/posts/nuxt-contentful-netlify-blog-making-1/
ContentfulとNuxtの連携の仕方②
https://izm51.com/posts/nuxt-contentful-netlify-blog-making-2/
ContentfulのRichtextで画像を表示する方法
https://github.com/contentful/rich-text/issues/61
画像表示
https://tech.hajimari.inc/entry/2019/06/05/171553
- 投稿日:2021-03-15T15:35:29+09:00
【JavaScript】別ファイルに関数をまとめてexportsを利用して呼び出す。
開発環境
React.js
概要
JavaScriptで関数を共通化して別ファイルにまとめたときに、HTMLのscriptタグを使い呼び出すのは面倒だと思いました。JavaScriptのexportsを使い呼び出すことができることを知りましたので記事にしておきます。
import.jsとexport.jsファイルを作成
import.jsからexport.jsの関数を呼び出していきます。
export.jsexports.criminalIsKogoro = function () { console.log("犯人は毛利小五郎"); } exports.detectiveCriminal = function (name) { console.log("犯人は" + name); } const criminalIsAgasa = function () { console.log("犯人は阿笠だ"); }比較するためにcriminalIsAgasaだけはexportsしないようにしておきます。
import.jsimport exportFunction from 'export.jsのパスを記述' // または // var exportFunction = require('export.jsのパスを記述'); exportFunction.criminalIsKogoro; // "犯人は毛利小五郎" exportFunction.detectiveCriminal("元太"); //"犯人は元太" exportFunction.criminalIsAgasa; // error. exportFunction.criminalIsAgasa is not a functionこのようにexportsをしておかないと外部のファイルから読み込むことができないことが分かりました。
参考
- 投稿日:2021-03-15T15:35:29+09:00
【React.js】別ファイルに関数をまとめてexportsを利用して呼び出す。
開発環境
React.js
概要
React.jsで関数を共通化して別ファイルにまとめたときに、HTMLのscriptタグを使い呼び出すのは面倒だと思いました。JavaScriptのexportsを使い呼び出すことができることを知りましたので、備忘録として記事に残しておきます。
import.jsとexport.jsファイルを作成
import.jsからexport.jsの関数を呼び出していきます。
export.jsexports.criminalIsKogoro = function () { console.log("犯人は毛利小五郎"); } exports.detectiveCriminal = function (name) { console.log("犯人は" + name); } const criminalIsAgasa = function () { console.log("犯人は阿笠だ"); }比較するためにcriminalIsAgasaだけはexportsしないようにしておきます。
import.jsimport exportFunction from 'export.jsのパスを記述' // または // var exportFunction = require('export.jsのパスを記述'); exportFunction.criminalIsKogoro; // "犯人は毛利小五郎" exportFunction.detectiveCriminal("元太"); //"犯人は元太" exportFunction.criminalIsAgasa; // error. exportFunction.criminalIsAgasa is not a functionこのようにexportsをしておかないと外部のファイルから読み込むことができないことが分かりました。
参考
- 投稿日:2021-03-15T14:57:08+09:00
Vue.js始めてみました⑥(v-for)
この度Vue.jsを学び始めました。
その勉強内容をまとめますv-for
HTML要素を繰り返し表示する時にv-forを使います。
Vue.js//配列から順番に値を1つづつ取り出し表示する <タグ v-for="変数 in 配列> //指定した回数表示を繰り返す <タグ v-for="変数 in 最大値> //配列から値と番号を1つずつ取り出し表示する <タグ v-for="(変数,番号) in 配列">使い方
Vue.js//配列から1つずつ取り出す使い方 <div id="app"> <ul> <li v-for="item in Array">{{ item }}</li> </ul> </div> <script> new Vue({ el: '#app', data: { Array:['いちご','メロン','バナナ','りんご'] } }) </script>上記のではArrayという配列にdataで配列データを用意しておき、それをv-forで順番に取り出し{{ item }}に入れて出力しています。
以下のようにすると配列データを番号付きで出力することもできます。
Vue.js//配列から1つずつ取り出し、番号付きで表紙する <div id="app"> <ul> <li v-for="(item,index) in Array">{{ index }}:{{ item }}</li> </ul> </div> <script> new Vue({ el: '#app', data: { Array:['いちご','メロン','バナナ','りんご'] } }) </script>以上です。
- 投稿日:2021-03-15T09:05:22+09:00
実務でよく使うVueのv-bind:classの使い方4つ
v-bind:classはVueで使えるv-bindディレクティブの一つです。
公式で紹介されてるものより、個人的には使い勝手がいいなと思う方法など、自分がよく使う4パターンを紹介します。1.真偽値に対して複数クラス
例:アクティブの時はテキストを青くして背景をグレーにしたい
sample.vue<div :class="{'text-blue bg-grey': isActive}"></div>2.複数の真偽値
例:アクティブの時はテキストを青くして、選ばれている時は背景をグレーにしたい
sample.vue<div :class="{ 'text-blue' : isActive , 'bg-grey' : isSelected }"></div>3.式(演算子)を使う
比較演算子や論理演算子を使って真偽値をかえします。
sample.vue<div :class="{'text-blue': apple == sale }"></div> <div :class="{'text-blue': apple > 3}"></div> <div :class="{'text-blue': apple && banana}"></div> <div :class="{'text-blue': apple || banana}"></div>4.三項演算子(条件分岐)
例:アクティブの時はテキストを青くしてそうじゃなかったらテキストを黒くしたい
sample.vue<div :class="isActive?'text-blue':'text-black'"></div>