AnnVoV / blog

24 stars 2 forks source link

写Vue 的热区组件小结 #9

Open AnnVoV opened 6 years ago

AnnVoV commented 6 years ago

1.拖拽实现思路

2.指令里$emit为什么不如预期

重点问题 现象:遇到的问题,在指令里emit 的时候,我的自定义参数通过$emit带不出去?

原因: 本质原因不是参数无法带出去,而是我搞错了我的指令里ctx.$emit的指向, 也就是说ctx.emit是谁抛出的

// 看下我写的模板
// hotzone/index.vue
<template>
  <div class="hotzone-container">
    <section v-touchdir="hotzoneList">
    </section>
  </div>
</template>

// APP.vue
// 使用了上面的组件
<hotzone-drag></hotzone-drag>

// hotzone/index.js
// 我在mousestart的时候,写了下面的事件
handler = {
  mousedown: function(e) {
    // 我这里emit 了selectstart事件,我以为我的selectstart事件是从hotzone-container 上emit的,这个ctx指向的是components context,所以其实是hotzone-drag这个组件在emit,所以接受这个事件的也是hotzone-drag这个组件
    ctx.$emit('selectstart', {...});
  }
};

定向emit: 某些情况我们需要设置我们接受事件的target,就可以考虑使用自定义事件来new CustomEvent()dispatchEvent 解决方法:目前是通过自定义事件做的 参考:https://github.com/vuejs/vue/issues/7147

event = new CustomEvent('addhotzone', dragPos)
target.dispatchEvent(event)

3.v-bindDir:xxx

指令外部与指令内部需要传递一些数据,我们则可以通过v-bindDir:xxx 这种方式来绑定数据或者函数

举个例子: 外部使用热区组件时,会维护一个hotzoneList,来维护当前的热区数组;当点击删除按钮时,可能会删除hotzoneList对应的某个元素;此时我们需要让指令内部知道我们的hotzoneList发生了变化,那我们可以这样

 <section class="hotzone"
                 :style="{backgroundImage: `url( ${imgUrl})`, width: `${containerWidth}px`, height: `${containerHeight}px`, backgroundSize: 'cover'}"
                 v-touchdir="hotzoneList"
                 @addhotzone="addZone"
                 @selectstart="selectStart"
                 @selectup="changeZone"></section>

// 然后在指令内部的update方法里
export default {
    bind (el, binding, vnode) {
        bindEvent(el, vnode.context, vnode)
    },
    update(el, binding, vnode) {
        allHotzone = binding.value && binding.value.length || 0;
    },
    unbind (el) {
        offEvent(el)
    }
}

4.clickoutside 的判断方法

本质是对Node.contains 这个api不熟悉, 这个方法很常用 看下v-clickoutside 这个判断的实现 https://github.com/varHarrie/varharrie.github.io/issues/4

export defult {
  bind(el, binding, vnode) {
    this.click = (e) => {
      return !el.contains(e.target);
    }
    document.body.addEventListener('click', this.click)
  }
  update() {
  }
  unbind(el) {
    document.body.removeEventListener('click', this.click)
  }
}