后端仔一枚,對前端不是特別熟,不足請諒解。
最近使用AntDesign時感覺message組件的出現動畫不是很明顯,僅有box-shadow做區分,並且動畫不是特別顯眼,於是打算為message的彈出動畫添加一個額外動畫
動畫效果使用 Animate.css
關於patch-package:允許創建並保留對 npm 依賴項的修復。食用方法在Github:
GitHub - ds300/patch-package: Fix broken node modules instantly 🏃🏽♀️💨
不想看過程的可以直接跳到底部看結論
💻環境
Vue版本:3.x
AntDesignVue版本:2.2.8
其他依賴包:
安裝 $ npminstall animate.css --save
安裝 $ npm install patch-package --save-dev
⏲過程
- 找到組件DOM
通過瀏覽器控制台找到Message組件生成的DOM
找到Message的容器,看到class-name為ant-message-notice-content明確節點后開始摳代碼
- 查看組件源碼-分析
先去到node_modules/ant-design-vue/es/message/index.js查看代碼
直接看到這個prefixCls,知道了這里的ant-message-notice-content是拼接出來的。
所以直接Ctrl+F搜索一下最末尾的-content
只找到了-custom-content,通過DOM可以看到這個class是容器內的,也就是包着圖標和文本的那一層,顯然這不是想要的
看到這個-custom-content是_createVNode創建(這里是通過as取的別名,就是vue中的createVNode,語法:createVNode(標簽, {屬性},內容))后return出去的,要找的應該是這個節點的上一層。
這里是通過getMessageInstance的instance的notice調的,先找到getMessageInstance方法的定義:
看到一個關鍵詞newInstance,顧名思義創建一個實例,並且第二個參數中調用了callback,也就是getMessageInstance調用時入參的function
找一下Notification在哪兒
看到這個是引用了message組件同級的vc-notification,繼續跟一下
index.js直接暴露的Notification,繼續跟,找到newInstance
可以看到165行到170行是找Message的掛載節點,稍加思考~嗯,這里就是整個Message組件的創建的地方了。
回到newInstance,定義了一個名為newNotificationInstance的函數,聲明兩個入參數,一個屬性,一個回調函數(論命名的重要性),屬性就不管了,主要看一下callback這個。
176到191行調用了callback,回頭再看一下這玩意兒(當時給我整暈了,都貼出來才清晰)
就是node_modules/ant-design-vue/es/message/index.js中的getMessageInstance。
有兩處,一處定義:
一處調用:
在調用的地方,這個回調函數的instance參數,就是Notification.js中newInstance中176到191行的入參,可以看到有個notice函數。
在圖1-7中,第181行代碼 self.$refs.notification.add(noticeProps) 添加了Message的消息元素。看到是通過notification的add添加的。在圖1-7中的194-199行代碼看到了notification
201行通過_createVNode創建的DOM,看到Notification作為整個參數被傳進去了,進去看一下

發現是引用的Notice.js,跟一下這個js
上半部分都看不懂,看到末尾發現在render函數中有幾個關鍵字 -notice
這個是Message渲染DOM的容器class,包括在下面的 -content
這個就是Message消息的外層。
這里嘗試改一下-content(就是這兒,我試過了),修改為: -content animate__animated animate__shakeX
然后執行生成一個補丁 npx patch-package ant-design-vue
應用 npx patch-package
重啟應用
再看一下DOM,添加成功
📑結論
- 設置 package.json
"script":{ + "postinstall":"patch-package" }
- 安裝依賴
npm install animate.css --save
npm install patch-package --save-dev
- 修改Notice.js源碼(+號)
render: function render() { var _className; var prefixCls = this.prefixCls, closable = this.closable, clearCloseTimer = this.clearCloseTimer, startCloseTimer = this.startCloseTimer, close = this.close, $attrs = this.$attrs; var componentClass = "".concat(prefixCls, "-notice"); var className = (_className = {}, _defineProperty(_className, "".concat(componentClass), 1), _defineProperty(_className, "".concat(componentClass, "-closable"), closable), _className); var closeIcon = getComponent(this, 'closeIcon'); return _createVNode("div", { "class": className, "style": $attrs.style || { right: '50%' }, "onMouseenter": clearCloseTimer, "onMouseleave": startCloseTimer }, [_createVNode("div", { + "class": "".concat(componentClass, "-content animate__animated animate__shakeX") }, [getSlot(this)]), closable ? _createVNode("a", { "tabindex": "0", "onClick": close, "class": "".concat(componentClass, "-close") }, [closeIcon || _createVNode("span", { "class": "".concat(componentClass, "-close-x") }, null)]) : null]); }
- 打補丁
npx patch-package ant-design-vue
npx patch-package
- 重啟APP-Over
🧰自定義AnimateClass
['success', 'info', 'warning', 'error', 'loading'].forEach(function (type) { //api[type] = function (content, duration, onClose) {
+ api[type] = function(content,duration,onClose,animateClass) if (isArgsProps(content)) { return api.open(_extends(_extends({}, content), { type: type })); } if (typeof duration === 'function') { onClose = duration; duration = undefined; } return api.open({ content: content, duration: duration, type: type, onClose: onClose,
+ animateClass:animateClass }); }; });
我們修改上述代碼,添加一個參數名為animateClass。這個api.open最終會執行getMessageInstance函數,將參數傳到Notification中。所以接着修改getMessageInstance調用時的參數,添加animateClass
api.open就是調用的notice方法,通過args將值取到。
然后到Notification.js修改defineComponent中的render的這段
var noticeNodes = notices.map(function (notice, index) { var update = Boolean(index === notices.length - 1 && notice.updateKey); var key = notice.updateKey ? notice.updateKey : notice.key; var content = notice.content, duration = notice.duration, closable = notice.closable, onClose = notice.onClose, style = notice.style, className = notice.class, + animateClass=notice.animateClass; var close = createChainedFunction(remove.bind(_this, notice.key), onClose); var noticeProps = { prefixCls: prefixCls, duration: duration, closable: closable, update: update, closeIcon: getComponent(_this, 'closeIcon'), onClose: close, onClick: notice.onClick || noop, style: style, class: className, key: key, + animateClass:animateClass }; return _createVNode(Notice, noticeProps, { default: function _default() { return [typeof content === 'function' ? content() : content]; } }); });
再到Notice.js中修改:
props: { duration: PropTypes.number.def(1.5), closable: PropTypes.looseBool, prefixCls: PropTypes.string, update: PropTypes.looseBool, closeIcon: PropTypes.any, onClose: PropTypes.func, + animateClass:"" }
render: function render() { var _className; var prefixCls = this.prefixCls, closable = this.closable, clearCloseTimer = this.clearCloseTimer, startCloseTimer = this.startCloseTimer, close = this.close, $attrs = this.$attrs, + animateClass = this.animateClass; var componentClass = "".concat(prefixCls, "-notice"); var className = (_className = {}, _defineProperty(_className, "".concat(componentClass), 1), _defineProperty(_className, "".concat(componentClass, "-closable"), closable), _className); var closeIcon = getComponent(this, 'closeIcon'); return _createVNode("div", { "class": className, "style": $attrs.style || { right: '50%' }, "onMouseenter": clearCloseTimer, "onMouseleave": startCloseTimer }, [_createVNode("div", { //"class": "".concat(componentClass, "-content")
+ "class":"".concat(componentClass,"-content animate__animated ").concat(animateClass) }, [getSlot(this)]), closable ? _createVNode("a", { "tabindex": "0", "onClick": close, "class": "".concat(componentClass, "-close") }, [closeIcon || _createVNode("span", { "class": "".concat(componentClass, "-close-x") }, null)]) : null]); }
然后生成補丁 npx patch-package ant-design-vue
應用補丁 npx patch-package
再調用message時就可以寫成這樣:
message.info({ content:'test', animateClass:'animate__rubberBand' })