bug描述
项目需求,我们用的antd3.26.15。 用到Mentions组件的时候,value我们使用的是名字 (name) 字段,这时候就会出现 重名 情况。当我需要 @ 某人的时候,我模糊搜索的时候,再次搜索名称就会一直出现。如图。第一个名字不应该出现,这个名字也是 重名 的名称。
思路
排查问题之后知道是option里面的value
太片面了(value又是选择是填充的值,这个值又不能重复)
,OnSelect
里面的参数就是这个value
又不能改,于是我们又加了个字段actualValue
。加了个字段那肯定就是要去看源码
了。看看怎么改源码
。(这个还是前辈做出来的,我顺着他的思路理了一遍,哈哈哈,白嫖思路)
首先想到的肯定去看antd的源码。看了源码其实也狠模糊从何做起。说说我个人的思考路线,首先思路
里面提到加了个actualValue
,那我们需要看Option
里面是什么东西,这时候就能定位到getOption
,看到就返回了children
。意思就是返回了全部东西了。
这里看到了RcMentions
组件,看到了咱们用的是rc-mentions
。咱们又去github上找。继续思路,上面咱们提到children
,所以我们直接在这里索引children
,发现好像也就是整理了一下(这里我理解其实就是我们能传递actualName的关键)
。这个时候我又想到了OnSelect
方法,那就又索引
这个方法呗。其实这个时候我们就能定位到关键方法selectOption
了,一些解释放在代码注释里面了。
import RcMentions from 'rc-mentions';
public selectOption = (option: OptionProps) => {
const { value, measureLocation, measurePrefix } = this.state;
const { split, onSelect } = this.props;
// 这里就是我们传过去的value,那么是不是可以在这里加actualName
const { value: mentionValue = '' } = option;
// const { value: mentionValue = '', actualValue } = option;
const { text, selectionLocation } = replaceWithMeasure(value, {
measureLocation,
targetText: mentionValue, // 这里就是复制,那么我们也可以把actualvalue赋值给他
// targetText: actualValue ?? mentionValue,
prefix: measurePrefix,
selectionStart: this.textarea!.selectionStart,
split: split!,
});
this.triggerChange(text);
this.stopMeasure(() => {
// We need restore the selection position
setInputSelection(this.textarea!, selectionLocation);
});
// 这里又把我们的option传递回去了,就是Onselct的参数
if (onSelect) {
onSelect(option, measurePrefix);
}
};
于是乎
问题就解决了我们写一个MyMention
组件继承Mention
组件,MyRcMention
继承RcMention
就可以了。
// MyMention
import classNames from 'classnames';
import { Mentions } from "antd";
import MyRCMentions from "./MyRCMentions";
import omit from 'omit.js';
export default class MyMentions extends Mentions {
constructor(props) {
super(props);
}
renderMentions = ({ getPrefixCls, renderEmpty }) => {
const { focused } = this.state;
const { prefixCls: customizePrefixCls, className, disabled, ...restProps } = this.props;
const prefixCls = getPrefixCls('mentions', customizePrefixCls);
const mentionsProps = omit(restProps, ['loading']);
const mergedClassName = classNames(className, {
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-focused`]: focused,
});
return (
<MyRCMentions
prefixCls={prefixCls}
notFoundContent={this.getNotFoundContent(renderEmpty)}
className={mergedClassName}
disabled={disabled}
{...mentionsProps}
filterOption={this.getFilterOption()}
onFocus={this.onFocus}
onBlur={this.onBlur}
ref={this.saveMentions}
>
{this.getOptions()}
</MyRCMentions>
);
};
render() {
return super.render();
}
}
// MyRcMention
import RcMentions from 'rc-mentions';
import { replaceWithMeasure, setInputSelection } from 'rc-mentions/lib/util';
export default class MyRCMentions extends RcMentions {
constructor(props) {
super(props);
}
selectOption = (option) => {
const { value, measureLocation, measurePrefix } = this.state;
const { split, onSelect } = this.props;
const { value: mentionValue = '', actualValue } = option;
const { text, selectionLocation } = replaceWithMeasure(value, {
measureLocation,
targetText: actualValue ?? mentionValue,
prefix: measurePrefix,
selectionStart: this.textarea.selectionStart,
split: split,
});
this.triggerChange(text);
this.stopMeasure(() => {
// We need restore the selection position
setInputSelection(this.textarea, selectionLocation);
});
if (onSelect) {
onSelect(option, measurePrefix);
}
};
render() {
return super.render()
}
}
最后
看似很简单,其实我们做了好久,刚开始我都没往源码这方面想,请教了前辈,他跟我一起解决这个bug,才做出来了。学到了很多。这个问题感觉应该很小众了,antd都更新了那么多版本了,应该是解决了。发出来也只是让我自己有一个思路,如果真有解决不了的bug,看看源码,从源码入手,想想能不能解决。
还有就是我其实是写Vue的,如果源码解释的有问题,可以帮忙提出来,谢谢大哥们