🐈

【音声ファイルアップロード機能】モーダル(コンポーネント)間のデータ受け渡し

2021/07/11に公開

headerから両方のモーダルを呼び出す仕様にしているため、BeforeMusicUploadModalからAfterMusicUploadModal.vueへ直接は渡せない
BeforeMusicUploadModal(子)からheader(親)にemitで値を渡して、header(親)からAfterMusicUploadModal(子)のpropsに渡す

nuxtでモーダル作成

BeforeMusicUploadModal.vue

<template>
  <div id="overlay" v-show="showContent" @click.self="closeBeforeMusicUploadModal">
    <div id="main-content">
      <h2 class="title">音声ファイルのアップロード</h2>
      <div class="drop_area" 
        @dragenter="dragEnter" 
        @dragleave="dragLeave" 
        @dragover.prevent 
        @drop.prevent="dropFile" 
        :class="{enter: isEnter}" 
      >
        <p>クリックしてファイルを追加</p>
        <p>最大100MB、形式: MP3, AAC</p>
        {{files.file}}
      </div>
      <!-- <div class="drop_area" v-if="isEnter">
        <p>ファイルを保持しています。</p>
        {{ files.name }}
      </div> -->
      <div class="button-content">
        <button class="cancel-btn" @click="closeBeforeMusicUploadModal">キャンセル</button>
        <button class="disabled-btn" disabled>アップロード</button>
      </div>
          <!-- <div>
              <ul>
                  <li v-for="(file, index) in files" :key="index">{{ file.name }}
                  </li>
              </ul>
          </div> -->
    </div>
  </div>
</template>

<script>
/* eslint-disable */

export default {
  // ここからheader.vueにクリックイベント(openAfterMusicUploadModal)を渡す
  transition: {
    name: 'modal',
    mode: 'out-in'
  },
  components: {
  },
  data () {
    return {
      showContent: false,
      showContent2: false,
      MusicFile: '',
      isEnter: false,
      files: [],
      greet: 'Hello Vue.js!'
    }
  },
  methods: {
    openBeforeMusicUploadModal (){
      this.$emit('openBeforeMusicUploadModal', this.showContent);
    },
    closeBeforeMusicUploadModal (){
      this.$emit('closeBeforeMusicUploadModal', this.showContent);
    },
    closeAfterMusicUploadModal () {
      this.showContent2 = false
    },
    // onMusicFileUploaded(e) {
    //   // event(=e)からMusicFileデータを取得する
    //   const musicFile = e.target.files[0]
    //   this.createMusicFile(musicFile)
    // },
    // createMusicFile(MusicFile) {
    //   const reader = new FileReader()
    //   // MusicFileをreaderにDataURLとしてattachする
    //   reader.readAsDataURL(MusicFile)
    //   // readAdDataURLが完了したあと実行される処理
    //   reader.onload = () => {
    //     this.submittedArticle.MusicFile = reader.result
    //   }
    // },
    dragEnter() {
        // console.log('Enter Drop Area');
        this.isEnter = true;
    },
    dragLeave() {
        this.isEnter = false;
    },
    dragOver() {
        console.log('DragOver')
    },
    dropFile() {
        this.files = [...event.dataTransfer.files]
        console.log(this.files[0].name)
        // this.files.forEach(file => {
        //     let form = new FormData()
        //     form.append('file', file)
        //     this.$axios.post('http://localhost:8000//api/musicFileUpload', form).then(response => {
        //         console.log(response.data)
        //     }).catch(error => {
        //         console.log(error)
        //     })
        // })
        // this.$emit('closeBeforeMusicUploadModal', this.showContent);
        console.log(this.showContent)
        this.$emit('openAfterMusicUploadModal', this.showContent2);
        console.log(this.showContent2)
        this.isEnter = false;
    }
  },
}
</script>

AfterMusicUploadModal.vue

<template>
  <div id="overlay" v-show="showContent2" @click.self="closeAfterMusicUploadModal">
    <div id="main-content">
      <h2 class="title">音声ファイルのアップロード</h2>
      <div class="sections">
        <div>
          <h3>カバー画像</h3>
          <div class="description">
            <p>クリックして画像を追加</p>
            <p>10MB以内 .jpg .png .heic に対応しています。</p>
          </div>
        </div>
        <h3>タイトル</h3>
  <div>
    <p>{{ greet }}</p>
  </div>
          <input type="text" class="text-box">
        <h3>ジャンル選択</h3>
          <div class="cp_ipselect cp_sl01">
          <select required>
            <option value="" hidden class="aa">ジャンルを選択してください</option>
            <option value="1">J-POP</option>
            <option value="1">アニメ</option>
            <option value="1">邦楽ヒップホップ/R&B/レゲエ</option>
            <option value="1">邦楽ロック</option>
            <option value="1">邦楽ダンス/エレクトロニカ</option>
            <option value="1">K-POP/ワールド・ミュージック</option>
            <option value="1">洋楽総合</option>
            <option value="1">洋楽ポップス</option>
            <option value="1">洋楽ヒップホップ/R&B/レゲエ</option>
            <option value="1">洋楽ロック</option>
            <option value="1">洋楽ダンス/エレクトロニカ</option>
            <option value="1">歌謡曲/演歌</option>
            <option value="1">ジャズ</option>
            <option value="1">クラシック</option>
          </select>
          </div>
        <h3>感情アイコン選択</h3>
          <ul class="emotion">
            <li class="joy"></li>
            <li class="angry"></li>
            <li class="sorrow"></li>
            <li class="easy"></li>
          </ul>
      </div>
      <div class="button-content">
        <button class="cancel-btn" @click="closeAfterMusicUploadModal">キャンセル</button>
        <button class="btn">アップロード</button>
      </div>
    </div>
  </div>
</template>

<script>
/* eslint-disable */

export default {
  props: ['greet'],
  // props: {
  //   greet: {
  //    type: String,
  //    default: 'hogehoge'
  //   }
  // },
  data () {
    return {
      showContent2: false
    }
  },
  methods: {
    // openAfterMusicUploadModal (){
    //   this.$emit('openAfterMusicUploadModal', this.showContent2);
    // },
    closeAfterMusicUploadModal (){
      this.$emit('closeAfterMusicUploadModal', this.showContent2);
    }
  },
}
</script>
```vue

呼び出しもと
headerAfterLogin.vue
```vue
<template>
    <div>
        <header class="header">
            <NuxtLink to="/"><h1 class="logo">Sound Matching</h1></NuxtLink>
            <nav class="nav">
            <ul>
                <li>検索</li>
                <!-- <li>{{ $store.state.auth.user.name }}</li> -->
                <button @click="logout">ログアウト</button>
                <li><button class="btn" @click="openBeforeMusicUploadModal">アップロード</button></li>
            </ul>
            </nav>
        </header>
        <div>
          <transition name="modal" mode="out-in">
            <BeforeMusicUploadModal
              v-show="showContent"
              @click.self="closeBeforeMusicUploadModal"
              @closeBeforeMusicUploadModal="closeBeforeMusicUploadModal"
              @openAfterMusicUploadModal="openAfterMusicUploadModal"
            ></BeforeMusicUploadModal>
          </transition>
        </div>
        <div>
          <transition name="modal" mode="out-in">
            <AfterMusicUploadModal
              greet='Hello with props'
              v-show="showContent2"
              @click.self="closeAfterMusicUploadModal"
              @closeAfterMusicUploadModal="closeAfterMusicUploadModal"
            ></AfterMusicUploadModal>
          </transition>
        </div>
    </div>
</template>

<script>
import BeforeMusicUploadModal from '@/components/BeforeMusicUploadModal.vue'
import AfterMusicUploadModal from '@/components/AfterMusicUploadModal.vue'

export default {
    transition: {
    name: 'modal',
    mode: 'out-in'
  },
  components: {
    BeforeMusicUploadModal,
    AfterMusicUploadModal
  },
  data () {
    return {
      showContent: false,
      showContent2: false
    }
  },
  methods: {
    openBeforeMusicUploadModal () {
      this.showContent = true
    },
    closeBeforeMusicUploadModal () {
      this.showContent = false
    },
    openAfterMusicUploadModal () {
      this.showContent = false
      this.showContent2 = true
      console.log(this.showContent)
      console.log(this.showContent2)
    },
    closeAfterMusicUploadModal () {
      this.showContent2 = false
    },
    logout() {
      this.$auth.logout();
    },
  },
}
</script>

やること

呼び出す子コンポーネントを定義

<script>
import BeforeMusicUploadModal from '@/components/BeforeMusicUploadModal.vue'
import AfterMusicUploadModal from '@/components/AfterMusicUploadModal.vue'

export default {
    transition: {
    name: 'modal',
    mode: 'out-in'
  },
  components: {
    BeforeMusicUploadModal,
    AfterMusicUploadModal
  },
  
  ~~~
  
</script>

ここで呼び出してる
タグ内にemitされてきて実行するメソッドを記述する(@closeBeforeMusicUploadModal="closeBeforeMusicUploadModal"とか)
各個要素で定義したメソッドがemitされてheader内で実行される

        <div>
          <transition name="modal" mode="out-in">
            <BeforeMusicUploadModal
              v-show="showContent"
              @click.self="closeBeforeMusicUploadModal"
              @closeBeforeMusicUploadModal="closeBeforeMusicUploadModal"
              @openAfterMusicUploadModal="openAfterMusicUploadModal"
            ></BeforeMusicUploadModal>
          </transition>
        </div>
        <div>
          <transition name="modal" mode="out-in">
            <AfterMusicUploadModal
              greet='Hello with props'
              v-show="showContent2"
              @click.self="closeAfterMusicUploadModal"
              @closeAfterMusicUploadModal="closeAfterMusicUploadModal"
            ></AfterMusicUploadModal>
          </transition>
        </div>

Discussion