From de6a76e91b70182491ea2f6a6081e8f2c940a041 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Fri, 31 Jul 2026 11:10:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(form):=20=E7=BB=9F=E4=B8=80=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=BB=84=E4=BB=B6=E6=A0=B7=E5=BC=8F=E5=B9=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增标签字重、自动宽度上限、输入框边框/背景色等配置项 2. 统一ns-form、ns-newform和diy-form的输入框样式与默认值 3. 优化标签宽度计算逻辑,添加自动宽度上限防止布局溢出 4. 适配多端输入框样式,添加聚焦态交互效果 --- components-diy/diy-form.vue | 7 ++ components/ns-form/ns-form.vue | 57 ++++++++++++- components/ns-newform/ns-newform.vue | 121 ++++++++++++++++++++++----- 3 files changed, 161 insertions(+), 24 deletions(-) diff --git a/components-diy/diy-form.vue b/components-diy/diy-form.vue index ce66edd..985ba59 100644 --- a/components-diy/diy-form.vue +++ b/components-diy/diy-form.vue @@ -187,11 +187,18 @@ export default { labelFixedWidth: pick('labelFixedWidth', 'label_fixed_width'), labelFontSize: pick('labelFontSize', 'label_font_size'), labelColor: pick('labelColor', 'label_color'), + labelFontWeight: pick('labelFontWeight', 'label_font_weight'), + labelAutoMaxWidth: pick('labelAutoMaxWidth', 'label_auto_max_width'), requiredColor: pick('requiredColor', 'required_color'), checkedColor: pick('checkedColor', 'checked_color'), // 占位符:遗漏会被 ns-newform SCSS 默认值回退覆盖 placeholderColor: pick('placeholderColor', 'placeholder_color'), placeholderFontSize: pick('placeholderFontSize', 'placeholder_font_size'), + // 输入框视觉增强(与 ns-newform 对齐) + inputBorderColor: pick('inputBorderColor', 'input_border_color'), + inputBgColor: pick('inputBgColor', 'input_bg_color'), + inputFocusBorderColor: pick('inputFocusBorderColor', 'input_focus_border_color'), + inputFocusBgColor: pick('inputFocusBgColor', 'input_focus_bg_color'), submitText: pick('submitText', 'submit_text'), submitColor: pick('submitColor', 'submit_color'), submitBgColor: pick('submitBgColor', 'submit_bg_color'), diff --git a/components/ns-form/ns-form.vue b/components/ns-form/ns-form.vue index 63e950a..a70dd65 100644 --- a/components/ns-form/ns-form.vue +++ b/components/ns-form/ns-form.vue @@ -281,10 +281,17 @@ labelFixedWidth: 180, labelFontSize: 28, labelColor: '#1f2937', + labelFontWeight: 600, + labelAutoMaxWidth: 200, requiredColor: '#ef4444', checkedColor: '#ff4544', placeholderColor: '#909399', placeholderFontSize: 28, + // 输入框视觉增强(与 ns-newform 对齐) + inputBorderColor: '#e5e7eb', + inputBgColor: '#f9fafb', + inputFocusBorderColor: '#ff4544', + inputFocusBgColor: '#ffffff', showRowDivider: true, rowDividerColor: '#f0f0f0' }; @@ -308,10 +315,15 @@ labelFixedWidth: pick('labelFixedWidth', 'label_fixed_width'), labelFontSize: pick('labelFontSize', 'label_font_size'), labelColor: pick('labelColor', 'label_color'), + labelFontWeight: pick('labelFontWeight', 'label_font_weight'), requiredColor: pick('requiredColor', 'required_color'), checkedColor: pick('checkedColor', 'checked_color'), placeholderColor: pick('placeholderColor', 'placeholder_color'), placeholderFontSize: pick('placeholderFontSize', 'placeholder_font_size'), + inputBorderColor: pick('inputBorderColor', 'input_border_color'), + inputBgColor: pick('inputBgColor', 'input_bg_color'), + inputFocusBorderColor: pick('inputFocusBorderColor', 'input_focus_border_color'), + inputFocusBgColor: pick('inputFocusBgColor', 'input_focus_bg_color'), showRowDivider: pick('showRowDivider', 'show_row_divider'), rowDividerColor: pick('rowDividerColor', 'row_divider_color') }; @@ -363,10 +375,16 @@ '--label-fixed-width': this.$util.rpx(cfg.labelFixedWidth), '--label-font-size': this.$util.rpx(num(cfg.labelFontSize, 28)), '--label-color': cfg.labelColor, + '--label-font-weight': cfg.labelFontWeight, '--required-color': cfg.requiredColor, '--checked-color': cfg.checkedColor, '--placeholder-color': cfg.placeholderColor, '--placeholder-font-size': this.$util.rpx(num(cfg.placeholderFontSize, 28)), + // 输入框视觉增强(与 ns-newform 对齐) + '--input-border-color': cfg.inputBorderColor, + '--input-bg-color': cfg.inputBgColor, + '--input-focus-border-color': cfg.inputFocusBorderColor, + '--input-focus-bg-color': cfg.inputFocusBgColor, '--row-divider-color': cfg.rowDividerColor, '--show-row-divider': cfg.showRowDivider === false ? '0' : '1' }); @@ -879,10 +897,16 @@ --label-fixed-width: 180rpx; --label-font-size: 28rpx; --label-color: #1f2937; + --label-font-weight: 600; --required-color: #ef4444; --placeholder-font-size: 28rpx; --checked-color: #ff4544; --placeholder-color: #909399; + // 输入框视觉增强(与 ns-newform 对齐) + --input-border-color: #e5e7eb; + --input-bg-color: #f9fafb; + --input-focus-border-color: #ff4544; + --input-focus-bg-color: #ffffff; --row-divider-color: #f0f0f0; --show-row-divider: 1; } @@ -946,6 +970,7 @@ text-align: left; font-size: var(--label-font-size, $font-size-base); color: var(--label-color, #1f2937); + font-weight: var(--label-font-weight, 600); text { font-size: var(--label-font-size, $font-size-base); @@ -967,6 +992,8 @@ line-height: inherit; text-align: left; + // H5 端 可能被 uni-app 编译为 包装组件,::v-deep 穿透 scoped 命中真实原生 input + ::v-deep input, input { font-size: var(--label-font-size, $font-size-base); text-align: left; @@ -978,8 +1005,16 @@ min-height: var(--input-height, 60rpx); border-radius: var(--input-radius, 0rpx); box-sizing: border-box; - padding: 0; - background: transparent; + padding: 0 12rpx; + // 输入框视觉增强(与 ns-newform 对齐) + border: 1rpx solid var(--input-border-color, #e5e7eb); + background: var(--input-bg-color, #f9fafb); + transition: all 0.3s ease; + + &:focus { + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); + } // 原生 placeholder 样式(WebView / H5 生效;小程序/鸿蒙的 placeholder // 通过 placeholder-class="placeholder" 钩子走 .placeholder 规则) @@ -997,6 +1032,7 @@ line-height: var(--input-height, 60rpx); } + ::v-deep textarea, textarea { font-size: var(--label-font-size, $font-size-base); width: 100%; @@ -1009,8 +1045,16 @@ text-align: left; border-radius: var(--input-radius, 0rpx); box-sizing: border-box; - padding: 0; - background: transparent; + padding: 12rpx; + // 输入框视觉增强(与 ns-newform 对齐) + border: 1rpx solid var(--input-border-color, #e5e7eb); + background: var(--input-bg-color, #f9fafb); + transition: all 0.3s ease; + + &:focus { + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); + } } .uni-input { @@ -1018,6 +1062,11 @@ color: var(--label-color, #1f2937); line-height: var(--input-height, 60rpx); min-height: var(--input-height, 60rpx); + // 输入框视觉增强(与 ns-newform 对齐) + border: 1rpx solid var(--input-border-color, #e5e7eb); + background: var(--input-bg-color, #f9fafb); + border-radius: var(--input-radius, 0rpx); + transition: all 0.3s ease; } .select-address { diff --git a/components/ns-newform/ns-newform.vue b/components/ns-newform/ns-newform.vue index 388bddf..d41c178 100644 --- a/components/ns-newform/ns-newform.vue +++ b/components/ns-newform/ns-newform.vue @@ -371,10 +371,18 @@ export default { labelFixedWidth: 180, labelFontSize: 28, labelColor: '#1f2937', + labelFontWeight: 600, + labelAutoMaxWidth: 200, // auto 模式下 label 宽度上限(rpx),超过后 ellipsis 截断 requiredColor: '#ef4444', checkedColor: '#ff4544', placeholderColor: '#ddd', placeholderFontSize: 28, + // 输入框视觉增强(可由后端 form_config 覆盖) + inputBorderColor: '#e5e7eb', + inputBgColor: '#f9fafb', + inputFocusBorderColor: '#ff4544', + inputFocusBgColor: '#ffffff', + labelFontWeight: 600, // 提交按钮 submitColor: '#ffffff', submitBgColor: '#ff4544', @@ -444,6 +452,12 @@ export default { '--checked-color': cfg.checkedColor, '--placeholder-color': cfg.placeholderColor, '--placeholder-font-size': this.$util.rpx(num(cfg.placeholderFontSize, 28)), + // 输入框视觉增强(边框 / 背景 / 聚焦 / label 字重) + '--input-border-color': cfg.inputBorderColor, + '--input-bg-color': cfg.inputBgColor, + '--input-focus-border-color': cfg.inputFocusBorderColor, + '--input-focus-bg-color': cfg.inputFocusBgColor, + '--label-font-weight': cfg.labelFontWeight, '--submit-color': cfg.submitColor, '--submit-bg-color': cfg.submitBgColor, '--submit-margin-top': this.$util.rpx(cfg.submitMarginTop || 0), @@ -559,8 +573,13 @@ export default { if (len > maxChars) maxChars = len; }); // 与后端公式一致:chars * (fontSize/2) * 1.1 + 12,单位 px → 转 rpx(×2) - const widthPx = Math.max(40, maxChars * (fontSize / 2) * 1.1 + 12); - this.maxLabelWidth = Math.round(widthPx * 2); + let widthPx = Math.max(40, maxChars * (fontSize / 2) * 1.1 + 12); + let widthRpx = Math.round(widthPx * 2); + // auto 模式下加宽度上限:超长 title 撑爆布局时,按 labelAutoMaxWidth 截断(rpx) + // 上限内 ellipsis 截断,保证控件区有足够空间;上限外也不会让 label 占满整行 + const maxWidthRpx = parseInt(this.config.labelAutoMaxWidth) || 200; + if (widthRpx > maxWidthRpx) widthRpx = maxWidthRpx; + this.maxLabelWidth = widthRpx; // 宽度变了,需要把全局 nameWidthStyle 重新合到每项 _labelStyle 里 this.recomputeItemStyles(); }, @@ -961,6 +980,12 @@ export default { --submit-bg-color: #ff4544; --placeholder-color: #ddd; --placeholder-font-size: 28rpx; + // 输入框视觉增强(边框 / 背景 / 聚焦 / label 字重) + --input-border-color: #e5e7eb; + --input-bg-color: #f9fafb; + --input-focus-border-color: #ff4544; + --input-focus-bg-color: #ffffff; + --label-font-weight: 600; --show-row-divider: 1; // 与后端 form-preview-wrap.no-divider-all 对齐:整组隐藏所有行分割线 @@ -1012,13 +1037,13 @@ export default { &.vertical-layout { flex-direction: column; align-items: flex-start; - + .name { width: 100%; - margin-bottom: 8rpx; + margin-bottom: var(--label-gap, 16rpx); margin-right: 0; } - + .box { width: 100%; } @@ -1068,7 +1093,7 @@ export default { text-align: left; font-size: var(--item-label-font-size, var(--label-font-size, 28rpx)); color: var(--item-label-color, var(--label-color, #1f2937)); - font-weight: 500; + font-weight: var(--item-label-font-weight, var(--label-font-weight, 600)); letter-spacing: 0.2rpx; text { @@ -1136,49 +1161,105 @@ export default { width: 100%; } - input { + // H5 端 被 uni-app 编译为 自定义组件, + // 真实 是其子节点,需要 ::v-deep 穿透 scoped 才能命中 + ::v-deep input { font-size: var(--label-font-size, 28rpx); text-align: left; height: var(--input-height, 60rpx); - border: none; + border: 1rpx solid var(--input-border-color, #e5e7eb); border-radius: var(--input-radius, 10rpx); line-height: var(--input-height, 60rpx); - padding: 0; - background: transparent; + padding: 0 12rpx; + background: var(--input-bg-color, #f9fafb); color: var(--label-color, #1f2937); transition: all 0.3s ease; width: 100%; box-sizing: border-box; - + &:focus { - background: transparent; + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); } - + &::placeholder { color: var(--placeholder-color, #ddd); font-size: var(--placeholder-font-size, 28rpx); } } - + + // 非 H5 端(小程序 / 鸿蒙 / App) 是直接原生元素,普通选择器即可 + input { + font-size: var(--label-font-size, 28rpx); + text-align: left; + height: var(--input-height, 60rpx); + border: 1rpx solid var(--input-border-color, #e5e7eb); + border-radius: var(--input-radius, 10rpx); + line-height: var(--input-height, 60rpx); + padding: 0 12rpx; + background: var(--input-bg-color, #f9fafb); + color: var(--label-color, #1f2937); + transition: all 0.3s ease; + width: 100%; + box-sizing: border-box; + + &:focus { + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); + } + + &::placeholder { + color: var(--placeholder-color, #ddd); + font-size: var(--placeholder-font-size, 28rpx); + } + } + + ::v-deep textarea { + font-size: var(--label-font-size, 28rpx); + width: 100%; + min-height: 120rpx; + line-height: 1.5; + text-align: left; + border: 1rpx solid var(--input-border-color, #e5e7eb); + border-radius: var(--input-radius, 10rpx); + padding: 12rpx; + background: var(--input-bg-color, #f9fafb); + color: var(--label-color, #1f2937); + transition: all 0.3s ease; + box-sizing: border-box; + height: auto; + + &:focus { + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); + } + + &::placeholder { + color: var(--placeholder-color, #ddd); + font-size: var(--placeholder-font-size, 28rpx); + } + } + textarea { font-size: var(--label-font-size, 28rpx); width: 100%; min-height: 120rpx; line-height: 1.5; text-align: left; - border: none; + border: 1rpx solid var(--input-border-color, #e5e7eb); border-radius: var(--input-radius, 10rpx); - padding: 0; - background: transparent; + padding: 12rpx; + background: var(--input-bg-color, #f9fafb); color: var(--label-color, #1f2937); transition: all 0.3s ease; box-sizing: border-box; height: auto; - + &:focus { - background: transparent; + background: var(--input-focus-bg-color, #ffffff); + border-color: var(--input-focus-border-color, #ff4544); } - + &::placeholder { color: var(--placeholder-color, #ddd); font-size: var(--placeholder-font-size, 28rpx);