在Vue2中如何通过变量动态绑定事件及传递额外参数?

Vue2是否支持给v-on修饰符动态指定eventType?

如题,目前在做低代码相关的工作,但是旧代码的组件引用关系非常抽象,而且绑定事件也不够灵活,所以希望在事件绑定的范畴内优化一下。在查阅Vue文档之后,发现文档里并未提到这种做法。我的设想是通过指定变量的方式来指定某个输入框/按钮能动态绑定某一类型的事件;如果无法通过变量来指定触发的事件类型,那么在v-on传入一个对象时,其中的回调函数如何传入剩余参数?

<template>
  <div id="app">
    <div class="box" v-on:eventType="eventList" v-for="(item, index) in child" :key="index">
      {{ item.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'APP',
  data() {
    return {
      eventList: {
        mouseenter: this['mouseenter'],
        mouseleave: this['mouseleave'],
        click: this['handleClick'],
      },
      child: [
        {
          name: 'c1'
        },
        {
          name: 'c2'
        }
      ],
      eventType: 'click'
    }
  },
  methods: {
    mouseenter(e) {
      console.log(e)
    },
    mouseleave(e) {
      console.log(e)
    },
    handleClick(e) {
      console.log(e)
    },
  },
  mounted() {
  }
}
</script>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
@mixin boxafter {
  content: '';
  width: 100%;
  height: 100%;
  border: 1px solid;
  position: absolute;
}
.box {
  width: 100px;
  height: 100px;
  position: relative;
  background-color: #aed;
}
</style>

在eventList中的mouseenter回调函数,在触发时,只能接收到默认的事件对象, 如果此时需要额外传入一个item,应该如何实现呢?希望路过的大佬指教一下

阅读 622
avatarAI BotBETA

回答

在Vue2中,通过变量动态绑定事件及传递额外参数可以通过以下方式实现:

  1. 动态绑定事件类型
    Vue2本身不支持直接通过变量动态指定v-on的事件类型(如v-on:[eventType]="handler")。不过,你可以通过计算属性或方法来动态绑定事件。

    你可以使用v-on指令和一个方法来间接实现这一点。在这个方法中,根据eventType的值调用相应的事件处理函数。

    <template>
      <div id="app">
        <div 
          class="box" 
          v-for="(item, index) in child" 
          :key="index"
          @click="handleEvent(item, $event, 'click')"
          @mouseenter="handleEvent(item, $event, 'mouseenter')"
          @mouseleave="handleEvent(item, $event, 'mouseleave')"
        >
          {{ item.name }}
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'APP',
      data() {
        return {
          child: [
            { name: 'c1' },
            { name: 'c2' }
          ],
          eventType: 'click' // 这个变量现在仅用于逻辑控制,不直接绑定事件
        };
      },
      methods: {
        handleEvent(item, event, eventType) {
          if (eventType === this.eventType) {
            // 根据 eventType 调用相应的处理函数
            if (eventType === 'click') {
              this.handleClick(item, event);
            } else if (eventType === 'mouseenter') {
              this.mouseenter(item, event);
            } else if (eventType === 'mouseleave') {
              this.mouseleave(item, event);
            }
          }
        },
        mouseenter(item, e) {
          console.log('mouseenter', item, e);
        },
        mouseleave(item, e) {
          console.log('mouseleave', item, e);
        },
        handleClick(item, e) {
          console.log('click', item, e);
        },
      }
    };
    </script>
  2. 传递额外参数
    在上面的示例中,handleEvent方法已经接收了item和事件对象$event作为参数。这样,你就可以在事件处理函数中访问这些参数。

    注意,这种方式虽然实现了动态事件绑定和额外参数的传递,但需要在模板中为每个可能的事件类型显式地绑定事件处理器。如果你的事件类型非常多,这可能会显得有点繁琐。

总结来说,Vue2不支持直接通过变量动态指定v-on的事件类型,但可以通过方法间接实现。对于传递额外参数,可以直接在事件处理函数中接收这些参数。

2 个回答

如果模板比较简单,可以考虑使用 h 函数。

<script>
import { defineComponent, h } from 'vue';

export default defineComponent({
  name: 'APP',
  data() {
    return {
      eventList: {
        // 修改为 on 开头的事件
        onMouseenter: this.mouseenter,
        onMouseleave: this.mouseleave,
        onClick: this.handleClick,
      },
      child: [
        {
          name: 'c1',
        },
        {
          name: 'c2',
        },
      ],
      eventType: 'click',
    };
  },
  mounted() {
  },
  methods: {
    mouseenter(e) {
      console.log(e);
    },
    mouseleave(e) {
      console.log(e);
    },
    handleClick(e) {
      console.log(e);
    },
  },
  render() {
    return () => h(
      'div',
      { id: 'app' },
      child.map((item, index) => (h(
        'div',
        {
          key: index,
          class: 'box',
          // 传入事件
          ...this.eventList,
        },
        item.name,
      ))),
    );
  },
});
</script>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
@mixin boxafter {
  content: '';
  width: 100%;
  height: 100%;
  border: 1px solid;
  position: absolute;
}
.box {
  width: 100px;
  height: 100px;
  position: relative;
  background-color: #aed;
}
</style>

在Vue 2.6.0之前的版本中,v-on指令这种动态绑定是不支持的。因此,如果你使用的是Vue 2.6.0或更高版本,就可以通过v-on指令实现动态事件绑定。

对于v-on指令不支持动态指定事件类型。可以通过一些变通的方法来实现类似的效果。以下是一个解决方案:
1.使用自定义指令:你可以创建一个自定义指令来动态绑定事件。
2.传递额外参数:在回调函数中传递额外参数,可以通过闭包或箭头函数来实现。
以下是一个示例代码,展示了如何实现这两个需求:

<template>
  <div id="app">
    <div
      class="box"
      v-for="(item, index) in child"
      :key="index"
      v-dynamic-event="{ eventType, handler: eventList[eventType], item }"
    >
      {{ item.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'APP',
  data() {
    return {
      eventList: {
        mouseenter: this.mouseenter,
        mouseleave: this.mouseleave,
        click: this.handleClick,
      },
      child: [
        { name: 'c1' },
        { name: 'c2' },
      ],
      eventType: 'click',
    };
  },
  methods: {
    mouseenter(e, item) {
      console.log('mouseenter', e, item);
    },
    mouseleave(e, item) {
      console.log('mouseleave', e, item);
    },
    handleClick(e, item) {
      console.log('click', e, item);
    },
  },
  directives: {
    dynamicEvent: {
      bind(el, binding) {
        const { eventType, handler, item } = binding.value;
        el.addEventListener(eventType, (e) => handler(e, item));
      },
      unbind(el, binding) {
        const { eventType, handler } = binding.value;
        el.removeEventListener(eventType, handler);
      },
    },
  },
};
</script>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.box {
  width: 100px;
  height: 100px;
  position: relative;
  background-color: #aed;
}
</style>

在这个示例中,创建了一个自定义指令 v-dynamic-event,它可以根据传入的 eventType 动态绑定事件,并且在事件触发时传递额外的 item 参数。这样就可以实现动态绑定事件类型和传递额外参数

推荐问题
宣传栏