React:突出显示两个索引之间的文本
React: Highlight text between two indexes
因此,对于每个预测,google 放置自动完成 API 也 returns 为每个预测匹配子字符串。
输入:散68
预测:旧金山 68
匹配的子字符串:[{ offset: 0, length: 3 }, { offset: 15, length: 2 }]
预期:San Francisco 68
我的目标是使用匹配的子字符串突出显示部分预测。现在有一些挑战。我可以使用 replace
函数并将每个子字符串替换为 <b>str</b>
,但它 returns 是一个字符串,这意味着除非我使用 dangerouslySetInnerHTML
,否则此方法不起作用。
我也不认为有办法替换多个子字符串。我尝试使用 reduce
函数,但在第一个循环之后它不会真正起作用,因为索引是错误的。
const highlight = (text, matched_substrings) => {
return matched_substrings.reduce((acc, cur) => {
return acc.replace(
acc.substring(cur.offset, cur.length),
(str) => `<b>${str}</b>`
)
}, text)
}
那么有办法做到这一点吗?我认为 React 使这更复杂。
可能不是最佳解决方案,但绝对可行:)
先决条件是,matched_substrigs 数组必须按偏移量
排序
export const highlightText = (text, matched_substring, start, end) => {
const highlightTextStart = matched_substring.offset;
const highlightTextEnd = highlightTextStart + matched_substring.length;
// The part before matched text
const beforeText = text.slice(start, highlightTextStart);
// Matched text
const highlightedText = text.slice(highlightTextStart, highlightTextEnd);
// Part after matched text
// Till the end of text, or till next matched text
const afterText = text.slice(highlightTextEnd, end || text.length);
// Return in array of JSX elements
return [beforeText, <strong>{highlightedText}</strong>, afterText];
};
export const highlight = (text, matched_substrings) => {
const returnText = [];
// Just iterate through all matches
for (let i = 0; i < matched_substrings.length; i++) {
const startOfNext = matched_substrings[i + 1]?.offset;
if (i === 0) { // If its first match, we start from first character => start at index 0
returnText.push(highlightText(text, matched_substrings[i], 0, startOfNext))
} else { // If its not first match, we start from match.offset
returnText.push(highlightText(text, matched_substrings[i], matched_substrings[i].offset, startOfNext))
}
}
return returnText.map((text, i) => <React.Fragment key={i}>{text}</React.Fragment>)
};
如果您不介意使用 dangerouslySetInnerHTML
,这里有一个解决方案
const Highlight = ({ text, substrings }) => {
const html = substrings.reduce((acc, cur, idx) => {
return acc.replace(
new RegExp(
'(?<=^.{' + (cur.offset + idx * 17) + '})(.{' + cur.length + '})',
),
(str) => `<strong>${str}</strong>`,
)
}, text)
return <span dangerouslySetInnerHTML={{ __html: html }} />
}
这样使用
<Highlight text={...} substrings={...} />
因此,对于每个预测,google 放置自动完成 API 也 returns 为每个预测匹配子字符串。
输入:散68
预测:旧金山 68
匹配的子字符串:[{ offset: 0, length: 3 }, { offset: 15, length: 2 }]
预期:San Francisco 68
我的目标是使用匹配的子字符串突出显示部分预测。现在有一些挑战。我可以使用 replace
函数并将每个子字符串替换为 <b>str</b>
,但它 returns 是一个字符串,这意味着除非我使用 dangerouslySetInnerHTML
,否则此方法不起作用。
我也不认为有办法替换多个子字符串。我尝试使用 reduce
函数,但在第一个循环之后它不会真正起作用,因为索引是错误的。
const highlight = (text, matched_substrings) => {
return matched_substrings.reduce((acc, cur) => {
return acc.replace(
acc.substring(cur.offset, cur.length),
(str) => `<b>${str}</b>`
)
}, text)
}
那么有办法做到这一点吗?我认为 React 使这更复杂。
可能不是最佳解决方案,但绝对可行:) 先决条件是,matched_substrigs 数组必须按偏移量
排序export const highlightText = (text, matched_substring, start, end) => {
const highlightTextStart = matched_substring.offset;
const highlightTextEnd = highlightTextStart + matched_substring.length;
// The part before matched text
const beforeText = text.slice(start, highlightTextStart);
// Matched text
const highlightedText = text.slice(highlightTextStart, highlightTextEnd);
// Part after matched text
// Till the end of text, or till next matched text
const afterText = text.slice(highlightTextEnd, end || text.length);
// Return in array of JSX elements
return [beforeText, <strong>{highlightedText}</strong>, afterText];
};
export const highlight = (text, matched_substrings) => {
const returnText = [];
// Just iterate through all matches
for (let i = 0; i < matched_substrings.length; i++) {
const startOfNext = matched_substrings[i + 1]?.offset;
if (i === 0) { // If its first match, we start from first character => start at index 0
returnText.push(highlightText(text, matched_substrings[i], 0, startOfNext))
} else { // If its not first match, we start from match.offset
returnText.push(highlightText(text, matched_substrings[i], matched_substrings[i].offset, startOfNext))
}
}
return returnText.map((text, i) => <React.Fragment key={i}>{text}</React.Fragment>)
};
如果您不介意使用 dangerouslySetInnerHTML
const Highlight = ({ text, substrings }) => {
const html = substrings.reduce((acc, cur, idx) => {
return acc.replace(
new RegExp(
'(?<=^.{' + (cur.offset + idx * 17) + '})(.{' + cur.length + '})',
),
(str) => `<strong>${str}</strong>`,
)
}, text)
return <span dangerouslySetInnerHTML={{ __html: html }} />
}
这样使用
<Highlight text={...} substrings={...} />