获取父组件事件的Vue子组件目标

时间:2018-09-17 03:21:22

标签: javascript vue.js vuejs2 vue-component dom-events

我正在试验Vue.js,并且我有一个父组件和一些子组件。我想要做的是跟踪“点击并拖动”到其上的组件。

This is an example to understand my problem.

到目前为止,我所拥有的是用户在父组件上发起一个mousedown事件,该事件有条件地激活了子组件上的mouseover侦听器,我在其中跟踪移动了哪些子组件。当用户释放鼠标按钮时,mouseover侦听器将被删除。

我已经可以使用此method to conditionally add event listeners来执行此操作,问题是当初始mousedown事件触发时,下面的子组件不会触发mouseover事件,因此它不会为了得到跟踪,将按预期跟踪子组件上的后续mouseover。我还希望能够跟踪鼠标在启动“单击并拖动”时所在的子组件。

要解决此问题,我获得了event.target.__vue__事件的mousedown来访问子组件并显式调用跟踪方法。 (示例中App.vue的第25行)

我的问题是:除了使用mousedown之外,还有一种Vue.js合适的方式来触发对父组件上的初始event.target.__vue__下的子组件的跟踪方法吗?还是通常有更好的方法来跟踪哪些子组件被“单击并拖动”了?

1 个答案:

答案 0 :(得分:2)

如果您的父组件和子对象存在牢固的关系(例如子组件必须放置在父组件内部),那么您可能想尝试Vue provide&inject

  1. 父组件提供了一种方法,允许子级注册其音轨,然后使用provide将其传递给孩子(在演示中,通过this关键字将实例传递给子级)。

  2. 每个子组件只需要调用该方法即可将其曲目上传到父组件。

但是要提供/注入,请注意以下事项:

  

注意:Provide和Inject绑定不是反应性的。这是   故意的。但是,如果您向下传递观察对象,则属性   在那个物体上确实保持反应性。

下面是一个简单的演示

Vue.config.productionTip = false

Vue.component('so-parent', {
  provide() {
    return {
      _tracker: this
    }
  },
  template: `
    <div @mousedown="toggleTrack(true)" @mouseup="toggleTrack(false)"><h3>children count: {{children.length}} - tracking: {{trackState}}</h3><h3>{{tracks}}</h3><slot></slot></div>
  `,
  data() {
    return {
      children: [],
      tracks: [],
      trackState: false
    }
  },
  methods: {
    _registerChild(child) {
      this.children.push(child)
    },
    _registerTracks(track) {
      if (this.trackState) this.tracks.push(track)
    },
    toggleTrack: function(state) {
      this.trackState = state
      if(!this.trackState) {
        this.tracks = []
      }
    }
  }
})

Vue.component('so-child', {
  inject: {
    _tracker: {
      default () {
        console.error('so-child must be child of so-parent')
      }
    }
  },
  data() {
    return {
      childState: false,
      childSeq: 0
    }
  },
  props: ['cid'],
  render(h) {
    return h('div', {
      class: 'child',
      on: {
        mouseover: () => this._tracker._registerTracks(this.cid)
      }
    }, [this.childSeq + ' Child Component ' + this.cid, this.$slots.default])
  },
  mounted() {
    this.childSeq = this._tracker.children.length
    this._tracker._registerChild(this)
  }
})

new Vue({
  el: '#app'
})
div.child {
  border: 1px solid;
  display: inline-block;
  padding: .5em 1em;
  margin: 0 0.5em 1em;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  &:hover {
    background: #b2bde3;
    cursor: pointer;
    color: white;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>

<div id="app">
  <so-parent>
    <so-child cid="A"></so-child>
    <so-child cid="B"></so-child>
    <so-child cid="C"></so-child>
    <so-child cid="D"></so-child>
  </so-parent>
</div>