- 投稿日:2020-06-27T23:16:25+09:00
【Vue】mixin / directives / filters / Vue Routerについてまとめてみたよ
Vueまとめ3(上級編)
こちらの記事は、Adnan Babakan 氏によりDev.to上で公開された『 Vue cheat sheet 3 』の邦訳版です(原著者から許可を得た上での公開です)
原著をベースに説明の足りない部分は適宜、追記しています。
(追記・改変の許可は得ています。)
DEV.toコミュニティの皆さん、こんにちは!
Vueまとめシリーズは多くの注目を集めたので、シリーズの公開を続けることにしました。これは、ほとんどすべての主要な初心者向けの事柄が以前のものでカバーされているので、これは少し高度になっています。
いくつかのコードサンプルは公式ウェブサイトから引用しています。Vue.jsで確認できます。1
mixins
- ミックスイン簡単に言うと、ミックスインは別々のファイルに保存されるコンポーネントの一部であり、他のコンポーネントで再使用可能なもの。
ミックスインは次のよう書くことができる。
// define a mixin object export const myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('Hello from mixin!') } } }ご覧のとおり、これには
created
フックとhello
というメソッドがあるので、このmixinを次のようにコンポーネントで使うことができる。<script> import { myMixin } from './myMixin.js' export default { mixins: [myMixin] } </script>したがって、このコンポーネントでこれらのフックとメソッドを記述した場合と同様に機能する。
ミックスインが競合した場合
コンポーネント自身のプロパティまたはメソッドとミックスインの間に競合がある場合は、ミックスインではなくコンポーネントの方が優先される。
let mixin = { data: function () { return { message: 'hello', foo: 'abc' } } } new Vue({ mixins: [mixin], data: function () { return { message: 'goodbye', bar: 'def' } }, created: function () { console.log(this.$data) // ミックスインではなくコンポーネントのdataになっている // => { message: "goodbye", foo: "abc", bar: "def" } } })Vueによる上書きの処理方法は変更できるが、それについては別の記事で説明する。
Vue.mixin()
- グローバルミックスイングローバルミックスインは、作成されたすべてのVueインスタンスをスコープに含むという以外は通常のミックスインと同様の機能を提供する。
import Vue from 'vue' Vue.mixin({ methods: { sayHi() { alert('Salam!') } } }); const app = new Vue({ el: '#app' })このメソッド
sayHi
は、上記のコードのすべてのコンポーネントとVueインスタンスで使用できる。
directives
- カスタムディレクティブご存じのとおり、ディレクティブはVueがDOMを処理する方法だ。たとえば、
v-model
やv-show
はディレクティブだ。ディレクティブを定義するには、次のようにする。
<script> export default { directives: { focus: { inserted: function (el) { el.focus() } } } } </script>focusディレクティブは、
v-focus
として次のように使うことができるようになる。// コンポーネントがレンダリングされるとすぐにinput要素がフォーカスされる <input v-focus />
Vue.directives()
- カスタムグローバルディレクティブカスタムディレクティブをVueインスタンス全体でグローバルに使用できるようにするには、次のように定義する。
Vue.directive('focus', { inserted: function (el) { el.focus() } })
filters
- フィルターフィルターは、単に値を変更してそれを返すために使用される。
それらは、ムスタッシュ構文とv-bind
ディレクティブの両方で使うことができる。コンポーネントでフィルターを定義するには、次のように定義する。
<script> export default { filters: { capitalize: function(value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } } </script>定義したcapitalizeフィルターは次のように使うことができる。
<span>{{ msg | capitalize }}</span>または、以下のように
v-bind
でも使うことができる。<a v-bind:href="url | capitalize">My capitalized link!</a>
Vue.filter()
- グローバルフィルターグローバルフィルターは通常のフィルターと同じだが、一度定義すると、すべてのVueインスタンスまたはコンポーネントで使用可能。
import Vue from 'vue' Vue.filter('focus', { capitalize: function(value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } })Vue Router
Vue Routerは、Vueを使用してクライアント側でルーティングシステムを設計するために使われる。
Vue Routerを使い始める
ルーターの使用を開始するには、ルーターをインストールする必要がある。
手順を紹介する。Vue Routerのインストール
npmを使用してインストールする(推奨)。
npm i vue-router --save
次のファイルを含めることでもインストールできる。
<script src="/path/to/vue.js"></script> <script src="/path/to/vue-router.js"></script>インストール後、VueにVueRouterを使用するよう指示する。
次の通り。import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)ルートにバインドされているコンポーネントは、ページのどこかにレンダリングする必要があります。これは次のように
router-view
タグを使って宣言される。<div id="app"> <div> Hello World! </div> <router-view></router-view> </div>ルートの定義
各ルートには、独自の固有のコンポーネントがバインドされる。以下のようにルートを定義できる。
const routes = [ { path: '/foo', component: require('./path/to/foo/component') }, { path: '/bar', component: require('./path/to/bar/component') } ] const router = new VueRouter({ routes // `routes: routes`の省略記法 })ユーザーのブラウザの履歴へルートを残したい場合は、以下のように履歴モードをアクティブにする必要がある。
const router = new VueRouter({ mode: 'history', routes // `routes: routes`の省略記法 })次に、ルートをVueインスタンスにアタッチする。
const app = new Vue({ router }).$mount('#app')履歴モードを使用している場合、すべてのリクエストを
index.html
ファイルにリダイレクトしてVueが残りの処理を行えるようにするには、Webサーバーの設定をする必要がある。そうしないと、ページ上でブラウザを更新することにより、そのページが実際にはサーバー上に存在しないため、404が返されてしまうことに注意。` - ルーターリンク
ルーターリンクは、ページを更新せず、必要なコンポーネントのみを取得するため(そして履歴モードで履歴にURLをプッシュするため)特別なもので、新しいページに切り替わったように見える。
ハイパーリンク(
a
タグ)の代わりに、router-link
を次のように使用する必要がある。<router-link to="/foo">Go to foo</router-link>高度なルーティング
Vue Routerはには単純なルーティング機能以外に、ルーティングを処理する優れた方法を他にも用意している。
動的ルーティング
動的ルートは、取得するいくつかのパラメータを持つ一連のルートを照合するために使用される。
動的ルートは、通常のルートと同様に定義されるが、動的セグメントの先頭にコロンが付いている。
const routes = [ { path: '/user/:username', component: require('./path/to/user/component') }, ]これで、
/user/adnanbabakan
、/user/dev/
または/user/vue
などのルートは全て有効になる。以下のようにルート内の
username
対応するコンポーネントには次のようにしてアクセスすることができる。<div>This is {{ $route.params.username }}'s profile!</a>動的ルートのパラメーター変更への対応
上記の例を考えてみよう。ユーザが
/user/adnanbabakan
から/user/dev
に移動する場合、同じコンポーネントをレンダリングしようとするので、Vueは以前のインスタンスを破棄しない。$route
オブジェクトで見ることのできるどんなparamsの変化にも対応するためにライフサイクルフックが呼び出されることはない。<script> export default { watch: { $route(to, from) { } } } </script>404ルーティング
すべてのWebサイトには、優れた404ルートが必要だ。Vue Routerでは、最後にアスタリスクルート
*
を定義して、定義されていないすべてのものをキャッチすることができる。アスタリスクルートは、他のルートの最後とその後に定義する必要がある。そうしないと、このアスタリスクルートは他のすべてと一致し、ルーティングシステムを破壊してしまうことに注意だ。
そのためには、以下のコードをご覧ください。
const routes = [ // 他のルートを書いた後に404となるルートを書く { path: '*', component: require('./path/to/404/component' } ]アスタリスクルート
アスタリスクを使用すると、別の種類の動的ルートを照合可能だ。動的ルートは2つのスラッシュ間の動的セグメントだけを照合可能だが、アスタリスクはそれとは別のことができる。
次のルートを見てみよう。
const routes = [ { path: '/user-*', component: require('./path/to/user/component') } ]このように書くことで、
/user-adnan
、および/user-dev
のようなルートでページはレンダリング可能だ。
$route.params
を使うことによってと呼ばれるプロパティがpathMatch
と呼ばれるプロパティをもつことができる。このプロパティはアスタリスクと一致した部分が含んでいる。
たとえば
/user-adnan
ページの$route.params.pathMatch
ははが返されadnan
を返す。名前付きルート
名前付きルートは、短い名前で長いルートパターンにアクセスするために使用される。
次のようなパターンがあるとする。
const routes = [ { path: '/user/profile/setting/', component: require('./path/to/user/component') } ]次のように名前を定義できる。
const routes = [ { path: '/user/profile/setting/', component: require('./path/to/user/component'), name: 'settings' } ]これで、リンクは次のように書ける。
<router-link :to='{name: "settings"}'> Profile settings </router-link>代わりにこう書くこともできる。
<router-link to="/user/profile/setting/"> Profile settings </router-link>オブジェクトを
to
属性に渡すときは、バインドする必要があることに注意だ。パラメータ付きの名前付きルート
先述の例のように、一部のルートにはパラメータがある場合があるがそれらの名前も定義できる。
const routes = [ { // usernameというパラメータを持っているが名前を付けることが可能 path: '/posts/from/:username', component: require('./path/to/posts/component'), name: 'posts' } ]そして、これのリンクを作成する時は、次のように書くことができる。
<router-link :to='{ name: "posts", params: {username: "adnanbabakan"} }'>Profile settings</router-link>プログラムによるナビゲーション
先に書いたように、
<router-link></router-link>
を使用してルーターリンクを作成することができるが、プログラムでユーザーをリダイレクトする必要がある場合はどうだろうか。さて、このコードでそれを行うことができるrouter.push('/foo');このコードはユーザーを
/foo
にリダイレクトする。これは特に、ログイン後のリダイレクトなどの状況で使用される。プログラムによる名前付きナビゲーション
You can also use
router.push()
for named routes like this:
このような名前付きルートにもrouter.push()
を使うことができる。router.push({name: 'myRoute'});パラメータのある場合のプログラムによるナビゲーション
同様に
router.push()
は次のようにparamsと一緒にリダイレクトするために使用できる。router.push({name: 'myRoute', params: {paramOne: 'Hello', paramTwo: 'Salam'}})ルートリダイレクト
ルートは、次のように相互にリダイレクトされるように定義できる。
const routes = [ { path: '/foo', redirect: '/bar' } ]名前付きリダイレクトのルート
次のように、ルートを名前付きルートにリダイレクトすることもできる。
const routes = [ { path: '/foo', redirect: { name: 'myRoute' } } ]動的ルートリダイレクト
A route can be redirected using a function to evaluate the destination, like this:
次のように、宛先を評価する関数を使用してルートをリダイレクトできます。const routes = [ { path: '/foo', redirect: to => { // the function receives the target route as the argument // return redirect path/location here. } } ];パラメータを使用したルートリダイレクト
ターゲットルートにパラメータがある場合は、リダイレクト先にも渡すことができる。
const routes = [ { path: '/profile/:username', redirect: '/user/:username' } ]ルートエイリアス
ルートエイリアスとは、1つのルートがアクセスされるための複数のアドレスをもつことができるとい機能だ。
次が例。
const routes = [ { path: '/foo', alias: '/bar' } ];これで
/foo
というルートは/bar/
でもアクセスすることができる。1つのルートは複数のエイリアスを持つこともできる。
const routes = [ { path: '/foo', // 配列に複数のエイリアスを指定できる alias: ['/bar', '/baz'] } ];
- 投稿日:2020-06-27T23:01:14+09:00
[随時更新] 自分のVue.jsの命名規則
自分のルール
以下の例のように、コンポーネント定義側とコンポーネント呼び出し側ともにパスカルケース(=アッパーキャメルケース)記法の複数英単語で命名する。
コンポーネント定義側
BaseCard.vue<template lang="pug"> .BaseCard nuxt-link(:to ="slug") img.Card__img(:src="img") p.Card__role {{role}} p.Card__title {{title}} </template>コンポーネント呼び出し側
src/pages/works/index.vue<template lang="pug"> .Works .wrapper template(v-if="works.length") ul.WorksList template(v-for="work in works") li.WorksList__item BaseCard(:slug="'works/' + work.fields.slug" :img="work.fields.img.fields.file.url" :role="work.fields.role" :title="work.fields.title") </template>Why 複数英単語
Vue.jsスタイルガイドに記載されている通り、HTMLとの衝突を避けるため。HTMLのタグ名は単数英単語の場合が多く、複数英単語にすることで衝突が避けられる。
- 投稿日:2020-06-27T20:09:57+09:00
nuxt.js vue-form-wizardフォームにsimple-vue-validatorバリデーションを実装してみました。
はじめに
以前作った
vue-form-wizard
ステップフォームにsimple-vue-validatorを追加してみました。
以前作成したステップフォームはこちらです。普通inputに
<input type='text' required= 'required'>
だけでもフロントのバリデーションは走らせることができますがやりたい実装としては下記のイメージのようにerrorMsgをinputの下に表示させようとしています。
Simple Vue Validator
一番カンタンだったのでSimple Vue Validatorを使って実装します。目次
- NPMパッケージをインストール
- プラグイン登録
- Simple Vue Validator呼び出し
- バリデーションチェック項目登録
- errorMsg追加
- html上に記載
- 終わり
1. NPMパッケージをインストール
$ npm i --save simple-vue-validator $ npm i --D simple-vue-validator $ npm i simple-vue-validatorどちらでも大丈夫です
2. プラグイン登録
最初componet直に呼び出しても使えなかったので調べてみましたがなかなかNuxtでの使い方の参考があまりなくてで調べるのに黒しました。結論プラグインに登録しないと行けませんでした。
登録をするためにはファイルを作成が必要です。
plugins/Vuelidate.js
を作成します。plugins/Vuelidate.jsimport Vue from 'vue' import SimpleVueValidation from 'simple-vue-validator' Vue.use(SimpleVueValidation)nuxt.config.jsplugins: [ '~/plugins/Vuelidate', ],pluginsに登録後nuxtconfigに再度呼び出しをするとグローバルでつかえるようになります。
3. Simple Vue Validator呼び出し
呼び出したconponentのscriptタグに
simple-vue-validator
を呼び出しが必要です。import SimpleVueValidation from 'simple-vue-validator' const Validator = SimpleVueValidation.Validator
simple-vue-validator
を呼び込んでValidator
に割当をします。4. バリデーションチェック項目登録
<script> methods: { validateStepOne: function(){//stepOneに移動した場合チェックfunction //OneStepCheckField return this.$validate( 'stepForm.oneStep.name',//stepOneチェックしたいフォームmodel。 ), validateStepTow: function(){//stepTwoに移動した場合チェックfunction //TwoStepCheckField return this.$validate( 'stepForm.stepTwo.mail',//stepTwoチェックしたいフォームmodel。 ) } </script>チェックしたいフォームを定義していきます。
oneSteVvalidation
とtwoSteVvalidation
のfunctionを分けた理由はvue-form-wizard
は一枚にindexをタブ形式で画面を表示したり非表示にする仕組みなのでバリデーションを分けないとステップ全部バリデーションが走ってしまうため1ステップから2ステップに移動した場合既にエラーメッセージが出てしいる状態になってしまいます。他のやり方があるかもしれないですが自分はこのやり方でやってみました。もしフォームが追加した場合は
[配列]
で囲んでチェックしたいmodelを追加することもできます。//追加したい場合の例 validateStepOne: function(){ //OneStepCheckFields return this.$validate([ 'stepForm.oneStep.name', 'stepForm.oneStep.tel' ]),5. errorMsg追加
validators: { //oneStepErrorMsgs 'stepForm.oneStep.name': function(value) { return Validator.value(value).required('未選択です')//ここにエラーメッセージ }, //twoStepErrorMsgs 'stepForm.stepTwo.mail': function(value) { return Validator.value(value).required('未選択です').email('メールアドレスが正しくありません')//ここにエラーメッセージ }, }errorメッセージのルールもカンタンに追加することができます。
//例 email('メールアドレスが正しくありません') digit('数字以外は入力できません')バリデーションルールを詳しは公式を参考してください。
6. html上に記載
上記に
validateStepOneのfunction()
をform-wizard
のtab-content
追加をします。
エラ〜メッセージのボックスも必要です。:before-change="oneSteVvalidation" //funtion.message {{ validation.firstError('modelName') }}index.vue<template lang="pug"> .container h2 {{ pageName }} form-wizard tab-content( title:'ONESTEP', :before-change="oneSteVvalidation" //<-ここfunction ) .inputBox input( type='text', v-model='stepForm.oneStep.name' ) .message {{ validation.firstError('stepForm.oneStep.name') }}//<-エラーメッセージ tab-content( title:'TWOSTEP', :before-change="oneSteVvalidation" //<-ここfunction ) .inputBox input( type='email', v-model='stepForm.stepTwo.mail' ) .message {{ validation.firstError('stepForm.stepTwo.name') }}//<-エラーメッセージ tab-content( title:'確認' ) .confirm name : {{ stepForm.oneStep.name }} email : {{ stepForm.oneStep.name }} button( slot="prev" ) 前のステップへ button( slot="next" ) 次のステップへ button( type="button" slot="finish") 送信 </template> <script> import SimpleVueValidation from 'simple-vue-validator'//SimpleVueValidation呼び出し const Validator = SimpleVueValidation.Validator//割当 import {FormWizard, TabContent} from 'vue-form-wizard' export default { components: { FormWizard, TabContent, } data(){ return{ pageName: 'contact', stepForm : { stepOne : { name : '' }, stepTwo : { mail : '' }, } }, methods: { validateStepOne: function(){//stepOneに移動した場合チェックfunction //OneStepCheckField return this.$validate( 'stepForm.oneStep.name',//stepOneチェックしたいフォームmodel。 ), validateStepTow: function(){//stepTwoに移動した場合チェックfunction //TwoStepCheckField return this.$validate( 'stepForm.stepTwo.mail',//stepTwoチェックしたいフォームmodel。 ) }, validators: { //oneStepErrorMsgs 'stepForm.oneStep.name': function(value) { return Validator.value(value).required('未選択です')//ここにエラーメッセージ }, //twoStepErrorMsgs 'stepForm.stepTwo.mail': function(value) { return Validator.value(value).requhired('未選択です').email('メールアドレスが正しくありません')//ここにエラーメッセージ } }, } </script>7. 終わり
vue-form-wizard
にsimple-vue-validator
使ってバリデーションを走らせて完成度が少し上がっていきました。
- 投稿日:2020-06-27T20:09:57+09:00
nuxt.js vue-form-wizardステップフォームにsimple-vue-validatorバリデーションを実装してみました。
はじめに
以前作った
vue-form-wizard
ステップフォームにsimple-vue-validatorを追加してみました。
以前作成したステップフォームはこちらです。普通inputに
<input type='text' required= 'required'>
だけでもフロントのバリデーションは走らせることができますがやりたい実装としては下記のイメージのようにerrorMsgをinputの下に表示させようとしています。
Simple Vue Validator
一番カンタンだったのでSimple Vue Validatorを使って実装します。目次
- NPMパッケージをインストール
- プラグイン登録
- Simple Vue Validator呼び出し
- バリデーションチェック項目登録
- errorMsg追加
- html上に記載
- 終わり
1. NPMパッケージをインストール
$ npm i --save simple-vue-validator $ npm i --D simple-vue-validator $ npm i simple-vue-validatorどちらでも大丈夫です
2. プラグイン登録
最初componet直に呼び出しても使えなかったので調べてみましたがなかなかNuxtでの使い方の参考があまりなく調べるのに黒しました。結論プラグインに登録しないと行けませんでした。
登録をするためにはファイルを作成が必要です。
plugins/Vuelidate.js
を作成します。plugins/Vuelidate.jsimport Vue from 'vue' import SimpleVueValidation from 'simple-vue-validator' Vue.use(SimpleVueValidation)nuxt.config.jsplugins: [ '~/plugins/Vuelidate', ],pluginsにファイル作成したら
nuxt.config.js
に登録をするとグローバルでつかえるようになります。3. Simple Vue Validator呼び出し
使用したいcomponentのscriptタグに
simple-vue-validator
を呼び出しが必要です。import SimpleVueValidation from 'simple-vue-validator' const Validator = SimpleVueValidation.Validator
simple-vue-validator
を呼び込んでValidator
に割当をします。4. バリデーションチェック項目登録
<script> methods: { validateStepOne: function(){//stepOneに移動した場合チェックfunction //OneStepCheckField return this.$validate( 'stepForm.oneStep.name',//stepOneチェックしたいフォームmodel。 ), validateStepTow: function(){//stepTwoに移動した場合チェックfunction //TwoStepCheckField return this.$validate( 'stepForm.stepTwo.mail',//stepTwoチェックしたいフォームmodel。 ) } </script>チェックしたいフォームを定義していきます。
oneStepValidation
とtwoStepValidation
のfunctionを分けた理由はvue-form-wizard
で作ったフォームが一枚にindexをタブ形式で入力画面を表示したり非表示にする仕組みなのでバリデーションを分けないとステップ全部バリデーションが走ってしまうため1ステップから2ステップに移動した場合既にエラーメッセージが既に出てしいる状態になってしまいます。他のやり方があるかもしれないですが自分は分けてfunctionを走らせるようにしました。もしフォームが追加した場合は
[配列]
で囲んでチェックしたいmodelを追加することもできます。//追加したい場合の例 validateStepOne: function(){ //OneStepCheckFields return this.$validate([ 'stepForm.oneStep.name', 'stepForm.oneStep.tel' ]),5. errorMsg追加
validators: { //oneStepErrorMsgs 'stepForm.oneStep.name': function(value) { return Validator.value(value).required('未選択です')//ここにエラーメッセージ }, //twoStepErrorMsgs 'stepForm.stepTwo.mail': function(value) { return Validator.value(value).required('未選択です').email('メールアドレスが正しくありません')//ここにエラーメッセージ }, }errorメッセージのルールもカンタンに追加することができます。
//例 email('メールアドレスが正しくありません') digit('数字以外は入力できません')バリデーションルールを詳しは公式を参考してください。
6. html上に記載
上記に
validateStepOneのfunction()
をform-wizard
のtab-content
追加をします。
エラ〜メッセージのボックスも必要です。:before-change="oneSteVvalidation" //funtion.message {{ validation.firstError('modelName') }}index.vue<template lang="pug"> .container h2 {{ pageName }} form-wizard tab-content( title:'ONESTEP', :before-change="oneSteVvalidation" //<-ここfunction ) .inputBox input( type='text', v-model='stepForm.oneStep.name' ) .message {{ validation.firstError('stepForm.oneStep.name') }}//<-エラーメッセージ tab-content( title:'TWOSTEP', :before-change="oneSteVvalidation" //<-ここfunction ) .inputBox input( type='email', v-model='stepForm.stepTwo.mail' ) .message {{ validation.firstError('stepForm.stepTwo.name') }}//<-エラーメッセージ tab-content( title:'確認' ) .confirm name : {{ stepForm.oneStep.name }} email : {{ stepForm.oneStep.name }} button( slot="prev" ) 前のステップへ button( slot="next" ) 次のステップへ button( type="button" slot="finish") 送信 </template> <script> import SimpleVueValidation from 'simple-vue-validator'//SimpleVueValidation呼び出し const Validator = SimpleVueValidation.Validator//割当 import {FormWizard, TabContent} from 'vue-form-wizard' export default { components: { FormWizard, TabContent, } data(){ return{ pageName: 'contact', stepForm : { stepOne : { name : '' }, stepTwo : { mail : '' }, } }, methods: { validateStepOne: function(){//stepOneに移動した場合チェックfunction //OneStepCheckField return this.$validate( 'stepForm.oneStep.name',//stepOneチェックしたいフォームmodel。 ), validateStepTow: function(){//stepTwoに移動した場合チェックfunction //TwoStepCheckField return this.$validate( 'stepForm.stepTwo.mail',//stepTwoチェックしたいフォームmodel。 ) }, validators: { //oneStepErrorMsgs 'stepForm.oneStep.name': function(value) { return Validator.value(value).required('未選択です')//ここにエラーメッセージ }, //twoStepErrorMsgs 'stepForm.stepTwo.mail': function(value) { return Validator.value(value).requhired('未選択です').email('メールアドレスが正しくありません')//ここにエラーメッセージ } }, } </script>7. 終わり
vue-form-wizard
にsimple-vue-validator
使ってバリデーションを走らせて完成度が少し上がっていきました。
- 投稿日:2020-06-27T19:34:23+09:00
IndexedDB + Vue CLI, markdown対応のtodoを作る
概要
前と同様、IndexedDB + Vue CLIで
Dexie.js ライブラリを使用した構成となります。・RDB, APIサービス等を使用しない。
ブラウザ側の IndexedDBにデータ保存する。シンプル構成となります。構成
Chrome 83
Vue CLI
dexie : 3.0.1
vue: 2.6.11
vue-router
marked: 1.1.0package.json
https://github.com/kuc-arc-f/vue_spa3b_2todo/blob/master/package.json
画面
実装など
・create
https://github.com/kuc-arc-f/vue_spa3b_2todo/blob/master/src/components/DexieTodos/new.vue・index
https://github.com/kuc-arc-f/vue_spa3b_2todo/blob/master/src/components/DexieTodos/Index.vue・show
https://github.com/kuc-arc-f/vue_spa3b_2todo/blob/master/src/components/DexieTodos/show.vue・edit
https://github.com/kuc-arc-f/vue_spa3b_2todo/blob/master/src/components/DexieTodos/edit.vue
参考ページ
IndexedDB + Dexie.js で CRUDの作成、Vue CLI版
https://qiita.com/knakaqi/items/765a1fb37a53a26278e9
- 投稿日:2020-06-27T17:00:12+09:00
VSCode の Vetur で types/vue-shim.d.ts が有効にならないのはワークスペースにフォルダが複数あるから
注意:執筆時点での情報です。 Vetur の将来のバージョンでは解消される可能性があります。
概要
そのまま件名の通りなのですが、
Vue.js で*.vue
ファイルを作り、<script lang="ts">
でコンポーネントを作るときには、
types
フォルダにvue-shim.d.ts
等のファイルを作って、型定義をすると思います。types/vue-shim.d.tsdeclare module "*.vue" { import Vue from 'vue' export default Vue }Visual Studio Code (VSCode) で Vetur プラグインを導入して、
TypeScript で Vue コンポーネントを作ったりします。my-component.vue<script lang="ts"> import Vue from 'vue' export default Vue.extend({ methods: { helloWorld () { this.$emit('say', 'Hello, world!') } } }) </script>すると、 Vetur の型ヒントでは
this
もthis.$emit
もany
となってしまいます。原因
この問題について、 Vetur のリポジトリに Issue が上がっていました。
https://github.com/vuejs/vetur/issues/1817#issuecomment-614789578In my case it's because I am using a multiroot workspace via 'Add Folder to Workspace'. When I take a project root into its own workspace, the problem goes away.
VSCode の Workspace に複数のルートフォルダが登録されていると、
Vetur がtypes
フォルダを正しく解析できない、ということのようです。解決策
1つの Workspace には、1つのルートフォルダのみにすると、正常に動作します。
このエントリが、困っているどなたかの助けになったら幸いです。
- 投稿日:2020-06-27T16:47:51+09:00
Vue.jsで糖質制限の情報をまとめたサイトを作った
はじめに
こんなサイトを作りました。
https://lowcarb-recommend.com/
3月中旬くらいにそろそろ手を出すか~とVue.jsのお勉強を始め、ゴールデンウィーク終わりごろにそろそろ何か作りたいなーと思っていた時、ちょうど自粛生活で太り気味で糖質制限ダイエットを始めていたので、それに関する情報をまとめたサイトを作ろうと思い作成を始めました。
どんな機能があるの?
機能としては下記3点です。
- 糖質制限食をランキングで閲覧
- 糖質制限レシピの閲覧
- 糖質制限に関するニュースの閲覧
1.の糖質制限食に関しては楽天市場系APIより情報を取得し、ショップごと、もしくはジャンルごと(パンや麺類など)で検索をかけられるようにしました
2.の糖質制限レシピについては、これも楽天レシピ系APIより情報を取得しています。
3.のニュースに関してはGoogle NewsよりRSSを取得しています。
環境
- Java
- Spring Boot
- Vue.js(Vue Router、Vuex、Vuetify)
- Swiper.js
- Heroku
- Mongo DB
- Netlify
もともとはVue.jsを使いたかったためフロントエンドは確定として、バックエンドはどうしようかなーと思ってたのですが、全部が慣れていないものだと作るのに時間がかかる→最後まで作り切れなさそうと少しビビっていたので業務で使っているJavaを選びました。
製作期間
- 2か月弱
バックエンドは、仕事で使っているJavaということもあり、2週間足らずで終わらせることができました。
フロントエンドについては、学び始めたばかりのVue.jsということもあり、1か月半かけて調べながら完成させました。苦労したところ
下記に、苦労した点と参考にさせていただいたものをまとめます。
ニュース情報をどう集めるか
当初はニュース関連のサービスでよく使われているであろうNews APIを使おうと思ってました。
しかし、9割9分自分の使い方がまずかったと思うのですが、うまく糖質制限に関する情報を取得できず、代替案を考えていたところ、Google NewsよりRSSを取得する方法を見つけたので、それに切り替えました。Google News RSSを取得する方法は下記を参考にさせていただきました。
https://qiita.com/KMD/items/872d8f4eed5d6ebf5df1
http://mogakana.blogspot.com/2011/05/javarss.htmlSwiper.jsの使い方
「TOPページになにか動くの導入してやろ~」と思いいろいろ調べてみると、当ライブラリに出会いました。
トップページに写真の上にキャプションをうまく載せられなかったり、うまくレスポンシブにできなかったりといろいろ思考錯誤しました。Swiper.jsに関しては下記を参考にさせていただきました。
https://qiita.com/whike_chan/items/c68e094f412b04b1afc2
https://github.surmon.me/vue-awesome-swiper/
https://www.kabanoki.net/4783/PWA化
開発も終盤にかかってきたところ、せっかくだしPWA化して「ホーム画面に追加」って出るとかっこいいなと思いいろいろ試したがなかなかLighthouseでOKにならない。
コンソールを見てみると下記エラーが出てました。consoleSite cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
さらに「bad-precaching-response」のようなエラーも出ていました。
Netlifyのデプロイ時に置いている_redirectsファイルのキャッシュを更新しようとする→そんなファイル無いぞと怒られるのが原因みたいだったため、下記サイトを参考にキャッシュ対象から除外しました。vue.config.jsに下記を書くことで解決しました。
vue.config.jsmodule.exports = { //省略 pwa: { workboxPluginMode: 'GenerateSW', workboxOptions: { exclude: /_redirects/ } } }https://michimani.net/post/programming-build-pwa-with-vuejs/
教訓
開発中、大枠は1か月くらいでできた(つもりだった)ため、もうすぐ終わるだろうと思っていたら、結局2か月かかってしまいました。
細かいところで修正したいところがたくさん出てくるんですよね、、開発しながら下記故事成語があったな~と思いだしたので、今後開発するときはこれを頭に入れておいて、「9割終わったと思うけど多分まだ5割なんだよな~」と思っておくと気が楽になるかもしれません、、百里を行く者は九十を半ばとす
https://imidas.jp/proverb/detail/X-02-C-27-8-0010.htmlおわりに
いろいろ書きましたが、ぜひ使ってみてください!
ロカボのススメ
- 投稿日:2020-06-27T16:47:51+09:00
自粛生活で太ったので、糖質制限の情報をまとめたサイトを作った
はじめに
こんなサイトを作りました。
https://lowcarb-recommend.com/
3月中旬くらいにそろそろ手を出すか~とVue.jsのお勉強を始め、ゴールデンウィーク終わりごろにそろそろ何か作りたいなーと思っていた時、ちょうど自粛生活で太り気味で糖質制限ダイエットを始めていたので、それに関する情報をまとめたサイトを作ろうと思い作成を始めました。
どんな機能があるの?
機能としては下記3点です。
- 糖質制限食をランキングで閲覧
- 糖質制限レシピの閲覧
- 糖質制限に関するニュースの閲覧
1.の糖質制限食に関しては楽天市場系APIより情報を取得し、ショップごと、もしくはジャンルごと(パンや麺類など)で検索をかけられるようにしました
2.の糖質制限レシピについては、これも楽天レシピ系APIより情報を取得しています。
3.のニュースに関してはGoogle NewsよりRSSを取得しています。
環境
- Java
- Spring Boot
- Vue.js(Vue Router、Vuex、Vuetify)
- Swiper.js
- Heroku
- Mongo DB
- Netlify
もともとはVue.jsを使いたかったためフロントエンドは確定として、バックエンドはどうしようかなーと思ってたのですが、全部が慣れていないものだと作るのに時間がかかる→最後まで作り切れなさそうと少しビビっていたので業務で使っているJavaを選びました。
製作期間
- 2か月弱
バックエンドは、仕事で使っているJavaということもあり、2週間足らずで終わらせることができました。
フロントエンドについては、学び始めたばかりのVue.jsということもあり、1か月半かけて調べながら完成させました。苦労したところ
下記に、苦労した点と参考にさせていただいたものをまとめます。
ニュース情報をどう集めるか
当初はニュース関連のサービスでよく使われているであろうNews APIを使おうと思ってました。
しかし、9割9分自分の使い方がまずかったと思うのですが、うまく糖質制限に関する情報を取得できず、代替案を考えていたところ、Google NewsよりRSSを取得する方法を見つけたので、それに切り替えました。Google News RSSを取得する方法は下記を参考にさせていただきました。
https://qiita.com/KMD/items/872d8f4eed5d6ebf5df1
http://mogakana.blogspot.com/2011/05/javarss.htmlSwiper.jsの使い方
「TOPページになにか動くの導入してやろ~」と思いいろいろ調べてみると、当ライブラリに出会いました。
トップページに写真の上にキャプションをうまく載せられなかったり、うまくレスポンシブにできなかったりといろいろ思考錯誤しました。Swiper.jsに関しては下記を参考にさせていただきました。
https://qiita.com/whike_chan/items/c68e094f412b04b1afc2
https://github.surmon.me/vue-awesome-swiper/
https://www.kabanoki.net/4783/PWA化
開発も終盤にかかってきたところ、せっかくだしPWA化して「ホーム画面に追加」って出るとかっこいいなと思いいろいろ試したがなかなかLighthouseでOKにならない。
コンソールを見てみると下記エラーが出てました。consoleSite cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
さらに「bad-precaching-response」のようなエラーも出ていました。
Netlifyのデプロイ時に置いている_redirectsファイルのキャッシュを更新しようとする→そんなファイル無いぞと怒られるのが原因みたいだったため、下記サイトを参考にキャッシュ対象から除外しました。vue.config.jsに下記を書くことで解決しました。
vue.config.jsmodule.exports = { //省略 pwa: { workboxPluginMode: 'GenerateSW', workboxOptions: { exclude: /_redirects/ } } }https://michimani.net/post/programming-build-pwa-with-vuejs/
教訓
開発中、大枠は1か月くらいでできた(つもりだった)ため、もうすぐ終わるだろうと思っていたら、結局2か月かかってしまいました。
細かいところで修正したいところがたくさん出てくるんですよね、、開発しながら下記故事成語があったな~と思いだしたので、今後開発するときはこれを頭に入れておいて、「9割終わったと思うけど多分まだ5割なんだよな~」と思っておくと気が楽になるかもしれません、、百里を行く者は九十を半ばとす
https://imidas.jp/proverb/detail/X-02-C-27-8-0010.htmlおわりに
いろいろ書きましたが、ぜひ使ってみてください!
ロカボのススメ
- 投稿日:2020-06-27T15:37:45+09:00
Nuxt.jsでMarkdownを静的に埋め込む
初めまして、インターンシップの一環でとある Web サイト改修のお仕事をさせてもらっています。
その内容の 1 つに、現在 marked で動的に読み込んでいる記事を静的なページにあらかじめ埋め込んで置けるようにする、という要求があります。さらに、図表番号などを前処理でつける必要があります。現在は一枚の html から動的に読み込みつつ処理しているようなので、もしかすると結構な大工事になりそうです。
Vue を触るのは初めてなので雰囲気を掴みつつ良さげな方法を探していこうと思います。フレームワークは?
さて、Vue で静的というと Vuepress や Nuxt.js が上がると思いますが、実際のページは単なる記事サイトではないので一旦 Vuepress は置いておくことにします。Nuxt ならば静的サイトを生成できるはずなので、Markdown を html に変換したものを Vue コンポーネントの中に埋め込むことができれば、いい感じに展開してくれるはずです(理解が正しければ)。
というわけで Nuxt を使うとするとコンポーネントとして読み込むのが良さそうなので、ひとまず Vue コンポーネントの中に Markdown を埋め込む(コンポーネントとして読み込む)というのを考えてみることにしました。ここで少し注意ですが、
nuxt generate
へのちょっとした勘違いから @nuxtjs/markdownit を候補から外していました。そのため試した順は一番最後となっていますが、@nuxtjs/markdownit でも静的に埋め込まれました。お急ぎの方はそちらからどうぞ。Webpackのローダー
標準的な Vue プロジェクトは Webpack を使っているようなので、手始めに Webpack のローダーで何かないかと調べました。そうすると結構出てくるんですが、どれもスターが微妙に少なかったり少し不安ですね。一応調べたものを列挙してみます。
markdown-to-vue-loader
調べると真っ先に出てきたのがこちらです。現状で GitHub のスター数が 23 とかなり心もとないですが、markdown をコンポーネントとして読み込みできそうです。まずは試してみましょう。
index.vue<template> <Md /> </template> <script lang="ts"> import Vue from 'vue' import Logo from '~/components/Logo.vue' import Md from '~/md/0.md' export default Vue.extend({ components: { Logo, Md, }, }) </script>nuxt.config.js// 一部省略 { build: { extend(config, { isDev }) { config.module.rules.push({ test: /\.md$/, exclude: /node_modules/, use: [ 'vue-loader', { loader: 'markdown-to-vue-loader', }, ], }) if (isDev) config.mode = 'development' }, }, }shims-md.d.ts// .mdを読み込める、ということにしておく declare module '*.md' {}ちゃんと埋め込みができているようです。markdown-it にはしっかりと設定も渡せるみたいです。
ware-loader + markdown-it
ware-loader というのは初めて聞きました。どうやら middleware として関数を渡しておくと、入力ソースに対して独自の処理ができるパッケージのようです。middleware の中で markdown-it に処理をさせてしまえば良いわけですね。
index.vue<template> <Md /> </template> <script lang="ts"> import Vue from 'vue' import Logo from '~/components/Logo.vue' import Md from '~/md/0.md' export default Vue.extend({ components: { Logo, Md, }, }) </script>nuxt.config.jsimport MarkdownIt from 'markdown-it' const md = new MarkdownIt() // 一部省略 { build: { extend(config, { isDev }) { config.module.rules.push({ test: /\.md$/, exclude: /node_modules/, use: [ 'vue-loader', { loader: 'ware-loader', options: { raw: true, middleware: (source) => `<template><div>${md.render(source)}</div></template>`, }, }, ], }) if (isDev) config.mode = 'development' }, } }shims-md.d.ts// .mdを読み込める、ということにしておく declare module '*.md' {}こちらもしっかりと埋め込みができました。
スターは 18 と非常に心もとないです。これは聞いたことがなくても仕方なさそう。ですがコードはかなりシンプルで、驚きの 62 行です。これなら最悪自分でメンテナンスできそうではあります。
この形式の良い点として、自前で処理用の関数を作れば Webpack の流れに乗せて前処理をしつつ、コンポーネント化までやってしまうことができそうです。
悪い点としては先ほどと同じく、メジャーではないパッケージを使うという不安さくらいでしょうか。開発者側としては利用者の多いパッケージを使いたくなりますね。Nuxtプラグイン
@nuxtjs/markdownit
最後の紹介になります。
Nuxt のコミュニティですでに Markdown を読み込めるプラグインが存在しました。スターも 1.1K となかなか信頼できそうなパッケージです。普通に読み込むだけならこのプラグインで良さそうですね。
index.vue<template> <div v-html="md"></div> </template> <script lang="ts"> import Vue from 'vue' import md from '~/md/0.md' export default Vue.extend({ computed: { md() { return md }, }, }) </script>nuxt.config.js// 一部省略 { modules: [ '@nuxtjs/markdownit', ], markdownit: { preset: 'default', linkify: true, breaks: true, use: ['markdown-it-div', 'markdown-it-attrs'], }, }shims-md.d.ts// stringとして.mdを読み込める、ということにしておく declare module '*.md' { const src: string export default src }こちらは Nuxt.js のコミュニティパッケージのようです。上の 2 つとは違って html 形式の文字列としてインポートできるようになっており、computed なメソッドを通して
v-html
で埋め込む流れのようです。(computed なのは再描画頻度を下げるためだと思います。)ここで少し勘違いをしてしまって、computed とはいえメソッドを通せば動的に処理されるのだろうと思っていました。しかし念の為
nuxt generate
で試してみると、何と静的に埋め込まれていました! どうやらnuxt generate
では静的に処理できる computed なものは html に埋め込まれてしまうようです。なるほどと思いながら、さらに methods ではどうなのか試して見ましたが、何とこちらも埋め込みされました...。これには流石に驚きですね。nuxt は魔術でも使っているんでしょうか...。
さらに気になるのは文字列として読み込んでいるところです。もし関数をインポートして適用したらどうなるのでしょうか。
結論から言うと、関数を適用した結果が html に埋め込まれました。もうびっくりです。前処理が必要だとしても、(Webpack などを使って)事前に行わなくて良いと言うことです。静的に処理できないパターンの罠はありそうですが、少なくとも今回のユースケースではかなり効果が出そうです。
どうするか
とにかく何らかの手段で埋め込みができることは確認できました。
色々調べましたが、
nuxt generate
を使うならば使い勝手は@nuxtjs/markdownitの圧勝ですね... 静的に処理できるものは勝手に埋め込んでくれるのが強すぎます。
正直まだよくわかっていませんが、nuxt generate
で静的に処理されるとすれば markdown-it を直接使ってもいいのかもしれません。raw-loader で md を文字列として読み込んでしまえば、html 化前に前処理を挟んでしまうこともできそうです。ところで、vuepress の良いところは md ファイルを特定のディレクトリに置いておけば、勝手にページを生成してくれる点です。リンクなどもできますし、かなりいい感じです。
もし前述の手段で Nuxt を使ったサイトを作るとすると、md ごとにページ用のコンポーネントが必要になりそうです。もしページが増えた時にコンポーネントも新しく作らなければならないとするとなかなか面倒です。この辺りを考えると、結局 Webpack の実行前に前処理が必要になってくるかもしれません。(ここまでの魔術を見せられると何らかの手段で出来そうな気もします。)まとめ
Markdown を静的に埋め込む手段について調査しました。
今回の結論は Nuxt.js を使うなら
@nuxtjs/markownit
を使っておけば面倒がなさそうと言うことです。nuxt generate
ならばかなり賢く処理してくれることがわかりました。
また、html 文字列へ変換する前に前処理が必要であれば raw-loader を使って文字列として読み込んでおき、任意の処理をした後に markdown-it なり marked で変換したものを埋め込むのも良さそうです。色々とあったのでかなり混乱しました。もし Nuxt.js ではなく Vue.js を使った開発なら他に挙げた手段が使えそうです。特に置換など md に少し手を加えたい場合には ware-loader + markdown-it も便利そうです。
今回はこのくらいでまとめておきたいと思います。何かの参考になれば幸いですが、間違いなどあれば教えていただけると嬉しいです。
- 投稿日:2020-06-27T13:22:49+09:00
【Vue.js入門】コンポーネント
アウトプット忘備録。間違えていたらごめんなさい。
コンポーネントとは
- ページを構成するUIの部品。
- 再利用がしやすいため、メンテナンス性が高まる。
コンポーネントを定義してみる
グローバルで定義
全てのvueインスタンスで使用可能。
<div id ="app"> <hoge-component></hoge-component> <!--hoge!が出力--> <hoge-component></hoge-component> <!--hoge!が出力(使い回しできる。)--> </div>Vue.component('hoge-component', { template: '<p>hoge!</p>' }) const app = new Vue({ el: '#app' })ローカルで定義
特定のvueインスタンスで呼び出したい時に使う。
<div id ="app"> <hoge-component></hoge-component> <!--hoge!が出力--> <hoge-component></hoge-component> <!--hoge!が出力(使い回しできる。)--> </div>//テンプレートを定数に格納 const hogeComponent = { template: '<p>hoge!</p>' } const app = new Vue({ el: '#app', components{ // ここのhoge-componentがテンプレート側で使えるようになる。 'hoge-component': hogeComponent } })コンポーネント名の注意
- ハイフンを一つ以上含む(ケバブケース)を使用する必要がある。
- キャメルケース等はダメ。
理由は、HTML要素との衝突を防ぐため。
オプション
コンポーネントでは、vueインスタンスと同様にtemplateだけでなくdateなどのオプションが使える。(elは使えない。)
下記はボタンを押すたびに、カウントが増えていくプログラム。
<div id ="app"> <button-count></button-count> </div>Vue.component('button-count', { data: function(){ return { count: 0 } }, template: '<button v-on:click="count++">{{ count }}</button>' }) const app = new Vue({ el: '#app' })dataを関数として定義しているのは、各インスタンスが独自のデータオブジェクトを使えるようにするため。