下拉弹层改视口定位,规则表单换 ComboBox

absolute 的弹层会计入祖先滚动容器的可滚动区域——在对话框里打开下拉,
modal 会被撑出滚动条。弹层改 position: fixed 按视口摆放:逃出所有
overflow 裁剪,又因为还在 dialog 的 DOM 子树里,照样画在 top layer 之上。
代价是位置不跟随滚动,滚动和缩放时直接收起(弹层内部滚动不算)。
三个弹层组件(SelectBox、ComboBox、SourcePicker)同一套做法。

组件根元素不再写死 width: 100%:它和调用方的宽度规则同权重,谁赢
看样式表加载顺序——请求页的级别下拉被撑满整行就是这么来的。
弹层加 user-select: none 和最大宽度,选项超长省略号截断。

规则表单的类型、载荷、目标原来是 input + datalist,原生建议列表的样式
和开合状态都管不到,换成同族的 ComboBox:选项只是建议、手填合法,
Enter 在弹层开着时选中高亮项、收起时照旧提交表单。
This commit is contained in:
2026-08-11 23:58:53 +08:00
parent f927f9fff7
commit 4c43756208
4 changed files with 413 additions and 41 deletions
+12 -20
View File
@@ -9,6 +9,7 @@
*/
import { computed, ref, watch } from 'vue'
import { buildRule, isStructuredEditable, parseRule } from '@shared/rules.ts'
import ComboBox from '../components/ComboBox.vue'
import IconClose from '~icons/ri/close-line'
const props = defineProps<{
@@ -143,45 +144,36 @@ function submit() {
<label class="row">
<span class="k">类型</span>
<span class="v">
<input v-model="type" class="mono" type="text" list="rule-types" autocomplete="off" />
<datalist id="rule-types">
<option v-for="t in COMMON_TYPES" :key="t" :value="t" />
</datalist>
<ComboBox v-model="type" mono :options="COMMON_TYPES" />
</span>
</label>
<label v-if="!isMatch" class="row">
<span class="k">载荷</span>
<span class="v">
<ComboBox
v-if="isRuleSet"
v-model="payload"
mono
:options="providerNames"
placeholder="规则组名"
/>
<input
v-else
v-model="payload"
class="mono"
type="text"
:list="isRuleSet ? 'rule-set-names' : undefined"
:placeholder="isRuleSet ? '规则组名' : 'youtube.com'"
placeholder="youtube.com"
autocomplete="off"
spellcheck="false"
/>
<datalist v-if="isRuleSet" id="rule-set-names">
<option v-for="name in providerNames" :key="name" :value="name" />
</datalist>
</span>
</label>
<label class="row">
<span class="k">目标</span>
<span class="v">
<input
v-model="target"
class="mono"
type="text"
list="rule-targets"
placeholder="DIRECT"
autocomplete="off"
/>
<datalist id="rule-targets">
<option v-for="name in outboundNames" :key="name" :value="name" />
</datalist>
<ComboBox v-model="target" mono :options="outboundNames" placeholder="DIRECT" />
</span>
</label>