我们在开发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>

  • alipay
  • wechat