refactor(ns-newform.vue): 优化必填星号样式,动态计算颜色和间距

This commit is contained in:
2026-09-03 17:59:22 +08:00
parent b2211edeab
commit fc5c7e682c

View File

@@ -5,8 +5,8 @@
<view v-if="item.controller == 'Text'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]" :style="rowCellStyle">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-left']" :style="item._boxAlignStyle">
<input
@@ -23,8 +23,8 @@
<view v-if="item.controller == 'Textarea'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', 'flex-box', 'textarea', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-left']" :style="item._boxAlignStyle">
<!-- 所有平台统一通过 formConfig.textareaRows / item.value.rows 控制显示行数:
@@ -51,8 +51,8 @@
>
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<text v-if="item.val != ''">{{ item.val }}</text>
@@ -67,8 +67,8 @@
<view v-if="item.controller == 'Checkbox'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'check-group-box', 'align-left', 'option-layout-' + (item.value.option_layout || 'vertical')]">
<checkbox-group @change="checkboxChange($event, index)" :style="item._optionLayoutStyle">
@@ -96,8 +96,8 @@
<view v-if="item.controller == 'Radio'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'radio-group-box', 'align-left', 'option-layout-' + (item.value.option_layout || 'vertical')]">
<radio-group @change="radioChange($event, index)" :style="item._optionLayoutStyle">
@@ -125,8 +125,8 @@
<view v-if="item.controller == 'Img'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'img-boxs', 'align-left']" :style="item._boxAlignStyle">
<view v-for="(v, k) in item.img_lists" :key="k" class="img-box" @tap="uploadImg(index)">
@@ -144,8 +144,8 @@
<view v-if="item.controller == 'Date'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<picker
@@ -166,8 +166,8 @@
<view v-if="item.controller == 'Datelimit'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'date-boxs', 'align-center']" :style="item._boxAlignStyle">
<view class="date-box">
@@ -205,8 +205,8 @@
<view v-if="item.controller == 'Time'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<picker
@@ -227,8 +227,8 @@
<view v-if="item.controller == 'Timelimit'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'date-boxs', 'align-center']" :style="item._boxAlignStyle">
<view class="date-box">
@@ -266,8 +266,8 @@
<view v-if="item.controller == 'City'" class="order-wrap" :class="rowWrapClass" :style="rowWrapStyle">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="item._labelStyle">
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required required-after" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
<text class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
<text class="tit">{{ item.value.title }}</text><text v-if="requiredPosition === 'after'" class="required" :style="item._starStyle">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<pick-regions
@@ -566,10 +566,8 @@ export default {
};
return this.$util.objToStyle(style);
},
requiredColor() {
return this.config.requiredColor;
},
// 必填星号位置(before=标签前(默认)/ after=标签后;与后端 form_config.required_position 对齐)
// 星号的颜色/字号/间距动态值由 recomputeItemStyles 预计算到 item._starStyle(inline,跨端安全)
requiredPosition() {
return this.config.requiredPosition === 'after' ? 'after' : 'before';
},
@@ -617,6 +615,23 @@ export default {
const align = itemValue.input_align;
this.$set(item, '_boxAlignStyle', align ? { 'text-align': align } : {});
// 必填星号样式:颜色/字号/间距全部预计算 inline(微信小程序/鸿蒙元服务对
// 嵌套 var() fallback 与 .required-after 类 margin 翻转支持不全,动态值不走 CSS 变量链)。
// 字号优先 item 级 label_font_size,回退全局 labelFontSize(默认 28);
// after 位置 margin-left,before 位置 margin-right(跨端用 $util.rpx,H5 转 px)
const starFontSize = this.$util.rpx(itemValue.label_font_size || this.config.labelFontSize || 28);
const starStyle = {
color: this.config.requiredColor || '#ef4444',
'font-size': starFontSize,
'font-weight': 'bold'
};
if (this.requiredPosition === 'after') {
starStyle['margin-left'] = this.$util.rpx(6);
} else {
starStyle['margin-right'] = this.$util.rpx(6);
}
this.$set(item, '_starStyle', starStyle);
// 选项排列样式:默认 vertical(每项一行),仅当后端显式配置 wrap 时横向换行
// 走 inline style(不依赖 dev 编译产物的 SCSS 类,跨端兼容更稳)
// 直接写 flex-direction 等 CSS 属性,inline style 优先级最高
@@ -1238,19 +1253,16 @@ export default {
}
}
/* 必填星号:动态值(颜色/字号/间距)由 item._starStyle 内联提供;
类内只留静态兜底(recompute 前的首次渲染),不依赖 var() 嵌套 fallback(MP/鸿蒙支持不全) */
.required {
color: var(--required-color, #ef4444);
font-size: var(--item-label-font-size, var(--label-font-size, 28rpx));
color: #ef4444;
font-size: 28rpx;
margin-right: 6rpx;
font-weight: bold;
display: inline-block;
vertical-align: middle;
}
/* 必填星号位置=标签后(required_position=after):margin 方向反转,与标签前视觉对称 */
.required.required-after {
margin-right: 0;
margin-left: 6rpx;
}
}
.box {