Angular Material浮动标签文本截断:Ajax加载后Notch宽度计算异常排查
问题描述
我在用Angular Material组件,页面初始加载时输入框的浮动标签功能正常,但通过Ajax调用把HTML响应追加到指定div后,浮动标签对应的notch宽度计算异常。同时Ajax请求完成后控制台出现CORS错误,不确定是CORS导致(比如阻止CSS加载)还是DOM加载相关问题。
Textbox.TS
public intializeElements = (): void => { const textFields1 = [].map.call(document.querySelectorAll('.mdc-text-field'), function (el) { return new MDCTextField(el); }); const helperTexts1 = [].map.call(document.querySelectorAll('.mdc-text-field-helper-text'), function (el) { return new MDCTextFieldHelperText(el); }); this.initializeLabelPosition(); this.listenOnValidationAttributeChange(); this._jQueryValidationExtension.setupShowErrors(this.showErrorCallback); } private listenOnChromeAutoFillPrefill = (): void => { var outlinedTextbox = this; setInterval(function () { $('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input)').each(function () { var elem = $(this); if (elem.val() || elem.is(":-webkit-autofill")) { outlinedTextbox.floatLabelAbove(this); } }) }, 500); } public initializeLabelPosition = (): void => { var outlinedTextbox = this; $('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input)').each(function () { // 检查初始值和自动填充的预填充功能 const elem = $(this); if (!elem.val() && !elem.is(":-webkit-autofill")) return; outlinedTextbox.floatLabelAboveWithoutInputCheck(elem[0]); }); $('div.mdc-text-field-helper-line').hide(); } public listenOnValidationAttributeChange = (): void => { var _outlinedTextBox = this; $('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input)').attrchange(function (source, id, value) { if (source == "aria-invalid") { _outlinedTextBox._validationStatus.setValidationStatus(id, value, $(this)[0].name); } }); // 处理文本框失焦事件 $('label.mdc-text-field:not(.phone-otp-phone-number-field)').attrchange(function (source, id, value) { if (source == "class") { if (value.indexOf("mdc-text-field--focused") === -1) { _outlinedTextBox._validationStatus.setValidationStatus(id, _outlinedTextBox._validationStatus.isInvalid(id)); } } }); $('span.phone-otp-helper-text').attrchange(function (source, id, value) { if ($(this).hasClass("field-validation-error")) { $(this).removeClass("field-validation-error"); } }); } public floatLabelAboveWithoutInputCheck = (elem: HTMLElement): void => { var $label = $(elem).parent(); var $notchOutline = $label.children(".mdc-notched-outline"); var $notch = $notchOutline.children(".mdc-notched-outline__notch"); var $floatingLabel = $notchOutline.children(".mdc-notched-outline__notch").children(".mdc-floating-label"); if (!$floatingLabel.hasClass("mdc-floating-label--float-above")) $floatingLabel.addClass("mdc-floating-label--float-above"); if (!$label.hasClass("mdc-text-field--label-floating")) $label.addClass("mdc-text-field--label-floating"); if (!$notchOutline.hasClass("mdc-notched-outline--notched")) $notchOutline.addClass("mdc-notched-outline--notched"); var notchWidth = this.getFloatingLabelWidth($floatingLabel) / 1.3333 + 8; $notch.css("width", notchWidth.toString()); } private getFloatingLabelWidth = ($elem: JQuery<HTMLElement>): number => { var html_org = $elem.html(); var html_calc = '<span>' + html_org + '</span>'; $elem.html(html_calc); var width = $elem.find('span:first').width(); $elem.html(html_org); return width; };
Ajax 操作代码
getCaptcha= (userAction): any => { let self = this; let $form = this._form.$form; var clientQueryString = self.getClientQueryString(); this._httpClient.sendHttpRequestAsync( HttpMethod.Get, `getCaptcha?userAction=${userAction}&${clientQueryString}`, false, DataType.Text, ContentType.FormUrlEncoded, null, this.getCsrfInHeader($form) ).then(response => { var strResponse = response.toString(); if (strResponse.startsWith('{')) { var jsonResponse = JSON.parse(response.toString()); if (typeof jsonResponse?.data?.status === 'boolean' && !jsonResponse.data.status) { $form.find('.cpt-section').html(''); this._form.showError(jsonResponse?.data?.messages); } } else { $form.find('.cpt-section').html(strResponse); } }) .catch((err) => { console.error('Get Department: ', err); }); }
文本框响应HTML
<div class="clearfix captcha-container"> <label for="imageText_abba3833-398b-4703-94e6-a72bd48aed87" class="mdc-text-field text-field mdc-text-field--outlined phone-otp-label"> <input id="imageText_abba3833-398b-4703-94e6-a72bd48aed87" class="mdc-text-field__input" aria-labelledby="lblImage_abba3833-398b-4703-94e6-a72bd48aed87" aria-describedby="captchaHelperText_abba3833-398b-4703-94e6-a72bd48aed87" aria-controls="captchaHelperText_abba3833-398b-4703-94e6-a72bd48aed87" type="text" data-val="true" data-val-regex="输入的字符与图片不符,请输入图片中显示的字符以继续。" data-val-regex-pattern="^([a-zA-Z0-9]{5,7})$" data-val-required="请输入图片中显示的字符以继续。" name="ImageText" value="" /> <span class="mdc-notched-outline"> <span class="mdc-notched-outline__leading"></span> <span class="mdc-notched-outline__notch"> <span class="mdc-floating-label" id="lblImage_abba3833-398b-4703-94e6-a72bd48aed87">输入上方显示的文本</span> </span> <span class="mdc-notched-outline__trailing"></span> </span> </label> <div class="mdc-text-field-helper-line phone-otp-helper-line"> <span class="mdc-text-field-helper-text mdc-text-field-helper-text--validation-msg phone-otp-helper-text field-validation-valid" id="captchaHelperText_abba3833-398b-4703-94e6-a72bd48aed87" aria-hidden="true" data-valmsg-for="ImageText" data-valmsg-replace="true"></span> </div>
显示效果
- 加载完成后文本框状态:

- 聚焦文本框时状态:

解决方案
1. 排除CORS影响
CORS错误仅限制跨域数据交互,不会影响CSS加载,当前notch宽度异常和CORS无关,可忽略该错误对本问题的影响。
2. 修复动态DOM初始化问题
Ajax加载的新DOM元素未执行MDCTextField初始化逻辑,这是核心问题:
- 修改
intializeElements方法,支持指定目标容器,避免重复初始化旧元素:
public intializeElements = (target?: JQuery): void => { const container = target || $(document); // 初始化目标容器内的MDCTextField组件 const textFields1 = [].map.call(container.find('.mdc-text-field').get(), function (el) { return new MDCTextField(el); }); const helperTexts1 = [].map.call(container.find('.mdc-text-field-helper-text').get(), function (el) { return new MDCTextFieldHelperText(el); }); // 初始化标签位置 if (target) { target.find('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input)').each(function () { const elem = $(this); if (!elem.val() && !elem.is(":-webkit-autofill")) return; this.floatLabelAboveWithoutInputCheck(elem[0]); }); target.find('div.mdc-text-field-helper-line').hide(); } else { this.initializeLabelPosition(); } this.listenOnValidationAttributeChange(); this._jQueryValidationExtension.setupShowErrors(this.showErrorCallback); }
- 在Ajax回调中插入HTML后,调用初始化方法:
// 原代码中$form.find('.cpt-section').html(strResponse);之后添加: const $cptSection = $form.find('.cpt-section'); $cptSection.html(strResponse); this.intializeElements($cptSection);
3. 修正宽度计算时机
临时span的宽度计算可能因DOM未完全渲染出错,改用requestAnimationFrame确保元素渲染后再计算:
public floatLabelAboveWithoutInputCheck = (elem: HTMLElement): void => { var $label = $(elem).parent(); var $notchOutline = $label.children(".mdc-notched-outline"); var $notch = $notchOutline.children(".mdc-notched-outline__notch"); var $floatingLabel = $notchOutline.children(".mdc-notched-outline__notch").children(".mdc-floating-label"); if (!$floatingLabel.hasClass("mdc-floating-label--float-above")) $floatingLabel.addClass("mdc-floating-label--float-above"); if (!$label.hasClass("mdc-text-field--label-floating")) $label.addClass("mdc-text-field--label-floating"); if (!$notchOutline.hasClass("mdc-notched-outline--notched")) $notchOutline.addClass("mdc-notched-outline--notched"); // 等待DOM渲染完成后计算宽度 requestAnimationFrame(() => { var notchWidth = this.getFloatingLabelWidth($floatingLabel) / 1.3333 + 8; $notch.css("width", notchWidth.toString()); }); }
4. 修正选择器语法错误
原listenOnChromeAutoFillPrefill方法中选择器缺少闭合括号,已在上方代码中修正:
// 修正前: $('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input') // 修正后: $('input.mdc-text-field__input:not(.phone-otp-phone-number-field__input)')
内容的提问来源于stack exchange,提问作者ramkee gurrala
相关产品推荐
相关产品推荐

