1
This commit is contained in:
parent
5851c98537
commit
3140456ee0
@ -144,6 +144,20 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
highlightElement.style.overflowWrap = inputStyles.overflowWrap;
|
||||
highlightElement.style.verticalAlign = inputStyles.verticalAlign;
|
||||
highlightElement.style.boxSizing = inputStyles.boxSizing;
|
||||
|
||||
// 关键:同步文本对齐属性,确保光标位置准确
|
||||
highlightElement.style.textAlign = inputStyles.textAlign;
|
||||
highlightElement.style.direction = inputStyles.direction;
|
||||
highlightElement.style.textIndent = inputStyles.textIndent;
|
||||
|
||||
// 调试信息(仅开发环境)
|
||||
if (process.env.NODE_ENV === 'development' && variant === 'textarea') {
|
||||
console.log('[VariableInput] 样式同步:', {
|
||||
fontSize: inputStyles.fontSize,
|
||||
lineHeight: inputStyles.lineHeight,
|
||||
padding: `${inputStyles.paddingTop} ${inputStyles.paddingRight} ${inputStyles.paddingBottom} ${inputStyles.paddingLeft}`,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 同步滚动位置(仅 textarea)
|
||||
@ -154,14 +168,28 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
highlightElement.scrollLeft = inputElement.scrollLeft;
|
||||
};
|
||||
|
||||
// 初始同步(延迟执行,确保 DOM 完全渲染)
|
||||
// 初始同步(多次延迟确保 DOM 完全渲染,包括 Modal/Sheet 的样式应用)
|
||||
syncStyles();
|
||||
setTimeout(syncStyles, 0);
|
||||
setTimeout(syncStyles, 10);
|
||||
setTimeout(syncStyles, 50);
|
||||
setTimeout(syncStyles, 100);
|
||||
|
||||
// 监听窗口大小变化(可能影响字体大小)
|
||||
const resizeObserver = new ResizeObserver(syncStyles);
|
||||
resizeObserver.observe(inputElement);
|
||||
|
||||
// 监听父元素属性变化(例如 Modal/Sheet 的显示状态)
|
||||
const mutationObserver = new MutationObserver(syncStyles);
|
||||
let parent = inputElement.parentElement;
|
||||
while (parent && parent !== document.body) {
|
||||
mutationObserver.observe(parent, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class', 'style'],
|
||||
});
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
// 监听滚动事件(仅 textarea)
|
||||
if (variant === 'textarea') {
|
||||
inputElement.addEventListener('scroll', syncScroll);
|
||||
@ -169,6 +197,7 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
mutationObserver.disconnect();
|
||||
if (variant === 'textarea') {
|
||||
inputElement.removeEventListener('scroll', syncScroll);
|
||||
}
|
||||
@ -178,6 +207,40 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [variant]);
|
||||
|
||||
// 当 value 变化时,确保样式同步(特别是首次输入时)
|
||||
useEffect(() => {
|
||||
if (!inputRef.current || !highlightRef.current || !value) return;
|
||||
|
||||
const syncCriticalStyles = () => {
|
||||
const inputElement = inputRef.current;
|
||||
const highlightContainer = highlightRef.current;
|
||||
if (!inputElement || !highlightContainer) return;
|
||||
|
||||
const inputStyles = window.getComputedStyle(inputElement);
|
||||
|
||||
// 同步关键样式
|
||||
highlightContainer.style.paddingTop = inputStyles.paddingTop;
|
||||
highlightContainer.style.paddingBottom = inputStyles.paddingBottom;
|
||||
highlightContainer.style.paddingLeft = inputStyles.paddingLeft;
|
||||
highlightContainer.style.paddingRight = inputStyles.paddingRight;
|
||||
highlightContainer.style.lineHeight = inputStyles.lineHeight;
|
||||
highlightContainer.style.fontSize = inputStyles.fontSize;
|
||||
highlightContainer.style.fontFamily = inputStyles.fontFamily;
|
||||
};
|
||||
|
||||
// 多次延迟确保样式完全应用
|
||||
syncCriticalStyles();
|
||||
const timer1 = setTimeout(syncCriticalStyles, 0);
|
||||
const timer2 = setTimeout(syncCriticalStyles, 10);
|
||||
const timer3 = setTimeout(syncCriticalStyles, 50);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer1);
|
||||
clearTimeout(timer2);
|
||||
clearTimeout(timer3);
|
||||
};
|
||||
}, [value]);
|
||||
|
||||
// 监听滚动和窗口大小变化,更新下拉框位置
|
||||
useEffect(() => {
|
||||
if (!showSuggestions) return;
|
||||
@ -452,9 +515,14 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
alignItems: variant === 'input' ? 'center' : 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: '100%', flex: variant === 'input' ? 'none' : undefined }}>
|
||||
{/* Input 需要包装 div 避免 flex 影响文字,Textarea 直接渲染 */}
|
||||
{variant === 'input' ? (
|
||||
<div style={{ width: '100%' }}>
|
||||
<HighlightLayer value={value} />
|
||||
</div>
|
||||
) : (
|
||||
<HighlightLayer value={value} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user