diff --git a/components/radio/RadioButton.jsx b/components/radio/RadioButton.jsx
index 2b4599a1a..b88d51be0 100644
--- a/components/radio/RadioButton.jsx
+++ b/components/radio/RadioButton.jsx
@@ -1,6 +1,5 @@
 import Radio from './Radio';
-import PropTypes from '../_util/vue-types';
-import { getOptionProps } from '../_util/props-util';
+import { getOptionProps, getListeners } from '../_util/props-util';
 import { ConfigConsumerProps } from '../config-provider';
 
 export default {
@@ -22,7 +21,7 @@ export default {
         ...otherProps,
         prefixCls,
       },
-      on: { ...this.$listeners },
+      on: getListeners(this),
     };
     if (this.radioGroupContext) {
       radioProps.on.change = this.radioGroupContext.onRadioChange;
diff --git a/components/slider/index.jsx b/components/slider/index.jsx
index 37aa83cc9..63acf568b 100644
--- a/components/slider/index.jsx
+++ b/components/slider/index.jsx
@@ -1,6 +1,6 @@
 import PropTypes from '../_util/vue-types';
 import BaseMixin from '../_util/BaseMixin';
-import { getOptionProps } from '../_util/props-util';
+import { getOptionProps, getListeners } from '../_util/props-util';
 import VcSlider from '../vc-slider/src/Slider';
 import VcRange from '../vc-slider/src/Range';
 import VcHandle from '../vc-slider/src/Handle';
@@ -117,6 +117,7 @@ const Slider = {
     const getPrefixCls = this.configProvider.getPrefixCls;
     const prefixCls = getPrefixCls('slider', customizePrefixCls);
     const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
+    const listeners = getListeners(this);
     if (range) {
       const vcRangeProps = {
         props: {
@@ -126,7 +127,7 @@ const Slider = {
           handle: info => this.handleWithTooltip(tooltipPrefixCls, info),
         },
         ref: 'sliderRef',
-        on: this.$listeners,
+        on: listeners,
       };
       return <VcRange {...vcRangeProps} />;
     }
@@ -138,7 +139,7 @@ const Slider = {
         handle: info => this.handleWithTooltip(tooltipPrefixCls, info),
       },
       ref: 'sliderRef',
-      on: this.$listeners,
+      on: listeners,
     };
     return <VcSlider {...vcSliderProps} />;
   },
diff --git a/components/tabs/tabs.jsx b/components/tabs/tabs.jsx
index 4b95b9127..321508c6b 100644
--- a/components/tabs/tabs.jsx
+++ b/components/tabs/tabs.jsx
@@ -3,7 +3,12 @@ import VcTabs, { TabPane } from '../vc-tabs/src';
 import TabContent from '../vc-tabs/src/TabContent';
 import { isFlexSupported } from '../_util/styleChecker';
 import PropTypes from '../_util/vue-types';
-import { getComponentFromProp, getOptionProps, filterEmpty } from '../_util/props-util';
+import {
+  getComponentFromProp,
+  getOptionProps,
+  filterEmpty,
+  getListeners,
+} from '../_util/props-util';
 import { cloneElement } from '../_util/vnode';
 import { ConfigConsumerProps } from '../config-provider';
 import TabBar from './TabBar';
@@ -139,6 +144,7 @@ export default {
     ) : null;
 
     const renderTabBarSlot = renderTabBar || this.$scopedSlots.renderTabBar;
+    const listeners = getListeners(this);
     const tabBarProps = {
       props: {
         ...this.$props,
@@ -146,7 +152,7 @@ export default {
         tabBarExtraContent,
         renderTabBar: renderTabBarSlot,
       },
-      on: this.$listeners,
+      on: listeners,
     };
     const contentCls = {
       [`${prefixCls}-${tabPosition}-content`]: true,
@@ -165,7 +171,7 @@ export default {
         __propsSymbol__: Symbol(),
       },
       on: {
-        ...this.$listeners,
+        ...listeners,
         change: this.handleChange,
       },
       class: cls,
diff --git a/components/tree/DirectoryTree.jsx b/components/tree/DirectoryTree.jsx
index 03bf15947..f3dfff13e 100644
--- a/components/tree/DirectoryTree.jsx
+++ b/components/tree/DirectoryTree.jsx
@@ -7,7 +7,7 @@ import Tree, { TreeProps } from './Tree';
 import { calcRangeKeys, getFullKeyList } from './util';
 import Icon from '../icon';
 import BaseMixin from '../_util/BaseMixin';
-import { initDefaultProps, getOptionProps } from '../_util/props-util';
+import { initDefaultProps, getOptionProps, getListeners } from '../_util/props-util';
 import { ConfigConsumerProps } from '../config-provider';
 
 // export type ExpandAction = false | 'click' | 'dblclick'; export interface
@@ -186,10 +186,8 @@ export default {
     const getPrefixCls = this.configProvider.getPrefixCls;
     const prefixCls = getPrefixCls('tree', customizePrefixCls);
     const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data;
-    warning(
-      !this.$listeners.doubleclick,
-      '`doubleclick` is deprecated. please use `dblclick` instead.',
-    );
+    const listeners = getListeners(this);
+    warning(!listeners.doubleclick, '`doubleclick` is deprecated. please use `dblclick` instead.');
     const treeProps = {
       props: {
         icon: getIcon,
@@ -201,7 +199,7 @@ export default {
       ref: 'tree',
       class: `${prefixCls}-directory`,
       on: {
-        ...omit(this.$listeners, ['update:selectedKeys']),
+        ...omit(listeners, ['update:selectedKeys']),
         select: this.onSelect,
         click: this.onClick,
         dblclick: this.onDoubleClick,
diff --git a/components/upload/Upload.jsx b/components/upload/Upload.jsx
index 22653341e..380c06b0c 100644
--- a/components/upload/Upload.jsx
+++ b/components/upload/Upload.jsx
@@ -3,7 +3,7 @@ import uniqBy from 'lodash/uniqBy';
 import findIndex from 'lodash/findIndex';
 import VcUpload from '../vc-upload';
 import BaseMixin from '../_util/BaseMixin';
-import { getOptionProps, initDefaultProps, hasProp } from '../_util/props-util';
+import { getOptionProps, initDefaultProps, hasProp, getListeners } from '../_util/props-util';
 import LocaleReceiver from '../locale-provider/LocaleReceiver';
 import defaultLocale from '../locale-provider/default';
 import { ConfigConsumerProps } from '../config-provider';
@@ -212,8 +212,9 @@ export default {
           remove: this.handleManualRemove,
         },
       };
-      if (this.$listeners.preview) {
-        uploadListProps.on.preview = this.$listeners.preview;
+      const listeners = getListeners(this);
+      if (listeners.preview) {
+        uploadListProps.on.preview = listeners.preview;
       }
       return <UploadList {...uploadListProps} />;
     },
diff --git a/components/vc-align/Align.jsx b/components/vc-align/Align.jsx
index 954da07e7..39fc58ea7 100644
--- a/components/vc-align/Align.jsx
+++ b/components/vc-align/Align.jsx
@@ -4,7 +4,7 @@ import addEventListener from '../_util/Dom/addEventListener';
 import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
 import { cloneElement } from '../_util/vnode.js';
 import clonedeep from 'lodash/cloneDeep';
-import { getSlot } from '../_util/props-util';
+import { getSlot, getListeners } from '../_util/props-util';
 
 function getElement(func) {
   if (typeof func !== 'function' || !func) return null;
@@ -117,7 +117,7 @@ export default {
       const { disabled, target, align } = this.$props;
       if (!disabled && target) {
         const source = this.$el;
-
+        const listeners = getListeners(this);
         let result;
         const element = getElement(target);
         const point = getPoint(target);
@@ -133,7 +133,7 @@ export default {
         }
         restoreFocus(activeElement, source);
         this.aligned = true;
-        this.$listeners.align && this.$listeners.align(source, result);
+        listeners.align && listeners.align(source, result);
       }
     },
   },
diff --git a/components/vc-tooltip/Tooltip.jsx b/components/vc-tooltip/Tooltip.jsx
index db061dd14..619bacf78 100644
--- a/components/vc-tooltip/Tooltip.jsx
+++ b/components/vc-tooltip/Tooltip.jsx
@@ -2,7 +2,7 @@ import PropTypes from '../_util/vue-types';
 import Trigger from '../vc-trigger';
 import { placements } from './placements';
 import Content from './Content';
-import { hasProp, getComponentFromProp, getOptionProps } from '../_util/props-util';
+import { hasProp, getComponentFromProp, getOptionProps, getListeners } from '../_util/props-util';
 function noop() {}
 export default {
   props: {
@@ -69,6 +69,7 @@ export default {
     if (hasProp(this, 'visible')) {
       extraProps.popupVisible = this.$props.visible;
     }
+    const listeners = getListeners(this);
     const triggerProps = {
       props: {
         popupClassName: overlayClassName,
@@ -89,9 +90,9 @@ export default {
         ...extraProps,
       },
       on: {
-        ...this.$listeners,
-        popupVisibleChange: this.$listeners.visibleChange || noop,
-        popupAlign: this.$listeners.popupAlign || noop,
+        ...listeners,
+        popupVisibleChange: listeners.visibleChange || noop,
+        popupAlign: listeners.popupAlign || noop,
       },
       ref: 'trigger',
     };
diff --git a/components/vc-trigger/Trigger.jsx b/components/vc-trigger/Trigger.jsx
index 12aa1e609..e8abd270d 100644
--- a/components/vc-trigger/Trigger.jsx
+++ b/components/vc-trigger/Trigger.jsx
@@ -2,7 +2,13 @@ import Vue from 'vue';
 import ref from 'vue-ref';
 import PropTypes from '../_util/vue-types';
 import contains from '../_util/Dom/contains';
-import { hasProp, getComponentFromProp, getEvents, filterEmpty } from '../_util/props-util';
+import {
+  hasProp,
+  getComponentFromProp,
+  getEvents,
+  filterEmpty,
+  getListeners,
+} from '../_util/props-util';
 import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
 import addEventListener from '../_util/Dom/addEventListener';
 import warning from '../_util/warning';
@@ -448,7 +454,8 @@ export default {
             sPopupVisible,
           });
         }
-        this.$listeners.popupVisibleChange && this.$listeners.popupVisibleChange(sPopupVisible);
+        const listeners = getListeners(this);
+        listeners.popupVisibleChange && listeners.popupVisibleChange(sPopupVisible);
       }
       // Always record the point position since mouseEnterDelay will delay the show
       if (sPopupVisible && alignPoint && event) {