$ emit或$ on的奇怪行为

时间:2017-07-29 16:41:02

标签: javascript vuejs2 vue-router

在我正在处理的网站中,我不得不使用事件发射器来达到要求。请查看fiddle。添加新邮件时,它会正常工作。但是当我点击route1route2并返回Parent视图时,问题便开始了。然后,我尝试添加一条新消息。它将出现两次或三次(如果您访问所有路线并返回)。我不完全确定是怎么回事。任何解决这个问题的建议都会很棒。

PS:请不要建议使用$parent而不是$root,因为在我的项目中我必须使用$root,因为该组件不是父组件的直接子组件。

以下是示例。

const Parent = {
	template: `
  <div>
    <child-component></child-component>
    <p v-for="msg in allMessages">{{msg}}</p>
    </div>
  `,
  computed: {
    allMessages: function () {
      return this.$root.$store.state.storedMessages
    }
  },
  mounted(){
    this.$root.$on('NewMessage', function(data){
    	this.$store.dispatch('newMessage', data)
    })
  }
}
Vue.component('navs', {
	template: `
  <div>
    <div class="left-nav-menu">

          <router-link to="/">Parent</router-link>

          <router-link to="/route1">route1</router-link>

          <router-link to="/route2">route2</router-link>

    </div>
  </div>
`
})

Vue.component('child-component', {
  template: `
  	 <form id="messageForm" @submit.prevent="sendMessage">
      <input type="text" v-model="message">
      <button type="submit" >Send Message</button>
    </form>
  `,
  data () {
    return {
      message: ''
    }
  },
  computed: {
  	allMessages: function () {
      return this.$root.$store.state.storedMessages
    }
  },
  methods: {
    sendMessage: function () {
      this.$root.$emit('NewMessage', this.message)
    }
  }
})

const route1 = {
	template: `<p>Route1</p>`
}
const route2 = {
	template: `<p>Route2</p>`
}

const store = new Vuex.Store({
	state: {
  	storedMessages: []
  },
    mutations: {
    	newMessage(state, data) {
          state.storedMessages.push(data)
      }
    },
    actions: {
        newMessage({commit}, payload) {
        
            commit('newMessage', payload)
        }
    }
})
const router = new VueRouter({
	routes: [
  	{ name: 'parent', path: '/', component: Parent },
     { name: 'route1', path: '/route1', component: route1 },
      { name: 'route2', path: '/route2', component: route2 }
  ]
})
new Vue({
	el: '#app',
  store,
  router
})
* {
  box-sizing: border-box;
}

.listing {
  list-style-type: none;
  overflow: hidden;
  padding: 0;
  li {
    float: left;
    width: 175px;
    padding: 10px;
    text-align: center;
    border: 1px #ddd solid;
    background: white;
    margin: 5px;
    cursor: pointer;
    img {
      width: 100%;
      margin-bottom: 7px;
    }
    &:hover {
      background: #eee;
    }
  }
}

.item-view {
  text-align: center;
}

.item {
  background: white;
  padding: 10px;
}

a {
  font-size: 16px;
  display: inline-block;
  padding: 10px;
  border: 1px #ddd solid;
  background: white;
  color: black;
  margin: 10px;
  &.back-listing {
    position: absolute;
    left: 0;
    top: 0;
  }
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <navs></navs>
  <router-view></router-view>
</div>

1 个答案:

答案 0 :(得分:3)

这种情况正在发生,因为您不断在mounted中添加消息处理程序。你需要删除它们。

const Parent = {
    template: `
  <div>
    <child-component></child-component>
    <p v-for="msg in allMessages">{{msg}}</p>
    </div>
  `,
  computed: {
    allMessages: function () {
      return this.$root.$store.state.storedMessages
    }
  },
  methods:{
    sendMessage(data){
      this.$store.dispatch('newMessage', data)
    }
  },
  mounted(){
    this.$root.$on('NewMessage', this.sendMessage)
  },
  beforeDestroy(){
    this.$root.$off('NewMessage', this.sendMessage)
  }
}

更新了代码。

&#13;
&#13;
const Parent = {
	template: `
  <div>
    <child-component></child-component>
    <p v-for="msg in allMessages">{{msg}}</p>
    </div>
  `,
  computed: {
    allMessages: function () {
      return this.$root.$store.state.storedMessages
    }
  },
  methods:{
  	sendMessage(data){
      this.$store.dispatch('newMessage', data)
    }
  },
  mounted(){
    this.$root.$on('NewMessage', this.sendMessage)
  },
  beforeDestroy(){
    this.$root.$off('NewMessage', this.sendMessage)
  }
}

Vue.component('navs', {
	template: `
  <div>
    <div class="left-nav-menu">

          <router-link to="/">Parent</router-link>

          <router-link to="/route1">route1</router-link>

          <router-link to="/route2">route2</router-link>

    </div>
  </div>
`
})

Vue.component('child-component', {
  template: `
  	 <form id="messageForm" @submit.prevent="sendMessage">
      <input type="text" v-model="message">
      <button type="submit" >Send Message</button>
    </form>
  `,
  data () {
    return {
      message: ''
    }
  },
  computed: {
  	allMessages: function () {
      return this.$root.$store.state.storedMessages
    }
  },
  methods: {
    sendMessage: function () {
      this.$root.$emit('NewMessage', this.message)
    }
  }
})

const route1 = {
	template: `<p>Route1</p>`
}
const route2 = {
	template: `<p>Route2</p>`
}

const store = new Vuex.Store({
	state: {
  	storedMessages: []
  },
    mutations: {
    	newMessage(state, data) {
          state.storedMessages.push(data)
      }
    },
    actions: {
        newMessage({commit}, payload) {
        
            commit('newMessage', payload)
        }
    }
})
const router = new VueRouter({
	routes: [
  	{ name: 'parent', path: '/', component: Parent },
     { name: 'route1', path: '/route1', component: route1 },
      { name: 'route2', path: '/route2', component: route2 }
  ]
})
new Vue({
	el: '#app',
  store,
  router
})
&#13;
* {
  box-sizing: border-box;
}

.listing {
  list-style-type: none;
  overflow: hidden;
  padding: 0;
  li {
    float: left;
    width: 175px;
    padding: 10px;
    text-align: center;
    border: 1px #ddd solid;
    background: white;
    margin: 5px;
    cursor: pointer;
    img {
      width: 100%;
      margin-bottom: 7px;
    }
    &:hover {
      background: #eee;
    }
  }
}

.item-view {
  text-align: center;
}

.item {
  background: white;
  padding: 10px;
}

a {
  font-size: 16px;
  display: inline-block;
  padding: 10px;
  border: 1px #ddd solid;
  background: white;
  color: black;
  margin: 10px;
  &.back-listing {
    position: absolute;
    left: 0;
    top: 0;
  }
}
&#13;
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <navs></navs>
  <router-view></router-view>
</div>
&#13;
&#13;
&#13;