20210425のvue.jsに関する記事は10件です。

【Vue.js】transition ラッパーは単一要素/コンポーネントで使うと言う話とか

Vue.js のtransitionについて。 単一要素はtransitionで複数要素はtransition-groupと言う単純な覚え方ではアカンと思ったので、覚書。 前置き transitionは Vue.js で、 遷移とか移り変わりの表現をいい感じにしてくれるラッパーコンポーネントである。 要素のフェードイン / フェードアウトを簡単に実装する事が出来るので、そう言う例が多く見られるが、 要するにvueが用意してくれているトランジションクラス(v-enterとかv-leaveとか)を用いて、要素がDOMに追加、更新、削除される意図したタイミングでアニメーションを指定する事が出来る。 本題 transitionでラップ出来るのは次のようなケース ・条件付きの描画 (v-if を使用) ・条件付きの表示 (v-show を利用) ・動的コンポーネント ・コンポーネントルートノード (Component root nodes) で、これらは単一要素/コンポーネントである事が条件としてあると言う事。 <!-- これはダメ --> <transition> <div v-if="show">message1</div> <div v-if="show">message2</div> </transition> 対象が単一要素であれば良いので、これなら問題ない。 (まあ普通はこっちになると思うけど) <!-- これは良い --> <transition> <div v-if="show"> <div>message1</div> <div>message2</div> </div> </transition> またパターンをifや動的プロパティで表現する時に複数要素を指定するのは問題ない。 <!-- これは良い --> <transition> <button v-if="show === 'message1'" key="message1"> message1 </button> <button v-if="show === 'message2'" key="message2"> message2 </button> <button v-if="show === 'message3'" key="message3"> message3 </button> </transition> つまり、条件の単一要素と言うのは「独立したノード」又は「一度に1つのみ描画される複数ノード」であれと言う事。 またtransition-groupでも使う時に注意が必要な点がある。 ドキュメントにも重要であると書かれており、使う上で直ぐに気づくと思うが、v-forで回す要素をspanでラップする形でDOMが形成される。 これはtag属性で指定する事でspan以外のタグを設定する事が出来るが、場合によってはコーディングに影響が出るので注意が必要。 <transition-group name="list" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

うん、JavascriptのImportとVueのコンポーネントを使えるようになるぞ!

これまで、Javascriptのimportを特に使わず、グローバル宣言で満足していましたし、Vueも宣言的レンダリング(双方向バインディング)で満足していたのですが、世間様では、Importやコンポーネントをを使うことが当たり前になってきたので、使いこなせるように、いつも使っているテンプレート環境をアップデートします。 ついでに、いつもテンプレートの使い方を忘れるので、ここでまとめておきます。 テンプレートは以下のGitHubに上げてあります。 poruruba/express_template https://github.com/poruruba/express_template ※たびたび機能追加しているので、ここに記載していない機能も入っている可能性大です。 テンプレートでできること node.jsさえインストールしてあれば、すぐにWebページのホスティングサーバ、RESTサーバ、GraphQLサーバを立ち上げられるようにしています。また、HTMLページのひな型も置いており、よく使う機能はライブラリとしてまとめておいてあります。 今回の投稿では、HTMLのひな型の使い方のまとめです。 立ち上げ方 以下から、Code一式をダウンロードします。 poruruba/express_template https://github.com/poruruba/express_template > unzip express_template-master.zip > cd express_template-master > npm install > mkdir cert > npm run start 上記だけで、HTTPサーバが立ち上がります。 もし、HTTPSでも立ち上げたい場合には、certフォルダにSSL証明書ファイルを配置します。 app.js の以下の場所のファイル名を、配置したファイル名に合わせます。 app.js var options = { key: fs.readFileSync('./cert/server.key'), // 秘密鍵ファイル cert: fs.readFileSync('./cert/server.crt'), // SSL証明書ファイル ca: fs.readFileSync('./cert/JPRS_DVCA_G2_PEM.cer') //SSL中間証明書ファイル }; 特に何も指定しなければ、ポート番号は、HTTPは10080、HTTPSは10443で立ち上がります。 ポート番号を変えるには、.envに以下を記載します。 .env PORT=【HTTPのポート番号】 SPORT=【HTTPSのポート番号】 静的ページの作成 public/template に、静的ページのひな型がありますので、適当な名前でコピーします。この名前がURLでのパスになります。 public/test とした場合、URLは、http://localhost:10080/test となります。 Vue2とBootstrap5とその他もろもろを使っています。 あとは、Vueの宣言的レンダリング(双方向バインディング)の機能を使えばたいていのことは事足ります。 たとえば、以下のようにindex.htmlに追記して、 public/template/index.html <h1>Template</h1> {{message}} <button class="btn btn-primary" v-on:click="btn_clicked">Button Click</button> start.js の該当箇所に追記すると、 public/template/js/start.js data: { message: "Hello" }, computed: { }, methods: { btn_clicked: function(){ this.message = "World"; } ブラウザから見るとHelloと表示されて、ボタンを押すとWorldに変わります。 {{ }} やv-on:clickはVue、buttonやbtn btn-primaryはBootstrapの機能です。 プログレスダイアログの表示 時間がかかる処理をするときには、処理中であることがわかるようにプログレスバーのあるダイアログを表示してあげると便利です。 5秒間プログレスダイアログを表示したのちに消してみます。 プログレスダイアログの表示  this.progress_open(表示タイトル, backdrop = 'static'); プログレスダイアログの非表示  this.progress_close(); pubic/template/index.html <button class="btn btn-primary" v-on:click="progress_clicked">Progress Click</button> public/template/js/start.js methods: { progress_clicked: function(){ this.progress_open(“プログレス表示です。”); setTimeout(() =>{ this.progress_close(); }, 5000); } backdropには、’static’またはtrueまたはfalseが指定できます。 クリップボードへのコピー&ペースト Javascript標準のClipboard APIを使っています。 クリップボードへのコピー  this.clip_copy(文字列) クリップボードからペースト  this.clip_paste() モーダルダイアログ Bootstrapを使ったモーダルダイアログです。あらかじめ使いやすいようにコンポーネントとして登録しているため、以下のように使います。 index.html にモーダルダイアログの表示内容を定義します。 public/template/index.html <modal-dialog size="lg" id="dialog_test"> <div slot="content"> <div class="modal-header"> タイトル </div> <div class="modal-body"> 本文 </div> <div class="modal-footer"> <button class="btn btn-primary" v-on:click="dialog_close('#dialog_test')">閉じる</button> </div> </div> </modal-dialog> 後は、ボタン押下などの契機に、以下のように呼び出します。 public/template/js/start.js modal_clicked: function(){ this.dialog_open('#dialog_test'); } モーダルダイアログの表示  this.dialog_open(‘#【ダイアログのID】’); モーダルダイアログの非表示  this.dialog_close(‘#【ダイアログのID】’); アコーディオン Bootstrapのアコーディオン表示です。 扱いやすいようにコンポーネント化していますので、以下のように定義すればよいです。 public/template/index.html <collapse-panel id="accordion_test" title="タイトル" collapse="true"> <span slot="content"> <div class="card-body"> 本文 </div> </span> </collapse-panel> collapseをtrueにすれば、初期状態で畳んだ状態となり、falseにすれば開いた状態になります。以下のJavascriptでも動的に制御できます。 アコーディオンのオープン  this.panal_open(‘#【アコーディオンのID】’) アコーディオンのクローズ  this.panal_close(‘#【アコーディオンのID】’) トーストの表示 右上に、トーストを表示させます。複数同時に表示することができ、時間がたつと消えてくれます。 this.toast_show(message, level = "success") 内部で以下を使わせてもらっています。 ooyun0/siiimple-toast https://github.com/ooyun0/siiimple-toast Cookieを設定・取得する Cookieの設定  Cookies.set(‘【名前】', JSON.stringify(【設定したい値】), { expires: 365 }); Cookieの取得  var value = Cookies.get('【名前】'); 単にこちらを使わせていただいているだけです。 js-cookie/js-cookie https://github.com/js-cookie/js-cookie/tree/latest URLのQueryStringとフラグメント識別子 URLに指定されたQueryStringやフラグメント識別子は、mountedで呼び出している関数proc_load()で処理され、変数searchsとhashsに格納されています。 ・QueryString(?の後に続くパラメータ):searchs http://localhost:10080/test/index.html?param1=abcdの場合 searches = { param1: 'abcd' } ・フラグメント識別子(#の後に続くパラメータ):hashs http://localhost:10080/test/index.html#param1=abcdの場合 hashs = { param1: 'abcd' } Vueコンポーネント さあ、本題である、Vueコンポーネントを追加します。 例えば、こんなコンポーネントを作ります。 public/template/js/comp/comp_test.js export default { mixins: [mixins_bootstrap], template: ` <div> <h2>テストコンポーネント</h2> {{message}} </div>`, data: function () { return { message: 'Hello World', } }, methods: { } }; start.js に以下を追加します。 public/template/js/start.js /* add additional components */ import comp_test from './comp/comp_test.js'; vue_add_global_component('comp_test', comp_test); index.htmlに以下を追加します。 public/template/index.html <comp_test></comp_test> コンポーネントに以下のMixinsを入れているので、作成するコンポーネントの中で、前の方で説明したプログレスダイアログやモーダルダイアログ、アコーディオンも使えます。 mixins: [mixins_bootstrap], WebAPI呼び出し WebAPI呼び出しをよく使うので、関数を作っておきました。内部でfetchを使っており、Promiseが返ります。 以下、いくつかの種類がありますが、いずれもURLに加えて、パラメータをオブジェクトで渡します。 ・do_post (url, body)  JSON/POST(application/json)呼び出しです。 ・do_post_urlencoded (url, params)  application/x-www-form-urlencoded 呼び出しです。 ・do_post_formdata (url, params)  フォームデータを呼び出しているのと同じです。 ・do_get (url, qs)  GET呼び出しです。 戻り値は、JSON(application/json)を前提としているため、 public/js/vue_utils.js return response.json(); としています。異なる場合はそれに合わせて以下のように変更してください。 public/js/vue_utils.js // return response.json(); // return response.text(); // return response.blob(); // return response.arrayBuffer(); GraphQL呼び出し この呼び出しがすぐ忘れそうだったので、今回の記事をQiitaに投稿した理由です。 いろんな呼び出し方を用意したので、お好みでどうぞ。 また、X-API-Key(apikey)は、AWS Appsyncなど、必要に応じて設定してください。 public/template/js/start.js var base_url=”【GraphQLのエンドポイント】”; var p1 = “Hello”; var p2 = 1234; var templ = `query($param1: String, $param2: Int){ hello( param1: $param1, param2: $param2){ id } }`; var ret = await gql_query(base_url, templ, { param1: p1, param2: p2 }, apikey); var templ = `{ hello(param1: \"Hello\", param2: 1234){ id } }`; var ret = await gql_query(base_url, templ, null, apikey); var templ = gql_templ`{ hello(param1: ${0}, param2: ${1}){ id } }`; var ret = await gql_query(base_url, templ, [p1, p2], apikey); var templ = gql_templ`{ hello(param1: ${0}, param2: ${1}){ id } }`; var ret = await gql_query(base_url, templ(p1, p2), null, apikey); graqhql_requestやapolloなどいろいろあったのですが、WebPackなど使わず、Javascriptだけで手軽に使いたかったため自作し、js/gql_utils.js にまとめておきました。 仮想コンソールの表示 スマホでの表示など、Chrome DevToolsでconsole.logなどのコンソールの出力が見えないときに使います。(Remote devicesを使う方法もありますが、それよりも手軽です) start.js で以下の部分のコメントを外します。それだけです。 public/template/js/start.js const vConsole = new VConsole(); とはいっても、ただ単に、以下を使わせていただいているだけです。 Tencent/vConsole https://github.com/Tencent/vConsole dat.GUIを使う dat.GUIを表示させます。 監視対象に、Vueのデータを含められるようにしました。 dataarts/dat.gui https://github.com/dataarts/dat.gui 登録は以下の関数です。  this.datgui_add(property, p1, p2, p3) まずは、start.js の以下の部分のコメントを外します。 public/template/js/start.js window.datgui = new dat.GUI(); そうすると、以下のように右上に、dat.GUIが現れます。 例えば、このようなVueに定義を含めた場合に、 public/template/js/start.js data: { message: "Hello" }, 以下のように、mountedなどで、フィールド名を文字列で指定すると、dat.GUIに内容が表示されます。 public/template/js/start.js this.datgui_add("message"); 値が変われば自動的に右上のdat.GUIの表示も変わりますし、dat.GUIのところで値を変えれば、実際の値も変わります。 dat.GUIの仕様を参考に、p1, p2, p3も指定してみてください。 終わりに 次回は、WebAPIの定義方法を紹介しようと思います。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavascriptのImportとVueのコンポーネントを使えるようになってみる

これまで、Javascriptのimportを特に使わず、グローバル宣言で満足していましたし、Vueも宣言的レンダリング(双方向バインディング)で満足していたのですが、世間様では、Importやコンポーネントをを使うことが当たり前になってきたので、使いこなせるように、いつも使っているテンプレート環境をアップデートします。 ついでに、いつもテンプレートの使い方を忘れるので、ここでまとめておきます。 テンプレートは以下のGitHubに上げてあります。 poruruba/express_template https://github.com/poruruba/express_template ※たびたび機能追加しているので、ここに記載していない機能も入っている可能性大です。 テンプレートでできること node.jsさえインストールしてあれば、すぐにWebページのホスティングサーバ、RESTサーバ、GraphQLサーバを立ち上げられるようにしています。また、HTMLページのひな型も置いており、よく使う機能はライブラリとしてまとめておいてあります。 今回の投稿では、HTMLのひな型の使い方のまとめです。 立ち上げ方 以下から、Code一式をダウンロードします。 poruruba/express_template https://github.com/poruruba/express_template > unzip express_template-master.zip > cd express_template-master > npm install > mkdir cert > npm run start 上記だけで、HTTPサーバが立ち上がります。 もし、HTTPSでも立ち上げたい場合には、certフォルダにSSL証明書ファイルを配置します。 app.js の以下の場所のファイル名を、配置したファイル名に合わせます。 app.js var options = { key: fs.readFileSync('./cert/server.key'), // 秘密鍵ファイル cert: fs.readFileSync('./cert/server.crt'), // SSL証明書ファイル ca: fs.readFileSync('./cert/JPRS_DVCA_G2_PEM.cer') //SSL中間証明書ファイル }; 特に何も指定しなければ、ポート番号は、HTTPは10080、HTTPSは10443で立ち上がります。 ポート番号を変えるには、.envに以下を記載します。 .env PORT=【HTTPのポート番号】 SPORT=【HTTPSのポート番号】 静的ページの作成 public/template に、静的ページのひな型がありますので、適当な名前でコピーします。この名前がURLでのパスになります。 public/test とした場合、URLは、http://localhost:10080/test となります。 Vue2とBootstrap5とその他もろもろを使っています。 あとは、Vueの宣言的レンダリング(双方向バインディング)の機能を使えばたいていのことは事足ります。 たとえば、以下のようにindex.htmlに追記して、 public/template/index.html <h1>Template</h1> {{message}} <button class="btn btn-primary" v-on:click="btn_clicked">Button Click</button> start.js の該当箇所に追記すると、 public/template/js/start.js data: { message: "Hello" }, computed: { }, methods: { btn_clicked: function(){ this.message = "World"; } ブラウザから見るとHelloと表示されて、ボタンを押すとWorldに変わります。 {{ }} やv-on:clickはVue、buttonやbtn btn-primaryはBootstrapの機能です。 プログレスダイアログの表示 時間がかかる処理をするときには、処理中であることがわかるようにプログレスバーのあるダイアログを表示してあげると便利です。 5秒間プログレスダイアログを表示したのちに消してみます。 プログレスダイアログの表示  this.progress_open(表示タイトル, backdrop = 'static'); プログレスダイアログの非表示  this.progress_close(); pubic/template/index.html <button class="btn btn-primary" v-on:click="progress_clicked">Progress Click</button> public/template/js/start.js methods: { progress_clicked: function(){ this.progress_open("プログレス表示です。"); setTimeout(() =>{ this.progress_close(); }, 5000); } backdropには、’static’またはtrueまたはfalseが指定できます。 クリップボードへのコピー&ペースト Javascript標準のClipboard APIを使っています。 クリップボードへのコピー  this.clip_copy(文字列) クリップボードからペースト  this.clip_paste() モーダルダイアログ Bootstrapを使ったモーダルダイアログです。あらかじめ使いやすいようにコンポーネントとして登録しているため、以下のように使います。 index.html にモーダルダイアログの表示内容を定義します。 public/template/index.html <modal-dialog size="lg" id="dialog_test"> <div slot="content"> <div class="modal-header"> タイトル </div> <div class="modal-body"> 本文 </div> <div class="modal-footer"> <button class="btn btn-primary" v-on:click="dialog_close('#dialog_test')">閉じる</button> </div> </div> </modal-dialog> 後は、ボタン押下などの契機に、以下のように呼び出します。 public/template/js/start.js modal_clicked: function(){ this.dialog_open('#dialog_test'); } モーダルダイアログの表示  this.dialog_open(‘#【ダイアログのID】’); モーダルダイアログの非表示  this.dialog_close(‘#【ダイアログのID】’); アコーディオン Bootstrapのアコーディオン表示です。 扱いやすいようにコンポーネント化していますので、以下のように定義すればよいです。 public/template/index.html <collapse-panel id="accordion_test" title="タイトル" collapse="true"> <span slot="content"> <div class="card-body"> 本文 </div> </span> </collapse-panel> collapseをtrueにすれば、初期状態で畳んだ状態となり、falseにすれば開いた状態になります。以下のJavascriptでも動的に制御できます。 アコーディオンのオープン  this.panal_open(‘#【アコーディオンのID】’) アコーディオンのクローズ  this.panal_close(‘#【アコーディオンのID】’) トーストの表示 右上に、トーストを表示させます。複数同時に表示することができ、時間がたつと消えてくれます。 this.toast_show(message, level = "success") 内部で以下を使わせてもらっています。 ooyun0/siiimple-toast https://github.com/ooyun0/siiimple-toast Cookieを設定・取得する Cookieの設定  Cookies.set(‘【名前】', JSON.stringify(【設定したい値】), { expires: 365 }); Cookieの取得  var value = Cookies.get('【名前】'); 単にこちらを使わせていただいているだけです。 js-cookie/js-cookie https://github.com/js-cookie/js-cookie/tree/latest URLのQueryStringとフラグメント識別子 URLに指定されたQueryStringやフラグメント識別子は、mountedで呼び出している関数proc_load()で処理され、変数searchsとhashsに格納されています。 ・QueryString(?の後に続くパラメータ):searchs http://localhost:10080/test/index.html?param1=abcd の場合 searches = { param1: 'abcd' } ・フラグメント識別子(#の後に続くパラメータ):hashs http://localhost:10080/test/index.html#param1=abcd の場合 hashs = { param1: 'abcd' } Vueコンポーネント さあ、本題である、Vueコンポーネントを追加します。 例えば、こんなコンポーネントを作ります。 public/template/js/comp/comp_test.js export default { mixins: [mixins_bootstrap], template: ` <div> <h2>テストコンポーネント</h2> {{message}} </div>`, data: function () { return { message: 'Hello World', } }, methods: { } }; start.js に以下を追加します。 public/template/js/start.js /* add additional components */ import comp_test from './comp/comp_test.js'; vue_add_global_component('comp_test', comp_test); index.htmlに以下を追加します。 public/template/index.html <comp_test></comp_test> コンポーネントに以下のMixinsを入れているので、作成するコンポーネントの中で、前の方で説明したプログレスダイアログやモーダルダイアログ、アコーディオンも使えます。 mixins: [mixins_bootstrap], 以下も参考になるかも  Vueのカスタムコンポーネントで双方向データバインディングを入れてみた WebAPI呼び出し WebAPI呼び出しをよく使うので、関数を作っておきました。内部でfetchを使っており、Promiseが返ります。 以下、いくつかの種類がありますが、いずれもURLに加えて、パラメータをオブジェクトで渡します。 ・do_post (url, body)  JSON/POST(application/json)呼び出しです。 ・do_post_urlencoded (url, params)  application/x-www-form-urlencoded 呼び出しです。 ・do_post_formdata (url, params)  multipart/form-data呼び出しです。 ・do_get (url, qs)  GET呼び出しです。 戻り値は、JSON(application/json)を前提としているため、 public/template/js/vue_utils.js return response.json(); としています。異なる場合はそれに合わせて以下のように変更してください。 public/template/js/vue_utils.js // return response.json(); // return response.text(); // return response.blob(); // return response.arrayBuffer(); 以下も参考になるかも  fetchの呼び出し @Javascript & Node.js 実験室 GraphQL呼び出し この呼び出しがすぐ忘れそうだったので、今回の記事をQiitaに投稿した理由です。 いろんな呼び出し方を用意したので、お好みでどうぞ。 また、X-API-Key(apikey)は、AWS Appsyncなど、必要に応じて設定してください。 public/template/js/start.js var base_url="【GraphQLのエンドポイント】"; var p1 = "Hello"; var p2 = 1234; var templ = `query($param1: String, $param2: Int){ hello( param1: $param1, param2: $param2){ id } }`; var ret = await gql_query(base_url, templ, { param1: p1, param2: p2 }, apikey); var templ = `{ hello(param1: \"Hello\", param2: 1234){ id } }`; var ret = await gql_query(base_url, templ, null, apikey); var templ = gql_templ`{ hello(param1: ${0}, param2: ${1}){ id } }`; var ret = await gql_query(base_url, templ, [p1, p2], apikey); var templ = gql_templ`{ hello(param1: ${0}, param2: ${1}){ id } }`; var ret = await gql_query(base_url, templ(p1, p2), null, apikey); graqhql_requestやapolloなどいろいろあったのですが、WebPackなど使わず、Javascriptだけで手軽に使いたかったため自作し、js/gql_utils.js にまとめておきました。 仮想コンソールの表示 スマホでの表示など、Chrome DevToolsでconsole.logなどのコンソールの出力が見えないときに使います。(Remote devicesを使う方法もありますが、それよりも手軽です) start.js で以下の部分のコメントを外します。それだけです。 public/template/js/start.js const vConsole = new VConsole(); とはいっても、ただ単に、以下を使わせていただいているだけです。 Tencent/vConsole https://github.com/Tencent/vConsole dat.GUIを使う dat.GUIを表示させます。 監視対象に、Vueのデータを含められるようにしました。 dataarts/dat.gui https://github.com/dataarts/dat.gui 登録は以下の関数です。  this.datgui_add(property, p1, p2, p3) まずは、start.js の以下の部分のコメントを外します。 public/template/js/start.js window.datgui = new dat.GUI(); そうすると、以下のように右上に、dat.GUIが現れます。 例えば、このようなVueに定義を含めた場合に、 public/template/js/start.js data: { message: "Hello" }, 以下のように、mountedなどで、フィールド名を文字列で指定すると、dat.GUIに内容が表示されます。 public/template/js/start.js this.datgui_add("message"); 値が変われば自動的に右上のdat.GUIの表示も変わりますし、dat.GUIのところで値を変えれば、実際の値も変わります。 dat.GUIの仕様を参考に、p1, p2, p3も指定してみてください。 終わりに 次回は、WebAPIの定義方法を紹介しようと思います。 簡単にRESTサーバ・GraphQLサーバを立ち上げる 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuetifyを部分的に使う方法

この記事は Vuetifyを一部のコンポーネントのみ使用する方法を記録したものです。 vue-cliを用いている前提です。 背景 私はbootstrapにトラウマがあります。 それはなぜかというと、 最初はbootstrapに則ったデザインでいいと言われたのに 徐々に細かい修正指示が入り、 CSSにたくさんの!importantをつけなければいけない、 という事象があったからです。 なので私は極力CSSフレームワークを使いたくない。 しかし、開発速度やデザインの統一の関係で どうしてもVuetifyを使わなければいけないタイミングが来ました。 じゃあ、せめて他のコンポーネントに影響を及ぼさない、 部分的な使用方法はないのか、と探し始めたのが この記事の背景です。 手順 vuetifyをインストール vue add vuetify 生成された src/plugins/vuetify を編集 import Vue from 'vue' import Vuetify from 'vuetify/lib' Vue.use(Vuetify) const opts = {} export default new Vuetify(opts) main.ts を編集 import Vue from 'vue' import vuetify from '@/plugins/vuetify' new Vue({ vuetify, }).$mount('#app') vue.config.js を編集 chainWebpack: config => { config.plugin('VuetifyLoaderPlugin').tap(args => [{ match (originalTag, { kebabTag, camelTag, path, component }) { if (kebabTag.startsWith('core-')) { return [camelTag, `import ${camelTag} from '@/components/core/${camelTag.substring(4)}.vue'`] } } }]) } 使いたいVuetifyコンポーネントを呼び出す <template> <v-card> ... </v-card> </template> <script> import { VCard } from 'vuetify/lib' export default { components: { VCard }, ... } </script> ビルド速度を削減(任意) アラカルトによりビルドが重くなるようなので、気になる方は対処するといいかも Vuetify2を使ったプロジェクトのビルドが遅いので高速化する - Qiita 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

...mapState でストア呼び出し

mapstateとは 一言でいうと、ストアのデータ呼び出しの記述を短くするためのもの、です。 this.$store.state.プロパティ名 でストアのデータを呼び出せますが、長くなってしまうので computed にまとめて呼び出すことが可能です。 mapStore自体がオブジェクトを返すのでこのようにします。 <script> import { mapState } from "vuex"; // vuexからmapStateをimport export default { computed: mapState(["lists"]), }; </script> 本来はコンポーネント内で this.$store.state.lists と記述しますが、 mapState を使うことで、 state に this.$store.state が代入され、簡潔に呼び出しができます computed と mapstate を共存させるには 最初に紹介した方法では、computedが定義できませんが、こんな記述方法もあります。 computed: { ...mapState(["lists"]), otherFunction() { // 略 }, }, ... ←の意味 これ( ... ) はスプレッド構文という名前で、オブジェクトを個々の値に展開することができるものです。 スプレッド構文を使わず下記の様にしてしまうと・・ computed: { mapState(['lists']), } mapstateがオブジェクトを返すので、このように {} が重なった状態になってしまいます。 computed: { { lists () { return this.$store.state.lists }, } } 以上、Vuexで最初よくわからなかった ...mapstate の意味についての備忘録でした。 参考文献 Vue公式 Vuex state
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メニューをクリックするごとにメイン部の表示を切り替えるやつをVue.jsで書いてみた

よくある、アプリケーション画面でトップとかサイドにメニューがあって、それをクリックするとメイン部分に表示をする(切り替える)仕組みについて。 jQueryを使った場合、対象の要素に対して背景色のクラスを"付けたり" or "外したり"とか、.show() or .hide()で表示を切り替えたりする。と思いつくのだけれど、Vue.jsでやる場合は「状態を変える」ことによって「表示を切り替える」ことらしいので、こういう感じでやるのかなーと書いてみた。 demo methodsの select()でクリックしたメニューのIDを保持 メニューの背景色を選択色に変えたり、表示の切り替えを methodsのisSelected({ID})で判定している。 次は、メニュー部とコンテンツ部をファイルに分けて(コンポーネントごとに切り出して)、メニュー部で選択した状態をコンテンツ部にどうやって伝えるかを実装してみる。 <script src="https://unpkg.com/vue"></script> <div id="app"> <div id="menu"> <ul> <li id="A01" v-on:click="select" v-bind:class="{selected: isSelected('A01')}">AAAAA</li> <li id="B01" v-on:click="select" v-bind:class="{selected: isSelected('B01')}">BBBBB</li> </ul> </div> <div id="contents"> <div class="item" id="AAAAA" v-show="isSelected('A01')"><p>{{ selected }}</p> </div> <div class="item" id="BBBBB" v-show="isSelected('B01')"><p>{{ selected }}</p> </div> </div> </div> <script> var vm = new Vue({ el: "#app", data : { selected: "" }, methods: { select: function (event) { this.selected = event.target.id }, isSelected: function(id){ return this.selected === id } } }) </script> #menu { width: 400px; } ul { list-style-type: none; overflow: hidden; } li { height: 40px; width: 100px; background-color: gray; color: white; text-align: center; line-height: 40px; margin-right: 2px; float: left; } .selected { background-color: cyan; color: black; } #contents { width: 600px; } .item { width: 100%; height: 200px; } #AAAAA { background-color: lightsalmon; } #BBBBB { background-color: lightblue; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelの@jsonディレクティブには変数以外を入れてはいけない

概要 〜ある日の午後の出来事〜 web.php Route::get('hoge/{id}', 'HogeController@index')->name('hoge'); Route::get('fuga/{id}', 'FugaController@index')->name('fuga'); Laravel × Vue.jsでの開発中、このようなルートを設定して <div id="app"> <hogehuga :routes='@json([ "hoge" => route("hoge", 1), "fuga" => route("fuga" ,1), ])' > </hogefuga> </div> BladeテンプレートからVue.jsにルートを渡してみたところ 構文エラー え???と思い、実際のコードを見てみると・・・ なぜか、fugaの方のルートがパラメータ渡せていない & 配列やjson_encodeの閉じかっこが無い。。。 解決策 色々試してみても全く解決しそうになく、類似の事象もみつからない。このまま迷宮入りかと思いきや、ReadDoubleにこんな記述がありました。 Note: @jsonディレクティブは既存の変数をJSONとしてレンダするためだけに使用してください。Bladeテンプレートは正規表現ベースのため、複雑な式をディレクティブに渡すと予期しない不良動作の原因になります。 なるほどー。 今回のように@jsonディレクティブにroute関数などを使った複雑な式を直接入れると思わぬバグをうむ可能性があるみたい。 ということで、以下のようにして解決。 @php $routes = [ "hoge" => route("hoge", 1), "fuga" => route("fuga" ,1), ]; @endphp <div id="app"> <hogehuga :routes='@json($routes)' > </hogefuga> </div> @jsonディレクティブには変数以外を入れないように気をつけましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ハンズオン/初心者向け】Nuxt.jsでStorybookを使ってみよう!

はじめに Storybookは、UI開発用のツールです。 開発環境と分離された環境で UI コンポーネントを個別に作成し、コンポーネントの再利用やテストを容易にします。 複雑な開発スタックを起動したり、特定のデータをデータベースに強制したり、アプリケーション内を移動したりすることなく、UI全体を開発できます。 Storybookのメリットは以下の記事をご確認ください。 ググったら1番上にありました。 環境 ・ "@storybook/addon-actions": "^6.2.9" ・ "@storybook/addon-essentials": "^6.2.9" ・ "@storybook/addon-links": "^6.2.9" ・ "@storybook/vue": "^6.2.9" 公式サイトはこちら 学べること ・Storybookの使い方 ・Font Awesomeの導入方法 ・Propsを使って、子→親にmethodsを渡す方法 インストール ターミナル ####### STEP1 ####### $ npx create-nuxt-app nuxt-storybook ####### STEP2 ####### ## vue2(Nuxt.jsはこちらを使いましょう) $ npx sb init ## vue3 $ npx sb@next init ####### STEP3 ####### $ npm run storybook これで、Storybookをローカルで起動できるようになります。 ディレクトリ構成 以下のようなフォルダやファイルが作成されます。 ├── .storybook │ ├── main.js │ ├── preview.js │ ├── stories │ └── assets │ │ ├── code-brackets.svg │ │ └── (省略) │ ├── button.css │ ├── Button.vue │ ├── Button.stories.js │ ├── header.css │ ├── Header.vue │ ├── Header.stories.js │ ├── page.css │ ├── Page.vue │ ├── Page.stories.js │ ├── Introduction.stories.mdx storiesにコンポーネントがあってもむd コンポーネントは、storiesじゃなくてcomponentsに入れたいよね。 ということで、ファイルをすべて移動させましょう! ついでにいらないLogo.vueも削除しときましょう。 ということで上記を実行すれば、このようなディレクトリ構造になります。 ├── .storybook │ ├── main.js │ ├── preview.js │ ├── components │ └── assets │ │ ├── code-brackets.svg │ │ └── (省略) │ ├── button.css │ ├── Button.vue │ ├── Button.stories.js │ ├── header.css │ ├── Header.vue │ ├── Header.stories.js │ ├── page.css │ ├── Page.vue │ ├── Page.stories.js │ ├── Introduction.stories.mdx │ ├── README.md ただこのままだと使えません。 なので、.storybook/main.jsを修正しましょう。 .storybook/main.js module.exports = { "stories": [ "../components/**/*.stories.mdx", "../components/**/*.stories.@(js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials" ] } これで完了です! それでは再度Storybookを起動しましょう。 ターミナル npm run storybook ちなみにこのままだとcssとvueが分割されています。 これもまとめた方がスマートだよねってことでまとめていきましょう! ついでに、assetsもIntroductionもいらない気がするので削除しましょう。 ということで、ディレクトリ構造はこのようになりました。 ├── .storybook │ ├── main.js │ ├── preview.js │ ├── components │ ├── Button.vue │ ├── Button.stories.js │ ├── Header.vue │ ├── Header.stories.js │ ├── Page.vue │ ├── Page.stories.js │ ├── README.md ものすごくスッキリしましたね! 実際にコンポーネントを作ってみよう! まずは、SCSSをインストールしましょう ターミナル npm install sass-loader node-sass --save-dev ## npm run devでバージョンで怒られたとき ## こんな感じで怒られました>< ## WARN sass-loader@11.0.1 is installed but ^10.1.1 is expected npm uninstall sass-loader --save-dev npm install sass-loader@10.1.1 --save-dev 次に、webpackのconfigを作成します。 これで、SCSSが使えるようになりました。 .storybook/webpack.config.js const path = require("path"); module.exports = ({ config }) => { config.module.rules.push({ test: /\.s(a|c)ss$/, use: ["style-loader", "css-loader", "sass-loader"], }); return config; }; 参考記事 見出しデザインを作ってみよう 作成するものはこの2つです。 どちらも良くあるデザインですね。 それでは作っていきましょう! Viewを作成 components/Atoms/HeadingH2.vue <template> <div> <h2 :class="className">{{ title }}</h2> </div> </template> <script> export default { name: 'Heading2', props: { title: { type: String, required: true, }, className: { type: String, required: true } }, }; </script> <style lang="scss" scoped> .el-lv2Heading { padding: 1.5rem; /*文字の上下 左右の余白*/ font-size: 1.75rem; color: #111111; /*文字色*/ background: #f4f4f4; /*背景色*/ border-left: solid 5px #0074d9; /*左線*/ border-bottom: solid 3px #d7d7d7; /*下線*/ font-weight: bold; } .el-lv2Heading-2 { position: relative; font-size: 1.75rem; padding: 1rem; text-align: center; font-weight: bold; &::before { position: absolute; bottom: -5px; left: calc(50% - 30px); width: 60px; height: 5px; content: ''; border-radius: 3px; background: #0074d9; } } </style> storiesファイル作成 components/Atoms/HeadingH2.stories.js // Viewをインポート import HeadingH2 from "./HeadingH2.vue"; // Storybookで表示される内容 export default { title: "Components/Atoms/HeadingH2", //ディレクトリ component: "HeadingH2" //コンポーネント名 }; const Template = (args, { argTypes }) => ({ components: { HeadingH2 }, //上記のコンポーネントと揃える props: Object.keys(argTypes), // templateで、下記の場合titleとclassNameに任意の値が入る template: "<HeadingH2 :title='title' :className='className' />" }) // 1つ目のデザイン export const Primary = Template.bind({}); Primary.args = { title: "見出し2です", className: "el-lv2Heading" }; Primary.storyName = "見出し2デザイン①"; // 2つ目のデザイン export const Secondary = Template.bind({}); Secondary.args = { title: "見出し2です", className: "el-lv2Heading-2"}; Secondary.storyName = "見出し2デザイン②"; それでは次にボタンを作ってみましょう! まずボタンには2種類あります。 ・リンクとして使うボタン ・@clickなど動作を行うために使うボタン リンクの場合、<nuxt-link>を使う方が望ましく、 @clickの場合、<button>を使いたいです。 ということで同じボタンですが、分けてこの2つは作ります。 またデザインは3パターンです。 Controlsを使えば色の変更やボタンサイズ、ボタンタイプを変更できます。 Font Awesomeを追加 npmでインストール ターミナル // 必須(Solid Style) npm install @fortawesome/vue-fontawesome @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons --save // 任意(Regular Style, Brands Style) npm install @fortawesome/free-regular-svg-icons --save npm install @fortawesome/free-brands-svg-icons --save プラグインを作成 plugins/fontawesome.js import Vue from 'vue'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import { config, library } from '@fortawesome/fontawesome-svg-core'; // solid Style import { faArrowRight } from '@fortawesome/free-solid-svg-icons'; // regular Style import {} from '@fortawesome/free-regular-svg-icons'; // brands Style import {} from '@fortawesome/free-brands-svg-icons'; // nuxt.config.jsでCSSファイルを追加 config.autoAddCss = false; // 利用するアイコンを配列に追加 const solidIcons = [faArrowRight]; const regularIcons = []; const brandsIcons = []; // 利用するアイコンをlibraryに追加 solidIcons.forEach((icon) => library.add(icon)); regularIcons.forEach((icon) => library.add(icon)); brandsIcons.forEach((icon) => library.add(icon)); // グローバルコンポーネントに登録 Vue.component('fa', FontAwesomeIcon); nuxt.config.jsに追記 nuxt.config.js export default { css: ['@fortawesome/fontawesome-svg-core/styles.css'], plugins: [ '@/plugins/fontawesome', ], }; Storybookに読み込む .storybook/preview.js import { configure } from '@storybook/vue'; import Vue from 'vue'; import { library } from '@fortawesome/fontawesome-svg-core'; import { fas } from '@fortawesome/free-solid-svg-icons'; import { fab } from '@fortawesome/free-brands-svg-icons'; import { far } from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; library.add(fas, far, fab); Vue.component('fa', FontAwesomeIcon); configure(require.context('../components', true, /\.stories\.js$/), module); export const parameters = { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }; Componentsで使用する components/Atoms/LinkButton.vue <template> <div> <span v-if="isIcon"> <fa :class="{ icon: isIcon }" :icon="[iconType, iconName]" /> </span> </div> </template> <script> export default { name: 'RoundButton', props: { isIcon: { type: Boolean, default: false, validator: function (value) { return [true, false].indexOf(value) !== -1; }, }, iconType: { type: String, required: false, validator: function (value) { return ['fas', 'fab', 'far'].indexOf(value) !== -1; }, }, iconName: { type: String, required: false, }, }, computed: { classes() { return { 'icon-btn': this.isIcon, }; }, }, }; </script> これで、Font Awesomeが使えるようになりました。 Viewを作成 components/Atoms/LinkButton.vue <template> <div> <nuxt-link :to="link" :class="classes"> {{ btnName }} <span v-if="isIcon"> <fa :class="{ icon: isIcon }" :icon="[iconType, iconName]" /> </span> </nuxt-link> </div> </template> <script> export default { name: 'RoundButton', props: { btnName: { type: String, required: true, }, link: { type: String, default: '/', }, btnColor: { type: String, default: 'blue', validator: function (value) { return ( [ 'navy', 'blue', 'olive', 'green', 'orange', 'red', 'maroon', 'fuchsia', 'purple', 'black', 'gray', ].indexOf(value) !== -1 ); }, }, btnType: { type: String, default: 'normal', validator: function (value) { return ['normal', 'rounded-corners', 'round'].indexOf(value) !== -1; }, }, btnSize: { type: String, default: 'medium', validator: function (value) { return ['small', 'medium', 'large', 'xlarge'].indexOf(value) !== -1; }, }, isIcon: { type: Boolean, default: false, validator: function (value) { return [true, false].indexOf(value) !== -1; }, }, iconType: { type: String, required: false, validator: function (value) { return ['fas', 'fab', 'far'].indexOf(value) !== -1; }, }, iconName: { type: String, required: false, }, }, computed: { classes() { return { 'el-btn': true, [`${this.btnColor}`]: true, [`el-btn-type-${this.btnType}`]: true, [`el-btn-size-${this.btnSize}`]: true, 'icon-btn': this.isIcon, }; }, }, }; </script> <style lang="scss" scoped> // 共通レイアウト .el-btn { display: inline-block; text-align: center; color: #fff; text-decoration: none; transition: 0.25s; cursor: pointer; } // ボタンタイプ .el-btn-type-normal { box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16); } .el-btn-type-rounded-corners { border-radius: 10px; } .el-btn-type-round { border-radius: 50px; } // ボタンサイズ .el-btn-size-small { font-size: 14px; padding: 10px 24px; } .el-btn-size-medium { font-size: 16px; padding: 12px 28px; } .el-btn-size-large { font-size: 18px; padding: 14px 32px; } .el-btn-size-xlarge { font-size: 20px; padding: 16px 36px; width: 250px; max-width: 100%; } //アイコン .icon-btn { position: relative; padding-right: 2em; padding-left: 1.38em; } .icon { position: absolute; top: 50%; transform: translateY(-50%); right: 0.83em; font-weight: 900; } //ボタンの色 .navy { background-color: #001f3f; border: 2px solid transparent; border-bottom-color: #000e1d; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #001f3f; } } .blue { background-color: #0074d9; border: 2px solid transparent; border-bottom-color: #0062b7; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #0074d9; } } .olive { background-color: #3d9970; border: 2px solid transparent; border-bottom-color: #33815e; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #3d9970; } } .green { background-color: #2ecc40; border: 2px solid transparent; border-bottom-color: #28b037; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #2ecc40; } } .orange { background-color: #ff851b; border: 2px solid transparent; border-bottom-color: #f87300; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #ff851b; } } .red { background-color: #ff4136; border: 2px solid transparent; border-bottom-color: #ff2114; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #ff4136; } } .maroon { background-color: #85144b; border: 2px solid transparent; border-bottom-color: #67103a; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #85144b; } } .fuchsia { background-color: #f012be; border: 2px solid transparent; border-bottom-color: #d30da6; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #f012be; } } .purple { background-color: #b10dc9; border: 2px solid transparent; border-bottom-color: #950ba9; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #b10dc9; } } .black { background-color: #111111; border: 2px solid transparent; border-bottom-color: #000; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #111111; } } .gray { background-color: #aaaaaa; border: 2px solid transparent; border-bottom-color: #999999; &:focus, &:hover { background-color: #fff; border-color: currentColor; color: #aaaaaa; } } </style> storiesファイル作成 components/Atoms/LinkButton.stories.js import LinkButton from './LinkButton.vue'; export default { title: 'Components/Atoms/LinkButton', component: 'LinkButton', argTypes: { btnColor: { control: { type: 'select', options: [ 'navy', 'blue', 'olive', 'green', 'orange', 'red', 'maroon', 'fuchsia', 'purple', 'black', 'gray', ], }, }, btnType: { control: { type: 'select', options: ['normal', 'rounded-corners', 'round'] } }, btnSize: { control: { type: 'select', options: ['small', 'medium', 'large', 'xlarge'] } }, isIcon: { control: { type: 'select', options: [true, false] } }, iconType: { control: { type: 'select', options: ['fas', 'far', 'fab'] } }, }, }; const Template = (args, { argTypes }) => ({ components: { LinkButton }, props: Object.keys(argTypes), template: "<LinkButton :btnName='btnName' :to='to' v-bind='$props' />", }); export const Primary = Template.bind({}); Primary.args = { btnName: 'ボタン①', link: '/', btnColor: 'olive', btnType: 'normal', btnSize: 'xlarge', isIcon: true, iconType: 'fas', iconName: 'arrow-right', }; Primary.storyName = 'ノーマルボタン'; export const Secondary = Template.bind({}); Secondary.args = { btnName: 'ボタン②', link: '/', btnColor: 'blue', btnType: 'rounded-corners', btnSize: 'large', }; Secondary.storyName = '角丸ボタン'; export const Tertiary = Template.bind({}); Tertiary.args = { btnName: 'ボタン③', link: '/', btnColor: 'orange', btnType: 'round', btnSize: 'medium', }; Tertiary.storyName = '丸ボタン'; // export const Quaternary = Template.bind({}); // export const Quinary = Template.bind({}); // export const Senary = Template.bind({}); // export const Septenary = Template.bind({}); // export const Octonary = Template.bind({}); // export const Novenary = Template.bind({}); // export const Decenary = Template.bind({}); これで完成です! methodsボタンを作成 次にmethodsなどで使うボタンを作成していきましょう。 デザインは先ほど使ったものをそのまま転用していきます。 Viewを作成 components/Atoms/MethodsButton.vue <template> <div> <button :class="classes" @click="onClick()"> {{ btnName }} <span v-if="isIcon"> <fa :class="{ icon: isIcon }" :icon="[iconType, iconName]" /> </span> </button> </div> </template> <script> export default { name: 'MethodsButton', props: { btnName: { type: String, required: true, }, btnColor: { type: String, default: 'blue', validator: function (value) { return ( [ 'navy', 'blue', 'olive', 'green', 'orange', 'red', 'maroon', 'fuchsia', 'purple', 'black', 'gray', ].indexOf(value) !== -1 ); }, }, btnType: { type: String, default: 'normal', validator: function (value) { return ['normal', 'rounded-corners', 'round'].indexOf(value) !== -1; }, }, btnSize: { type: String, default: 'medium', validator: function (value) { return ['small', 'medium', 'large', 'xlarge'].indexOf(value) !== -1; }, }, isIcon: { type: Boolean, default: false, validator: function (value) { return [true, false].indexOf(value) !== -1; }, }, iconType: { type: String, required: false, validator: function (value) { return ['fas', 'fab', 'far'].indexOf(value) !== -1; }, }, iconName: { type: String, required: false, }, onClick: { type: Function, required: true, }, }, computed: { classes() { return { 'el-btn': true, [`${this.btnColor}`]: true, [`el-btn-type-${this.btnType}`]: true, [`el-btn-size-${this.btnSize}`]: true, 'icon-btn': this.isIcon, }; }, }, }; </script> storiesファイル作成 components/Atoms/MethodsButton.stories.js import MethodsButton from './MethodsButton.vue'; export default { title: 'Components/Atoms/MethodsButton', component: 'MethodsButton', argTypes: { btnColor: { control: { type: 'select', options: [ 'navy', 'blue', 'olive', 'green', 'orange', 'red', 'maroon', 'fuchsia', 'purple', 'black', 'gray', ], }, }, btnType: { control: { type: 'select', options: ['normal', 'rounded-corners', 'round'] } }, btnSize: { control: { type: 'select', options: ['small', 'medium', 'large', 'xlarge'] } }, isIcon: { control: { type: 'select', options: [true, false] } }, iconType: { control: { type: 'select', options: ['fas', 'far', 'fab'] } }, }, }; const Template = (args, { argTypes }) => ({ components: { MethodsButton }, props: Object.keys(argTypes), template: "<MethodsButton :btnName='btnName' v-bind='$props' />", }); export const Primary = Template.bind({}); Primary.args = { btnName: 'ボタン①', btnColor: 'olive', btnType: 'normal', btnSize: 'xlarge', isIcon: true, iconType: 'fas', iconName: 'arrow-right', onClick: '', }; Primary.storyName = 'ノーマルボタン'; export const Secondary = Template.bind({}); Secondary.args = { btnName: 'ボタン②', btnColor: 'blue', btnType: 'rounded-corners', btnSize: 'large', onClick: '', }; Secondary.storyName = '角丸ボタン'; export const Tertiary = Template.bind({}); Tertiary.args = { btnName: 'ボタン③', btnColor: 'orange', btnType: 'round', btnSize: 'medium', onClick: '', }; Tertiary.storyName = '丸ボタン'; // export const Quaternary = Template.bind({}); // export const Quinary = Template.bind({}); // export const Senary = Template.bind({}); // export const Septenary = Template.bind({}); // export const Octonary = Template.bind({}); // export const Novenary = Template.bind({}); // export const Decenary = Template.bind({}); 親コンポーネントでの使い方 pages/index.vue <template> <div class="container"> <input type="text" v-model="test" /> <!-- propsの呼び出し方法は、キャメルケースではなくケバブケース --> <!-- このようにonClickをon-clickに直さないと動作しない --> <MethodsButton btnName="送信" btnColor="blue" btnType="round" btnSize="small" :on-click="testMessage" /> </div> </template> <script> import MethodsButton from '@/components/Atoms/MethodsButton'; export default { components: { MethodsButton, }, data() { return { test: '', }; }, methods: { testMessage() { console.log(this.test); }, }, }; </script> 最後に githubにあげました。 また、Vue3やTypeScriptを使ってモダンに仕上げていく予定です。 そちらもいずれ記事にします! ここまで読んでいただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js で開発環境だけで呼ばれると思ってた重い処理が常に呼ばれてた件

下のコードを読み込むと alert('重い処理') は呼ばれるだろうか? <html> <head> <script src="https://unpkg.com/vue"></script> </head> <body> <div id="app"> <development-only> {{heavy_code()}} </development-only> </div> <script> new Vue({ el: "#app", components: { "development-only": { template: '<div v-if="false"><slot></slot></div>', }, }, methods: { heavy_code() { alert('重い処理') }, }, }) </script> </body> </html> 答え: 呼ばれる development-only コンポーネントは開発環境だけで表示するつもりで、今は本番環境なので、コンポーネント側のルートで v-if="false" となっている。だから slot はそもそも呼ばれないはずだ。と思っていたけどなんか重いので恐る恐る試したら呼ばれたのである。slot よりも先に呼び出し側で作ってから渡しているということだろうか。 ちなみに <development-only v-if="false"> とすれば呼ばれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js で開発環境だけで呼ばれてると思ってた重い処理が常に呼ばれてた件

下のコードを読み込むと alert('重い処理') は呼ばれるだろうか? <html> <head> <script src="https://unpkg.com/vue"></script> </head> <body> <div id="app"> <development-only> {{heavy_code()}} </development-only> </div> <script> new Vue({ el: "#app", components: { "development-only": { template: '<div v-if="false"><slot></slot></div>', }, }, methods: { heavy_code() { alert('重い処理') }, }, }) </script> </body> </html> 答え: 呼ばれる development-only コンポーネントは開発環境だけで表示するつもりで、今は本番環境なので、コンポーネント側の親タグで v-if="false" となっている。だから slot はそもそも呼ばれないはずだ。と思っていたけどなんか重いので恐る恐る試したら呼ばれたのである。slot よりも先に呼び出し側で作ってから渡しているということだろうか。 ちなみに <development-only v-if="false"> とすれば呼ばれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む