Skip to content

Commit 482beff

Browse files
committed
fix: multiple trigger support in comment component at any position 🦊
1 parent 231b8b3 commit 482beff

File tree

2 files changed

+289
-216
lines changed

2 files changed

+289
-216
lines changed

packages/devui-vue/devui/mention/src/mention.tsx

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,46 @@ export default defineComponent({
2020
const showSuggestions = ref<boolean>(false);
2121
const currentIndex = ref<number>(0);
2222
const suggestionsTop = ref<number>();
23+
const suggestionsLeft = ref<number>();
2324
const suggestions = ref<IMentionSuggestionItem[]>([]);
2425
const filteredSuggestions = ref<IMentionSuggestionItem[]>([]);
2526
const suggestionsDom = ref<HTMLDivElement>();
2627
const loading = computed(() => props.loading);
2728
const instance = getCurrentInstance();
2829

30+
const checkShouldShowSuggestions = (word: string) => {
31+
if (word && props.trigger.includes(word[0])) {
32+
// 需要以空格作为分割,单词尾部的 trigger 符号不生效
33+
return word.length === 1 || !props.trigger.includes(word[word.length - 1]);
34+
} else {
35+
return false;
36+
}
37+
};
38+
2939
const handleUpdate = debounce((val: string) => {
30-
if (props.trigger.includes(val[0])) {
40+
const wordsWithoutSpace = val.split(' ');
41+
const lastWordIndex = wordsWithoutSpace.length - 1;
42+
const lastWord = wordsWithoutSpace[lastWordIndex];
43+
const shouldBeActive = checkShouldShowSuggestions(lastWord);
44+
if (shouldBeActive) {
3145
showSuggestions.value = true;
3246
if (props.position === 'top') {
3347
setTimeout(() => {
34-
const height = window.getComputedStyle(suggestionsDom.value as Element, null).height;
48+
const element = window.getComputedStyle(suggestionsDom.value as Element, null);
49+
const { height, width } = element;
3550
suggestionsTop.value = -Number(height.replace('px', ''));
51+
suggestionsLeft.value = Number(width.replace('px', ''));
3652
}, 0);
3753
}
3854
filteredSuggestions.value = (suggestions.value as IMentionSuggestionItem[]).filter((item: IMentionSuggestionItem) =>
3955
String(item[props.dmValueParse.value as keyof IMentionSuggestionItem])
4056
.toLocaleLowerCase()
41-
.includes(val.slice(1).toLocaleLowerCase())
57+
.includes(lastWord.slice(1).toLocaleLowerCase())
4258
);
4359
} else {
4460
showSuggestions.value = false;
4561
}
46-
emit('change', val.slice(1));
62+
emit('change', lastWord.slice(1));
4763
}, 300);
4864

4965
const handleBlur = (e: Event) => {
@@ -67,7 +83,12 @@ export default defineComponent({
6783
e.stopPropagation();
6884
e.preventDefault();
6985
showSuggestions.value = false;
70-
textContext.value = textContext.value.substring(0, 1) + item[props.dmValueParse.value as keyof IMentionSuggestionItem];
86+
const wordsWithoutSpace = textContext.value.split(' ');
87+
const lastWordIndex = wordsWithoutSpace.length - 1;
88+
const lastWord = wordsWithoutSpace[lastWordIndex];
89+
const selectedWord = item[props.dmValueParse.value as keyof IMentionSuggestionItem];
90+
wordsWithoutSpace[lastWordIndex] = `${lastWord[0]}${selectedWord}`;
91+
textContext.value = wordsWithoutSpace.join(' ');
7192
};
7293

7394
const arrowKeyDown = (e: KeyboardEvent) => {
@@ -102,9 +123,12 @@ export default defineComponent({
102123
e.stopPropagation();
103124
e.preventDefault();
104125
showSuggestions.value = false;
105-
textContext.value =
106-
textContext.value.substring(0, 1) +
107-
filteredSuggestions.value[currentIndex.value][props.dmValueParse.value as keyof IMentionSuggestionItem];
126+
const wordsWithoutSpace = textContext.value.split(' ');
127+
const lastWordIndex = wordsWithoutSpace.length - 1;
128+
const lastWord = wordsWithoutSpace[lastWordIndex];
129+
const selectedWord = filteredSuggestions.value[currentIndex.value][props.dmValueParse.value as keyof IMentionSuggestionItem];
130+
wordsWithoutSpace[lastWordIndex] = `${lastWord[0]}${selectedWord}`;
131+
textContext.value = wordsWithoutSpace.join(' ');
108132
emit('select', filteredSuggestions.value[currentIndex.value]);
109133
}
110134
}
@@ -149,6 +173,7 @@ export default defineComponent({
149173
style={{
150174
marginTop: props.position === 'top' ? '0px' : '-16px',
151175
top: suggestionsTop.value ? suggestionsTop.value + 'px' : 'inherit',
176+
left: suggestionsLeft.value ? suggestionsLeft.value + 'px' : 'inherit',
152177
}}>
153178
{filteredSuggestions.value.length > 0 ? (
154179
filteredSuggestions.value?.map((item, index) => {

0 commit comments

Comments
 (0)