我们在开发web页面的过程中,很容易就遇到同一个内容需要响应多种事件,而处理这些过程又很容易引发彼此的冲突(事件之间)。由于本人在最近开发过程中就遇到这些问题,网上的教程五花八门,真正能实现的没几个,也有可能我用的姿势不对(O(∩_∩)O哈哈~)

  废话少说,就让我们开始吧~

1. 鼠标单、双击事件

  来源于本人开发中,涉及对element-ui中的el-tree添加节点的双击事件,示例如下(只涉及关键部分):

<template>
  <div>
    <el-tree
      empty-text
      v-loading="treeLoading"
      :data="data"
      show-checkbox
      default-expand-all
      :expand-on-click-node="false"
      :check-on-click-node="true"
      node-key="id"
      :props="defaultProps"
      :default-checked-keys="CheckedKeys"
      @check-change="CheckChange"
     >
         <span class="custom-tree-node" slot-scope="{node,data}">
            <span
              @dblclick="NodedbClick(data,node)"
              @click="NodeClick(data, node)"
            >{{node.label}}</span>
          </span>
    </el-tree>
  </div>
</template>

<script>
  export default {
   data() {
       return {
          ...
          data: [],
          treeLoading: false,
          treeClick: null, //这个是关键,监听单双击
          ...
       }
      },
      ...
      methods: {
          ...
          //单击事件
        NodeClick(data, node) {
              clearTimeout(this.treeClick); //清除延迟
              this.treeClick = setTimeout(() => {
                //执行单击方法
                CheckChange(data, node.checked)
                //这里我的单击方法和复选框改变的方法一致  
              }, 300);    //300ms后没有点击两次,就执行单击事件
        },
        //双击事件
        NodedbClick(data, node) {    //否则执行双击事件,执行前清除延迟
              clearTimeout(this.treeClick); //清除延迟
              node.checked = true; //双击要给复选框打钩
              node.parent.indeterminate = !node.parent.checked;
              //给父节点多选框一个状态
              this.CheckChange(data, node.checked); //点击即选中并跳转
              /**
                  其他代码
                  **/
        },
        //选中事件
        CheckChange(datas, checked, indeterminate) {
          if (checked) {
            //选中
            /**
                  执行选中逻辑
                **/
          } else {
            //取消选中
            /**
                  执行取消选中逻辑
                  **/
          }
    },
      },
      ...
  }
</script>

2. 拖拽含输入框的组件

  来源于本人开发中,涉及对element-ui中的el-autocomplete添加拖拽事件,写得不好的话容易造成拖拽事件和焦点事件冲突,示例如下(只涉及关键部分):

<template>
  <div class="search-box" ref="searchbox" @mousedown="move">
    <el-autocomplete
      v-model="value"
      :fetch-suggestions="remoteMethod"
      placeholder="请输入内容"
      @select="changeOption"
      size="mini"
      class="search-input"
    ></el-autocomplete>
    <i class="el-icon-search search-icon el-input__icon" slot="suffix"></i>
  </div>
</template>

<script>
export default {
  data() {
    return {
      ...
      downTime: null,    
      upTime: null,    //按下鼠标时间和放开鼠标时间
      isMoving: false,
      ...
    };
  },
  methods: {
    ...
    //自动搜索方法
    remoteMethod(query, cb) {
     //执行搜索方法
    },

    move(e) {
      this.downTime = new Date().getTime(); //按下鼠标时间
      //获取目标元素
      let odiv = this.$refs.searchbox,
        //元素的宽高
        odivW = odiv.offsetWidth,
        odivH = odiv.offsetHeight,
        wW = window.innerWidth,
        wH = window.innerHeight,
        //算出鼠标相对元素的位置
        disX = e.clientX - odiv.offsetLeft,
        disY = e.clientY - odiv.offsetTop,
        //居中导致多了transformX的差值
        translateX = odivW / 2;
      //鼠标按下并移动的事件
      if (Math.abs(this.upTime - this.downTime) >= 1000) { // 按住组件大于1秒就是要拖拽
        document.onmousemove = e => {
          //用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
          let left = e.clientX - disX - translateX;
          let top = e.clientY - disY;
          top = top < 60 ? 60 : top;
          //避免出界
          if (left < 6) {
            left = 6;
          } else if (left + odivW > wW - 6) {
            left = wW - odivW - 6;
          }
          if (top < 66) {
            //60是顶部nav的高度
            top = 66;
          } else if (top + odivH > wH - 40 - 6) {
            //46是底部的高度
            top = wH - odivH - 40 - 6;
          }

          left += translateX;
          //绑定元素位置到positionX和positionY上面
          this.positionX = top;
          this.positionY = left + translateX;

          //移动当前元素
          //odiv.style.transform = 'translateX(0)';
          odiv.style.left = left + "px";
          odiv.style.top = top + "px";

          //避免移动过程中,其他文字被选中
          window.getSelection
            ? window.getSelection().removeAllRanges()
            : document.selection.empty();
          this.isMoving = true;
        };
      }
      document.onmouseup = e => {
        document.onmousemove = null;
        document.onmouseup = null;
        this.isMoving = false;
        this.upTime = new Date().getTime();  //放开鼠标时间
      };
    },

    //选中
    changeOption(option) {
      //执行选中逻辑
    },
    ...
  },
  ...
}
</script>

3. el-autocomplete收缩

  来源于本人开发中,涉及对element-ui中的el-autocomplete设置收缩,默认的话是获取到焦点,搜索完选中才会收缩或者点击其他地方。
  但是本人遇到的问题是将el-autocomplete套在一个div中,浮在一个页面上还要支持拖拽,可能姿势不对就导致多种事件的冲突,示例如下(只涉及关键部分)

//因为是采用引入组件的方式,如果直接放在里面可忽略这一步
//配置vuex相关

//state.js
const state = {
  ...
  SEARCHBOX: false,
  ...
}

//mutations.js
const mutations = {
  ...
  SEARCHBOXX(state, val) {
  state.SEARCHBOX = val
  }
  ...
}
//父组件
<template>
<div>
    <div id="container" @mouseenter="hideSearchBox">
    </div>
   <search-box />
</div>
</template>

<script>
import SearchBox from '路径'
  export default {
  components: {
   ...
   SearchBox
   ...
  },
  ...
  methods: {
   ...
   //隐藏搜索下拉框
    hideSearchBox() {
      this.$store.commit("SEARCHBOXX", false);
    }
   ...
  },
  ...
 }
</script>
//SearchBox子组件
<template>
  <div class="search-box" ref="searchbox" @mousedown="move" @mouseenter="showSearchBox">
    <div class="Shining"></div>
    <el-autocomplete
      v-model="value"
      :fetch-suggestions="remoteMethod"
      placeholder="请输入内容"
      @select="changeOption"
      :debounce="0"
      size="mini"
      :popper-class="showDropDown?'show':'hide'"
      :autofocus="true"
      class="search-input"
    ></el-autocomplete>
    <i class="el-icon-search search-icon el-input__icon" slot="suffix"></i>
  </div>
</template>

<script>
  export default {
    name: 'SearchBox',
    ...
    computed: {
    showDropDown: {
      get() {
        return this.$store.state.SEARCHBOX;
      },
      set() {}
    }
   },
   ...
   methods: {
    //显示搜索框
    showSearchBox() {
      this.$store.commit("SEARCHBOXX", true);
    }
   },
   ...
  }
</script>

<style lang="scss">
.show {
  display: block;
}

.hide {
  display: none;
}
</style>