質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

6332閲覧

Vue.jsでモーダルを閉じる動きの実装($.emit)

c_nnnnnn

総合スコア12

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/12/03 02:15

1. emitが効かない
vue-masonryを使用して画像を並べ、そこにモーダル部分をVue.jsのコンポーネントで作成し、クリック時にモーダルが開く機能の実装を目指しています。
開く部分やモーダル内表示は実装できたのですが、モーダル内の「close」ボタンでモーダルを閉じても効きません。当該部分はemitを用いています。

html

1 <div v-masonry-tile class="item" v-for="(item,index) in filteredItems" v-bind:key="item.id" v-on:click="openModal(index)"> 2 <div v-on:mouseleave="!isMobile ? hideOverlay() : null" v-on:mouseover="!isMobile ? showOverlay(index) : null" > 3 <img :src="item.src" :alt="item.altTxt"/> 4 <p class="photo__overlay" v-show="hoverFlag && index === hoverIndex "</p> 5 </div> 6 <modal v-show="modalFlg && index === modalIndex" v-on:close="closeModal" v-bind:modal-id="index" v-bind:modal-data="modalItems"/> 7 </div> 8 </div>

JavaScript

1let app = new Vue({ 2 el: '#app', 3 data: { 4 isMobile : false, 5 hoverFlag: false, 6 hoverIndex: null, 7 modalFlg:false, 8 modalIndex: null, 9 modalItems: [] 10 }, 11 components:{ 12 'modal':{ 13 template : ` 14 <div class="gallery__overlay"> 15 <div class="gallery__modal modal"> 16 <p>これがモーダルウィンドウです。</p> 17 <p v-for="(item,index) in ModalData" v-bind:key="item.id" v-if="currentSlide == index"> 18 <img :src="item.src" :alt="item.altTxt"/> 19 </p> 20 <p @click="$emit('close')"><button>close</button></p> 21 </div> 22 </div> 23 `, 24 props:{ 25 ModalData: Array, 26 ModalId: Number 27 }, 28 data:function(){ 29 return{ 30 currentSlide : this.ModalId 31 } 32 } 33 } 34 }, 35 created: function() { 36 const json_url = "/json/photogallery.json"; 37 //JSONを取得してitemsに格納 38 axios.get(json_url) 39 //成功した場合 40 .then(response => {this.items = response.data;}); 41 }, 42 computed: { 43 filteredItems: function() { 44 //略 45 this.modalItems = this.items; 46 return this.items; 47 } 48 }, 49 methods: 50 closeModal: function(){ 51 this.modalFlg = false; 52 this.modalIndex = null; 53 } 54 } 55});

closeModal関数部分にmodalFlg、modalIndexをconsole.logで出力すると、closeクリック時に問題なく出力されているので、emitによるイベントの受け渡しは成功していると思うのですが、実際のモーダルは閉じません。どういった原因が考えられるでしょうか。

2. 番号リスト
モーダルの一番外側のdivにcloseボタンと同様のイベントを、内部の白い領域にstopPropagationを使用した伝播を防ぐイベントを設定すると、closeボタンのみ効き、モーダルが閉じるようになります。

JavaScript

1components:{ 2 'modal':{//一番目のdiv,二番目のdivに@clickを追加 3 template : ` 4 <div class="gallery__overlay" @click="$emit('close')"> 5 <div class="gallery__modal modal" @click="stopEvent"> 6 ~~ 7 <p @click="$emit('close')"><button>close</button></p> 8 </div> 9 </div> 10 `, 11 methods :{//イベントの伝播を止める 12 stopEvent: function(){ 13 event.stopPropagation() 14 },・・・

このことで望みの動作は実装できているのですが、挙動の理由が分かりません。そのような組み方をした場合、closeボタンと半透明のオーバーレイ部分にてcloseModal関数が発火できるようになると思われるのですが、オーバーレイ部分は反応しません。また、一番外側のdivからイベント設定を外すと、closeボタンのクリックイベントも効かなくなります。どのような原因が考えられるでしょうか。

よろしくお願いいたします。

イメージ説明
※リンク切れは仕様です

参考ページは以下です。
https://reffect.co.jp/vue/understand-component-by-moda-window
http://frontendmemo.work/2019-08-13-183000/

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

FKM

2021/12/03 09:24

divの方だけ$.emit('close')を残すとどうなりますか?
c_nnnnnn

2021/12/03 10:09

div.gallery__overlayにだけ$.emit('close')を残すと、クリックに反応しなくなります。
guest

回答2

0

自己解決

コンポーネントを親子に分割しなくともそこまで複雑ではない仕様のため、直書きに変更して正常に動作するようになりました。
もう少しコンポーネントの親子関係について習熟後、挑戦したいと思います。ご回答ありがとうございます。

投稿2022/03/04 02:51

c_nnnnnn

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

親コンポーネントと子コンポーネントの関係を、一度整理した方がいいと思います。

現状だと親コンポーネントにクリックイベントを渡しているのに、モーダルの開閉処理を行っているのは子コンポーネントの中にあるようです。

v-on:clickの中身にある$emit('close')は開閉処理を行うものではなく、this.$emitは子コンポーネントから親コンポーネントにイベントをコールバック関数化して受け渡すものです。なので、クリックによって親コンポーネントにイベントを飛ばしているのに、飛ばした先の親コンポーネントに開閉処理はないので、何も起きません。

投稿2021/12/03 09:34

編集2021/12/03 09:38
FKM

総合スコア3647

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

c_nnnnnn

2021/12/03 10:37 編集

コメントありがとうございます。いま一度整理します。 まず子コンポーネントに$.emit('close')を設定し、イベントを親コンポーネントに渡しています。 親コンポーネントのHTML要素にはデータバインディングを用いて、v-on:close="closeModal"と記述し、子から渡ってきた関数にcloseModalメソッドをバインドしています。 親コンポーネント(インスタンス)には、closeModalがmethodsに設定してあり、インスタンスのプロパティを更新することでモーダル要素が閉じる仕組みとなっています(上から2つ目のコード:JavaScript下部参照)。そのため、「飛ばした先の親コンポーネントに開閉処理はない」ということはない認識なのですが、いかがでしょう。記述場所が誤っているなどでしょうか。 「現状だと親コンポーネントにクリックイベントを渡しているのに、モーダルの開閉処理を行っているのは子コンポーネントの中にあるようです。」とのことですが、そのような挙動を実現するために(子コンポーネントの動作を親コンポーネントに伝えてイベントを発火するために)、$.emitを使う必要があるという認識です。認識に誤りがありそうでしょうか。
FKM

2021/12/05 04:26

開閉条件をv-show="modalFlg"だけにした場合どうなりますか?
c_nnnnnn

2021/12/06 02:08

開閉条件をv-show="modalFlg"だけにして、divの外側のイベント・内部白い領域のstopPropagationイベントを削除し、closeボタンのみにイベントを付加した場合も、モーダルは閉じません。 開閉条件をv-show="modalFlg"だけにして、divの外側のイベント・内部白い領域のstopPropagationイベントはそのままにするとモーダルの開閉自体はできますが、<modal>はvue-masonryで並んだ各サムネイルの子要素としてそれぞれ配置しているため、index === modalIndexを削除すると他の全てのモーダルが背後に開いてしまう動作となります。v-for内に<modal>を配置しないとindexをうまく渡せなかったためこのような配置になっています。(モーダル要素をいくつも作らないですむよう、モーダルの開くタイミングでindexを取得してインスタンスプロパティにセットして、それを<modal>のv-bindに…とやろうとしましたがうまく値が渡りませんでした)
FKM

2021/12/07 00:04 編集

自分もテストしてみたんですが、Appに直書きだと動かない可能性があります。Appから親コンポーネントを作成し、その中にVue.createでテンプレートを作成するとモーダルは機能しました。リンク先にあるような最低限のモーダルが機能してるのを確認してから追加実装された方がいいと思いますが、最低限のモーダルが機能していることは確認済みでしょうか。
c_nnnnnn

2021/12/07 03:22

テスト検証ありがとうございます。最低限のモーダル自体は機能しています。vue.createでのテンプレート作成と直書きでは挙動が異なる可能性があるのですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問