Аудио DOM, созданный внутри vuex, не реагирует - PullRequest
0 голосов
/ 03 апреля 2020

Я хочу создать аудиоэлемент, который будет использоваться для воспроизведения всех аудио-URL, которые у меня есть на всех маршрутах, я думаю, что это полезный подход для SPA (я прав?). Поэтому я решил объявить новый Audio в состоянии vuex, которое я могу легко использовать и обновлять, просто изменив свойство sr c аудиообъекта. И это работает, но проблема возникает, когда я хочу получить свойства этого аудиообъекта, такие как currentTime и длительность для построения индикатора выполнения звука, и он не реагирует. Как решить эту проблему?

const state = {
  audio: false,
  object: new Audio()
}

// getters
const getters = {
  audio: state => state.audio,
  percentage: state => (isNaN(Math.round((state.object.currentTime / state.object.duration) * 100))) ? 0 : Math.round((state.object.currentTime / state.object.duration) * 100)
}

// actions
const actions = {
  playAudio ({ commit, state }, previewUrl) {
    commit('play_audio', previewUrl)
  },
  stopAudio ({ commit, state }) {
    commit('stop_audio')
  }
}

// mutations
const mutations = {
  play_audio (state, previewUrl) {
    state.object.pause()
    state.object.currentTime = 0.0
    state.object.src = previewUrl
    state.object.play()
    state.audio = {
      preview_url: previewUrl
    }
  },
  stop_audio (state) {
    state.object.pause()
    state.object.currentTime = 0.0
    state.src = ''
    state.audio = false
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

1 Ответ

2 голосов
/ 03 апреля 2020

Vue официально поддерживает только простые JavaScript объекты в качестве реактивных данных; такие вещи, как элементы DOM и другие подобные объекты, не будут и не могут стать реактивными.

Одним из способов решения этой проблемы является сохранение только строковых audioSrc и логических значений isAudioPlaying в хранилище Vuex, а затем управление объект Audio в компоненте root Vue. Вы можете наблюдать за изменениями audioSrc и isAudioPlaying, а затем вызывать методы объекта Audio в ответ на эти изменения.

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    audioUrl: null,
    isAudioPlaying: false,
  },
  
  mutations: {
    play(state, url) {
      state.audioUrl = url
      state.isAudioPlaying = true
    },
    
    pause(state) {
      state.isAudioPlaying = false
    }
  }
})

new Vue({
  el: '#app',
  store,
  
  created() {
    this.audio = new Audio()
  },
  
  watch: {
    '$store.state.audioUrl'(url) {
      this.audio.pause()
      this.audio.src = url
      this.audio.currentTime = 0
      this.audio.play()
    },
    
    '$store.state.isAudioPlaying'(playing) {
      if (playing) {
        this.audio.play()
      } else {
        this.audio.pause()
      }
    }
  },
  
  methods: {
    play(url) {
      this.$store.commit('play', url)
    },
    pause() {
      this.$store.commit('pause')
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.3/vuex.js"></script>

<div id="app">
  <button @click="play('https://upload.wikimedia.org/wikipedia/commons/5/5b/Ludwig_van_Beethoven_-_Symphonie_5_c-moll_-_1._Allegro_con_brio.ogg')">Play Beethoven</button>
  <button @click="pause">Pause</button>
  
  <div>audioUrl: {{ $store.state.audioUrl }}</div>
  <div>isAudioPlaying: {{ $store.state.isAudioPlaying }}</div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...