ant design vue message 支持可手动关闭

文章讲述了如何在vue2项目中,针对ant-design-vue的Message组件增加手动关闭功能。作者通过分析源码,发现Message缺少关闭图标和可关闭属性,于是复制源码创建了一个myMessage.js文件,添加了关闭图标和可关闭属性,并提供了具体修改后的代码示例。最后,文章提到了实现该功能所需的CSS调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 项目:

vue2 + ant-design-vue1.7.8

需求:

message组件添加可手动关闭功能,效果如下:

85578769dd8e48d8aee7c9dbd73143f6.png

当前message效果:

c957c736d2b342bfb2655d857913d832.png

源码分析:

通过ant design vue源码,了解到Message和Notification底层是同一个组件vc-notification,根据不同配置,实现不同样式和功能。

Nitification组件中有可手动关闭的图标,Message组件中可手动关闭的图标被阉割了。

Nitification源码:

ant-design-vue/es/notification/index.js

d91bafb81c644dde87c8335a2fd4c1ef.png

522e337837a945cb837ace19afa4ab17.png

Message源码:

ant-design-vue/es/message/index.js

5740c90e29d141058ef2c7b752cbab71.png

 be5211047c3843c480466c01b5f317c4.png

 Message源码中没有关闭图标和是否可关闭的属性。

方案:

项目中添加一个myMessage.js文件,抄一份message源码,添加上关闭图标和是否可关闭属性

修改后代码如下:

import _extends from 'babel-runtime/helpers/extends';
import Notification from 'ant-design-vue/es/vc-notification';
import Icon from 'ant-design-vue/es/icon';

var defaultDuration = 3;
var defaultTop = void 0;
var messageInstance = void 0;
var key = 1;
var prefixCls = 'ant-message';
var transitionName = 'move-up';
var getContainer = function getContainer() {
  return document.body;
};
var maxCount = void 0;

function getMessageInstance(callback) {
  if (messageInstance) {
    callback(messageInstance);
    return;
  }
  Notification.newInstance({
    prefixCls: prefixCls,
    transitionName: transitionName,
    // 覆盖原来的样式
    style: {
      top: defaultTop
    },
    getContainer: getContainer,
    maxCount: maxCount,
    // 添加关闭图标
    closeIcon: function closeIcon(h) {
      var closeIconToRender = h(
        'span', {
          'class': prefixCls + '-close-x'
        },
        [h(Icon, {
          'class': prefixCls + '-close-icon',
          attrs: {
            type: 'close'
          }
        })]
      );
      return closeIconToRender;
    }
  }, function (instance) {
    if (messageInstance) {
      callback(messageInstance);
      return;
    }
    messageInstance = instance;
    callback(instance);
  });
}

// type NoticeType = 'info' | 'success' | 'error' | 'warning' | 'loading';

function notice(args) {
  var duration = args.duration !== undefined ? args.duration : defaultDuration;
  var iconType = {
    info: 'info-circle',
    success: 'check-circle',
    error: 'close-circle',
    warning: 'exclamation-circle',
    loading: 'loading'
  } [args.type];

  var target = args.key || key++;
  var closePromise = new Promise(function (resolve) {
    var callback = function callback() {
      if (typeof args.onClose === 'function') {
        args.onClose();
      }
      return resolve(true);
    };
    getMessageInstance(function (instance) {
      instance.notice({
        key: target,
        // 添加是否可关闭属性
        closable: true,
        duration: duration,
        style: {},
        content: function content(h) {
          var iconNode = h(Icon, {
            attrs: {
              type: iconType,
              theme: iconType === 'loading' ? 'outlined' : 'filled'
            }
          });
          var switchIconNode = iconType ? iconNode : '';
          return h(
            'div', {
              'class': prefixCls + '-custom-content' + (args.type ? ' ' + prefixCls + '-' + args.type : '')
            },
            [args.icon ? typeof args.icon === 'function' ? args.icon(h) : args.icon : switchIconNode, h('span', [typeof args.content === 'function' ? args.content(h) : args.content])]
          );
        },
        onClose: callback
      });
    });
  });
  var result = function result() {
    if (messageInstance) {
      messageInstance.removeNotice(target);
    }
  };
  result.then = function (filled, rejected) {
    return closePromise.then(filled, rejected);
  };
  result.promise = closePromise;
  return result;
}

// type ConfigContent = React.ReactNode | string;
// type ConfigDuration = number | (() => void);
// export type ConfigOnClose = () => void;

function isArgsProps(content) {
  return Object.prototype.toString.call(content) === '[object Object]' && !!content.content;
}

// export interface ConfigOptions {
//   top?: number;
//   duration?: number;
//   prefixCls?: string;
//   getContainer?: () => HTMLElement;
//   transitionName?: string;
// }

var api = {
  open: notice,
  config: function config(options) {
    if (options.top !== undefined) {
      defaultTop = options.top;
      // delete messageInstance for new defaultTop
      messageInstance = null;
    }
    if (options.duration !== undefined) {
      defaultDuration = options.duration;
    }
    if (options.prefixCls !== undefined) {
      prefixCls = options.prefixCls;
    }
    if (options.getContainer !== undefined) {
      getContainer = options.getContainer;
    }
    if (options.transitionName !== undefined) {
      transitionName = options.transitionName;
      // delete messageInstance for new transitionName
      messageInstance = null; 
    }
    if (options.maxCount !== undefined) {
      maxCount = options.maxCount;
      messageInstance = null;
    }
  },
  destroy: function destroy() {
    if (messageInstance) {
      messageInstance.destroy();
      messageInstance = null;
    }
  }
};

['success', 'info', 'warning', 'error', 'loading'].forEach(function (type) {
  api[type] = function (content, duration, onClose) {
    if (isArgsProps(content)) {
      return api.open(_extends({}, content, {
        type: type
      }));
    }
    if (typeof duration === 'function') {
      onClose = duration;
      duration = undefined;
    }
    return api.open({
      content: content,
      duration: duration,
      type: type,
      onClose: onClose
    });
  };
});

api.warn = api.warning;

export default api;

组件中引入及使用:

<template>
  <div>
    <a-button @click="openMessage">Message</a-button>
    <a-button @click="openNotification">Notification</a-button>
  </div>
</template>
<script>
import myMessage from "@/views/component/myMessage";
export default {
  data() {
    return {};
  },
  methods: {
    openMessage() {
      myMessage.info({ duration: 3, content: "这是一条info提示" });
      myMessage.success({ duration: 3, content: "这是一条success提示" });
      myMessage.error({ duration: 3, content: "这是一条error提示" });
      myMessage.warning({ duration: 3, content: "这是一条warning提示" });
      myMessage.warn({
        duration: 3,
        content:
          "这是一条warn提示 This is the content of the notification. This is the content of the notification. This is the content of the notification."
      });
    },
    openNotification() {
      this.$notification.success({
        duration: 10000,
        message: "Notification Title",
        description:
          "This is the content of the notification. This is the content of the notification. This is the content of the notification.",
        onClick: () => {
          console.log("Notification Clicked!");
        }
      });
    }
  }
};
</script>

全局引入的,可做如下配置:

import myMessage from "@/views/component/myMessage";
Vue.prototype.$message = myMessage;

实现效果如下:

543050bed62e443398d95bc4d48730a6.png

这时关闭图标是不能点击的,

需要在全局样式中添加

.ant-message-notice-close {
    pointer-events: all;
}

这样关闭图标就可以正常使用了。

样式再稍加调整,就可以实现如下效果了。

 

8881f40b2c1a440788e778a0fe9a6e6a.png

 

5e33c80b96ad422fa60c3cd1c77d9139.png

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值