项目场景:
之前在项目中使用到了ant-design的date-picker组件,需求是在日期框中为直播过的日期添加一些提醒。使用时候发现panelChange设置无效
翻看源码
1.在3.x的分支中可以看到generateSinglePicker这个组件是绑定了panelChange这个事件的
2.于是又去看了vc-picker组件,发现没有接受这个事件。
到这里其实就已经知道原因了,现在想的是如何解决。
1.升级库的版本(升级到最新的版本4.x),但是直接升级可能会出现不兼容的情况,引发新的bug。
2.直接修改lib下面的vc-picker(更不推荐),如果需要更新该库到新版本,你将无法直接使用包管理工具(如npm或yarn)进行更新,因为任何更新操作都可能会覆盖你的修改。
3.自己重新封装一个自定义的panelChange事件。
其实只有方法3最可行,正好MutationObserver这一新的webAPI可以满足这一需求。
Mutation Observer
Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。
概念上,它很接近事件,可以理解为 DOM 发生变动就会触发 Mutation Observer 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说,DOM 的变动立刻会触发相应的事件;Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。
Mutation Observer 有以下特点
- 它等待所有脚本任务完成后,才会运行(即异步触发方式)
- 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动
- 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。
解决方案:
直接利用MutationObserver来观察dom变动,然后执行响应的代码:
1.确定要观察的对象,我这里直接观察的是header,当左右筛选月份时去调响应的接口,拿到直播日期再做处理。
2.确定点击的是左边还是右边,点击的是年份还是月份。
我这里利用的将点击的数据存入数组,下次的点击的时候再作比较。
const observeDatePickerChanges = () => {
const datePicker = datePickerRef.value.$el;
const parentNode = datePicker.parentElement;
nextTick(() => {
const headerView = parentNode.querySelector('.ant-picker-header');
observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
//TODO:区分点击的是月份还是年份
const textContent: string = mutation.target.textContent!;
if (/^\d+月$/.test(textContent)) {
// 点击的是月份
const month = parseInt(textContent);
monthDateStack.value.push(month);
fetchActivities();
} else if (/^\d+年$/.test(textContent)) {
// 点击的是年份
const year = parseInt(textContent);
yearDateStack.value.push(year);
fetchActivities();
}
});
});
observer.observe(headerView, {
childList: true,
subtree: true,
characterData: true,
});
});
};
onBeforeUnmount(()=>{
yearDateStack.value = []; // 清空 yearDateStack 数组
monthDateStack.value = []; // 清空 monthDateStack 数组
})
const stopObservingDatePickerChanges = () => {
if (observer) {
observer.disconnect(); // 停止 MutationObserver 的监听
observer = null; // 释放 MutationObserver
}
};
const getLivesProducts = async (status: boolean) => {
// 触发自定义的openChange事件
if (status) {
observeDatePickerChanges();
fetchActivities();
} else {
emit('transfeTime', selectedDate.value)
stopObservingDatePickerChanges();
}
3.当然还有需要处理的是当直接选择月份和年份也要观察(不是左右箭头选择)。不过因为需求急,而且ant-design date-picker可以设置
mode=“date”,不让选择。