远端单选框组 ​
在单选框组上管理异步选项、重载和请求取消。
基础用法 ​
示例通过本地 Promise 函数加载选项,支持模型更新、暂停与重载。所有请求都留在演示内部。
基础场景的原始值模型保持 ready/running,单选更新会替换上一项;对象模式则保留规范化选项及来源raw。两种存储语义由 valueMode 明确选择,单选不接收集合存储策略。
本地数据与生命周期
<template>
<section class="data-demo">
<!-- prettier-ignore -->
<AsamCheckboxItem v-model="active">启用请求</AsamCheckboxItem>
<AsamRemoteRadio
ref="control"
v-model="value"
:data-source="dataSource"
:active="active"
size="default"
@error="error = $event.message"
@success="error = ''"
>
<template #option="{ option }">{{ option.label }}</template>
</AsamRemoteRadio>
<div class="demo-actions">
<AsamButton type="default" native-type="button" :disabled="!active" @click="reload"
>强制重载</AsamButton
>
<AsamButton type="default" native-type="button" @click="control?.cancel()"
>取消请求</AsamButton
>
</div>
<p class="example-paragraph" role="status">{{ result }} {{ error }}</p>
<pre>{{ value }}</pre>
</section>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamRemoteRadioValuesDemo' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamRemoteRadio, defineAsamOptions } from '@asam-ui/ui';
import type { AsamAsyncChoiceExpose, AsamApiRequest } from '@asam-ui/ui';
interface Item {
label: string;
value: string;
children?: readonly Item[];
}
interface Query {
text: string;
}
const value = ref<string | null>(null);
const active = ref(true);
const control = ref<AsamAsyncChoiceExpose<string, Item>>();
const error = ref('');
const result = ref('');
const items: readonly Item[] = [
{ label: '准备', value: 'ready' },
{ label: '进行', value: 'running' }
];
const api: AsamApiRequest<Query, readonly Item[]> = async (params, context) => {
context.signal.throwIfAborted();
return items.filter((item) => item.label.includes(params.text));
};
const factory = defineAsamOptions<string, Item>();
const dataSource = factory.api({
api,
params: { text: '' },
transform: (response) => response,
fieldNames: { label: 'label', value: 'value' }
});
async function reload() {
const response = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
</script>
<style scoped>
.data-demo {
display: grid;
gap: var(--asam-space-md);
justify-items: start;
}
.data-demo > p,
.data-demo > pre,
.data-demo > fieldset {
width: 100%;
min-width: 0;
margin: 0;
}
.demo-actions {
display: flex;
flex-wrap: wrap;
gap: var(--asam-space-md);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template>
<section class="data-demo">
<!-- prettier-ignore -->
<AsamCheckboxItem v-model="active">启用请求</AsamCheckboxItem>
<AsamRemoteRadio
ref="control"
v-model="value"
:data-source="dataSource"
:active="active"
size="default"
@error="error = $event.message"
@success="error = ''"
>
<template #option="{ option }">{{ option.label }}</template>
</AsamRemoteRadio>
<div class="demo-actions">
<AsamButton type="default" native-type="button" :disabled="!active" @click="reload"
>强制重载</AsamButton
>
<AsamButton type="default" native-type="button" @click="control?.cancel()"
>取消请求</AsamButton
>
</div>
<p class="example-paragraph" role="status">{{ result }} {{ error }}</p>
<pre>{{ value }}</pre>
</section>
</template>
<script setup>
defineOptions({ name: 'AsamRemoteRadioValuesDemo' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamRemoteRadio, defineAsamOptions } from '@asam-ui/ui';
const value = ref(null);
const active = ref(true);
const control = ref();
const error = ref('');
const result = ref('');
const items = [
{ label: '准备', value: 'ready' },
{ label: '进行', value: 'running' }
];
const api = async (params, context) => {
context.signal.throwIfAborted();
return items.filter((item) => item.label.includes(params.text));
};
const factory = defineAsamOptions();
const dataSource = factory.api({
api,
params: { text: '' },
transform: (response) => response,
fieldNames: { label: 'label', value: 'value' }
});
async function reload() {
const response = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
</script>
<style scoped>
.data-demo {
display: grid;
gap: var(--asam-space-md);
justify-items: start;
}
.data-demo > p,
.data-demo > pre,
.data-demo > fieldset {
width: 100%;
min-width: 0;
margin: 0;
}
.demo-actions {
display: flex;
flex-wrap: wrap;
gap: var(--asam-space-md);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
数据来源与覆盖 ​
dataSource、api + params、request 三种来源只选一种。 完整说明。
单选值模式的模型为标量或 null;valueMode=object 时使用规范化 AsamOption。单选框组由组件入口确定单选职责,没有 multiple 或 multipleValueMode 配置。
生命周期、事件与实例 ​
active=false 暂停请求并保留上次成功数据;reload({ force: true }) 请求新数据,cancel() 取消当前请求。 完整说明。
immediate 控制初始化是否请求,active 控制请求是否启用。初始化和默认值以本页自动 API 的原始来源为准。
插槽与基础能力 ​
option 插槽接收 { option },option.raw 保留原始对象;default 插槽沿用基础选项布局。实例仅增加数据重载与取消,不声明基础选择器的 focus/blur。
本站继承关系 ​
- 单选框组:适用的基础展示、交互与公开 API。
本页数据来源、模型、事件和实例的覆盖规则优先;本站链接不扩大本组件公开契约。尺寸使用基础组件的 ASAM 尺寸规则,示例使用 default。
连续按钮与对象模型 ​
type="button" 将选项排列为连续拼接的按钮;尺寸为 large / big / default / small。 完整说明。
四个公开事件在完整示例的事件记录中可检查:update:modelValue 与 change 保留具体单项/集合模型,success 保留规范化选项及来源 raw,error 保留错误种类和消息。失败恢复和取消继续保留调用方模型;取消不伪装为 error。
option 插槽保留具体规范化项和 option.raw.id;default 插槽无 scope 参数,可替换选项布局。完整示例可切换自定义默认内容并恢复来源选项;默认内容替代选项布局,切换本身不修改模型,恢复后仍保留原始实体。
连续按钮、对象模型与四档尺寸
局部请求错误插槽 ​
可选 error 插槽仅在当前请求错误存在时调用,接收只读 { error, stale, retry }。 完整说明。
retry 不接收参数,返回强制 reload 的 Promise,并遵守取消和卸载规则。 完整说明。
提供该插槽时,自有内容替换整个默认局部错误区;返回空内容也表示主动替换。 未提供时继续显示原错误文字、过期提示和默认重试按钮。无 error 的单独 stale 状态 不调用此插槽;empty、loading 和其他基础插槽继续使用原作用域。
以下完整 TS/JS 示例先制造失败,再等待插槽 retry 的返回结果;成功后可再次制造 更新失败,观察旧结果与模型保留。每次挂载使用独立子 app 和本地 provider。
局部错误定制、等待重试与过期恢复
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const transport_js_1: any = require("./transport.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamRemoteRadioDemoLocalErrorExample' },
__name: 'Demo',
setup(__props?: any) {
const host: any = (0, vue_3.ref)();
let app: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
const transport: any = (0, transport_js_1.createTransport)();
app = (0, vue_3.createApp)(Child_vue_1.default, { transport });
(0, ui_1.provideAsamData)(app, transport.provider, { scope: 'AsamRemoteRadio-local-error' });
app.mount(host.value);
});
(0, vue_3.onBeforeUnmount)(() => app?.unmount());
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-spacing-1" };
const _hoisted_2: any = {
role: "alert",
"data-testid": "local-error"
};
const _hoisted_3: any = { class: "example-paragraph" };
const _hoisted_4: any = {
key: 0,
class: "example-paragraph"
};
const _hoisted_5: any = {
class: "example-paragraph",
role: "status",
"data-testid": "retry-result"
};
const _hoisted_6: any = {
class: "example-paragraph",
"data-testid": "transport-count"
};
const _hoisted_7: any = { "data-testid": "local-model" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamRemoteRadioChildLocalErrorExample' },
__name: 'Child',
props: {
transport: { type: null, required: true }
},
setup(__props?: any) {
const props: any = __props;
const transport: any = props.transport;
const value: any = (0, vue_3.ref)(null);
const control: any = (0, vue_3.ref)();
const busy: any = (0, vue_3.ref)(false), result: any = (0, vue_3.ref)('');
const dataSource: any = (0, ui_1.defineAsamOptions)().api({
api: transport.api,
params: undefined,
transform: (rows?: any) => rows,
fieldNames: { label: 'label', value: 'value' }
});
(0, vue_3.onMounted)(async () => {
const response: any = await control.value?.reload();
result.value = response?.status ?? 'cancelled';
});
async function recover(retry?: any) {
busy.value = true;
transport.failing.value = false;
try {
const response: any = await retry();
result.value = response.status;
}
finally {
busy.value = false;
}
}
async function failAgain() {
busy.value = true;
transport.failing.value = true;
try {
const response: any = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
finally {
busy.value = false;
}
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamRemoteRadio), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => ((value).value = $event)),
"data-source": (0, vue_2.unref)(dataSource),
immediate: false
}, {
error: (0, vue_2.withCtx)(({ error, stale, retry }: any) => [
(0, vue_2.createElementVNode)("div", _hoisted_2, [
(0, vue_2.createElementVNode)("p", _hoisted_3, (0, vue_2.toDisplayString)(error.message) + "(" + (0, vue_2.toDisplayString)(error.kind) + ")", 1 /* TEXT */),
stale
? ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("p", _hoisted_4, "已保留上次成功结果。"))
: (0, vue_2.createCommentVNode)("v-if", true),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: ($event?: any) => (recover(retry))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_2.createTextVNode)(" 恢复并重试 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "data-source"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: failAgain
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_2.createTextVNode)("模拟更新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_2.createElementVNode)("p", _hoisted_5, (0, vue_2.toDisplayString)(result.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("p", _hoisted_6, " 请求 " + (0, vue_2.toDisplayString)((0, vue_2.unref)(transport).calls.value) + " 次,字典刷新 " + (0, vue_2.toDisplayString)((0, vue_2.unref)(transport).refreshes.value) + " 次 ", 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", _hoisted_7, (0, vue_2.toDisplayString)(value.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-a13c2d72";
},
"transport.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTransport = createTransport;
const vue_1: any = require("vue");
function createTransport() {
const failing: any = (0, vue_1.ref)(true), calls: any = (0, vue_1.ref)(0), refreshes: any = (0, vue_1.ref)(0);
const api: any = async () => {
calls.value++;
if (failing.value)
throw Error('演示请求暂不可用');
return [
{ id: 1, value: 'ready', label: '准备' },
{ id: 2, value: 'running', label: '进行' }
];
};
const provider: any = {
dict: {
get: async (_type?: any, context?: any) => {
context.signal.throwIfAborted();
return api();
},
refresh: async (context?: any) => {
context.signal.throwIfAborted();
refreshes.value++;
}
}
};
return { failing, calls, refreshes, api, provider };
}
},
};
const __dependencies: any = {"Demo.vue":{"./Child.vue":"Child.vue","./transport.js":"transport.ts"},"Child.vue":{"./transport.js":"transport.ts"},"transport.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-a13c2d72] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-a13c2d72]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const transport_js_1 = require("./transport.js");
exports.default = Object.assign({ name: 'AsamRemoteRadioDemoLocalErrorExample' }, {
__name: 'Demo',
setup(__props) {
const host = (0, vue_2.ref)();
let app;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
const transport = (0, transport_js_1.createTransport)();
app = (0, vue_2.createApp)(Child_vue_1.default, { transport });
(0, ui_1.provideAsamData)(app, transport.provider, { scope: 'AsamRemoteRadio-local-error' });
app.mount(host.value);
});
(0, vue_2.onBeforeUnmount)(() => app?.unmount());
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-spacing-1" };
const _hoisted_2 = {
role: "alert",
"data-testid": "local-error"
};
const _hoisted_3 = { class: "example-paragraph" };
const _hoisted_4 = {
key: 0,
class: "example-paragraph"
};
const _hoisted_5 = {
class: "example-paragraph",
role: "status",
"data-testid": "retry-result"
};
const _hoisted_6 = {
class: "example-paragraph",
"data-testid": "transport-count"
};
const _hoisted_7 = { "data-testid": "local-model" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamRemoteRadioChildLocalErrorExample' }, {
__name: 'Child',
props: { transport: { type: Object, required: true } },
setup(__props) {
const props = __props;
const transport = props.transport;
const value = (0, vue_2.ref)(null);
const control = (0, vue_2.ref)();
const busy = (0, vue_2.ref)(false), result = (0, vue_2.ref)('');
const dataSource = (0, ui_1.defineAsamOptions)().api({ api: transport.api, params: undefined });
(0, vue_2.onMounted)(async () => {
const response = await control.value?.reload();
result.value = response?.status ?? 'cancelled';
});
async function recover(retry) {
busy.value = true;
transport.failing.value = false;
try {
const response = await retry();
result.value = response.status;
}
finally {
busy.value = false;
}
}
async function failAgain() {
busy.value = true;
transport.failing.value = true;
try {
const response = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
finally {
busy.value = false;
}
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamRemoteRadio), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ((value).value = $event)),
"data-source": (0, vue_1.unref)(dataSource),
immediate: false
}, {
error: (0, vue_1.withCtx)(({ error, stale, retry }) => [
(0, vue_1.createElementVNode)("div", _hoisted_2, [
(0, vue_1.createElementVNode)("p", _hoisted_3, (0, vue_1.toDisplayString)(error.message) + "(" + (0, vue_1.toDisplayString)(error.kind) + ")", 1 /* TEXT */),
stale
? ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("p", _hoisted_4, "已保留上次成功结果。"))
: (0, vue_1.createCommentVNode)("v-if", true),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: $event => (recover(retry))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_1.createTextVNode)(" 恢复并重试 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "data-source"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: failAgain
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_1.createTextVNode)("模拟更新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_1.createElementVNode)("p", _hoisted_5, (0, vue_1.toDisplayString)(result.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("p", _hoisted_6, " 请求 " + (0, vue_1.toDisplayString)((0, vue_1.unref)(transport).calls.value) + " 次,字典刷新 " + (0, vue_1.toDisplayString)((0, vue_1.unref)(transport).refreshes.value) + " 次 ", 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", _hoisted_7, (0, vue_1.toDisplayString)(value.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-c0402666";
},
"transport.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTransport = createTransport;
const vue_1 = require("vue");
function createTransport() {
const failing = (0, vue_1.ref)(true), calls = (0, vue_1.ref)(0), refreshes = (0, vue_1.ref)(0);
const api = async () => {
calls.value++;
if (failing.value)
throw Error('演示请求暂不可用');
return [
{ id: 1, value: 'ready', label: '准备' },
{ id: 2, value: 'running', label: '进行' }
];
};
const provider = {
dict: {
get: async (_type, context) => {
context.signal.throwIfAborted();
return api();
},
refresh: async (context) => {
context.signal.throwIfAborted();
refreshes.value++;
}
}
};
return { failing, calls, refreshes, api, provider };
}
},
};
const __dependencies = {"Demo.vue":{"./Child.vue":"Child.vue","./transport.js":"transport.js"},"Child.vue":{},"transport.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-c0402666] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-c0402666]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
API
属性 AsamRemoteRadioProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
ariaLabel | — | string | undefined | — |
id | — | string | undefined | — |
disabled | — | boolean | undefined | — |
size | — | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
fill | — | string | undefined | — |
type | — | enum"button" | "radio"完整类型:"button" | "radio" | undefined | — |
name | — | string | undefined | — |
modelValue | — | V | null | undefined | AsamChoiceOption<V, I> | null | undefined | — |
textColor | — | string | undefined | — |
valueMode | — | enum"value" | "object"完整类型:"value" | undefined | "object" | — |
validateEvent | — | boolean | undefined | — |
immediate | — | boolean | undefined | — |
active | — | boolean | undefined | — |
dataSource | — | AsamOptionsSource<V, I, "api" | "request"> | undefined | — |
api | — | undefined | AsamApiRequest<P, R> | — |
request | — | undefined | AsamRequestConfig | — |
params | — | undefined | P | — |
transform | — | undefined | ((response: R) => readonly I[]) | undefined | ((response: unknown) => readonly I[]) | undefined | — |
fieldNames | — | undefined | AsamMapping | undefined | — |
cache | — | undefined | AsamOptionsCache | undefined | — |
事件 AsamRadioDataEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
success | — | [data: readonly AsamOption<V, I>[]] | — |
error | — | [error: AsamDataError] | — |
update:modelValue | — | [value: V | AsamOption<V, I> | null] | — |
change | — | [value: V | AsamOption<V, I> | null] | — |
插槽 AsamAsyncChoiceSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
default | — | (() => unknown) | undefined | — |
option | — | ((scope: { option: AsamOption<V, I>; }) => unknown) | undefined | — |
error | 替换本地错误区域;重试返回现有强制重新加载的 Promise。 | (AsamAsyncChoiceSlots<V, I>)["error"] | — |
实例方法与状态 AsamAsyncChoiceExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
reload | — | (options?: { readonly force?: boolean; }) => Promise<AsamReloadResult<readonly AsamOption<V, I>[]>> | — |
cancel | — | () => void | — |
用法与契约补充说明 ​
数据来源与覆盖 ​
dataSource、api + params、request 三种来源只选一种。dataSource 必须由 defineAsamOptions 创建,使用该来源时映射、转换和缓存配置写在工厂内,不再重复传短来源属性。自定义字段映射同时提供同步 transform;API 返回 Promise,并检查 context.signal。
生命周期、事件与实例 ​
active=false 暂停请求并保留上次成功数据;reload({ force: true }) 请求新数据,cancel() 取消当前请求。success 返回规范化选项数组,error 返回 AsamDataError;旧成功数据更新失败时组件显示过期状态。reload 的 status 为 success、error 或 cancelled;不能把取消当作成功。
连续按钮与对象模型 ​
type="button" 将选项排列为连续拼接的按钮;尺寸为 large / big / default / small。完整示例保留数字值 0 和 option.raw,演示停用选项、加载失败后保留模型、恢复与取消慢请求。对象由组件规范化,调用方不手工拼接标签。Radio 只承担单选;不接收 Checkbox 的 min/max 或 tag。
局部请求错误插槽 ​
可选 error 插槽仅在当前请求错误存在时调用,接收只读 { error, stale, retry }。
error 与本实例 error 事件中的 AsamDataError 为同一对象,保留 cause、kind、
message 与 notified;渲染插槽不会再次通知 provider。stale 表示保留的数据已过期。
更多参数与事件说明 ​
局部请求错误插槽 ​
retry() 不接收参数,直接返回现有 reload({ force: true }) 的 Promise,结果为
AsamReloadResult<readonly AsamOption<V, I>[]> 的 success、error 或 cancelled 分支。
重试遵守 active、当前来源、取消和卸载规则,不改写模型。
继承能力
本入口的独有 API 见上表,基础能力见本站对应页面。
关联组件
参数与事件补充说明
组合契约按分支生效;请同时查看公开类型。
参数与事件说明
ariaLabel
必填:否;声明来源:上游声明。
id
必填:否;声明来源:ASAM 声明。
disabled
必填:否;声明来源:ASAM 声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
fill
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
type
必填:否;声明来源:ASAM 声明。
type 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"button" / "radio"
name
必填:否;声明来源:ASAM 声明。
modelValue
必填:否;声明来源:ASAM 声明。
modelValue 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
modelValue.label:string— 数据 / provider 协议modelValue.value:V— 数据 / provider 协议modelValue.disabled:boolean | undefined— 数据 / provider 协议枚举:
false/truemodelValue.raw:I— 数据 / provider 协议modelValue.children:readonly AsamOption<V, I>[] | undefined— 数据 / provider 协议
textColor
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
valueMode
必填:否;声明来源:ASAM 声明。
valueMode 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"value"
枚举:"object"
validateEvent
必填:否;声明来源:ASAM 声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
immediate
必填:否;声明来源:数据 / provider 协议。
immediate 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
active
必填:否;声明来源:数据 / provider 协议。
active 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
dataSource
必填:否;声明来源:数据 / provider 协议。
dataSource 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
dataSource.kind:"api" | "request"— 数据 / provider 协议枚举:
"api"/"request"dataSource.__@sourceBrand@58165:{ readonly value: V; readonly raw: I; }— 数据 / provider 协议dataSource.__@sourceBrand@58165.value:V— 数据 / provider 协议dataSource.__@sourceBrand@58165.raw:I— 数据 / provider 协议
api
必填:否;声明来源:数据 / provider 协议。
api 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(params: P, context: AsamRequestContext): Promise<R>
request
必填:否;声明来源:数据 / provider 协议。
request 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
request.url:string— 数据 / provider 协议request.method:"delete" | "get" | "post" | "put" | undefined— 数据 / provider 协议枚举:
"delete"/"get"/"post"/"put"request.params:Readonly<Record<string, unknown>> | undefined— 数据 / provider 协议request.data:unknown— 数据 / provider 协议
params
必填:否;声明来源:数据 / provider 协议。
transform
必填:否;声明来源:数据 / provider 协议。
transform 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(response: R): readonly I[]
事件参数:(response: unknown): readonly I[]
fieldNames
必填:否;声明来源:数据 / provider 协议。
fieldNames 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
fieldNames.label:string— 数据 / provider 协议fieldNames.value:string— 数据 / provider 协议fieldNames.disabled:string | undefined— 数据 / provider 协议fieldNames.children:string | undefined— 数据 / provider 协议
cache
必填:否;声明来源:数据 / provider 协议。
cache 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
cache.ttlMs:number— 数据 / provider 协议cache.key:((requestInput: unknown) => string) | undefined— 数据 / provider 协议事件参数:
(requestInput: unknown): string
AsamRemoteRadioProps 公开类型视图
import type { AsamRemoteRadioProps, AsamValue, AsamRecord, AsamChoiceRuntimeProps, AsamControlSize, AsamOptionsSource, AsamApiRequest, AsamRequestContext, AsamMapping, AsamOptionsCache, AsamRequestConfig, AsamChoiceOption, AsamOption } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamRemoteRadioProps
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord, P = unknown, R = unknown> = AsamRemoteRadioProps<V, I, P, R>;
参数与事件说明
success
必填:是;声明来源:数据 / provider 协议。
error
必填:是;声明来源:数据 / provider 协议。
update:modelValue
必填:是;声明来源:数据 / provider 协议。
change
必填:是;声明来源:数据 / provider 协议。
AsamRadioDataEmits 公开类型视图
import type { AsamRadioDataEmits, AsamValue, AsamOption, AsamDataError } from '@asam-ui/ui';
// AsamRadioDataEmits
type PublicContract<V extends AsamValue = AsamValue, I extends object = object> = {
"success": [data: readonly AsamOption<V, I>[]];
"error": [error: AsamDataError];
"update:modelValue": [value: V | AsamOption<V, I> | null];
"change": [value: V | AsamOption<V, I> | null];
};
参数与事件说明
default
必填:否;声明来源:数据 / provider 协议。
default 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
option
必填:否;声明来源:数据 / provider 协议。
option 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: { option: AsamOption<V, I>; }): unknown
error
必填:否;声明来源:数据 / provider 协议。
error 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: Parameters<Extract<NonNullable<(AsamAsyncChoiceSlots<V, I>)["error"]>, (...args: never[]) => unknown>>[0]): unknown
AsamAsyncChoiceSlots 公开类型视图
import type { AsamAsyncChoiceSlots, AsamValue, AsamOption, AsamDataError, AsamReloadResult } from '@asam-ui/ui';
// AsamAsyncChoiceSlots
type PublicContract<V extends AsamValue = AsamValue, I extends object = object> = {
"default"?: (() => unknown) | undefined;
"option"?: ((scope: { option: AsamOption<V, I>; }) => unknown) | undefined;
"error"?: (AsamAsyncChoiceSlots<V, I>)["error"];
};
参数与事件说明
reload
必填:是;声明来源:数据 / provider 协议。
reload 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(options?: { readonly force?: boolean; } | undefined): Promise<AsamReloadResult<readonly AsamOption<V, I>[]>>
cancel
必填:是;声明来源:数据 / provider 协议。
cancel 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
AsamAsyncChoiceExpose 公开类型视图
import type { AsamAsyncChoiceExpose, AsamValue, AsamRecord, AsamOption, AsamReloadResult } from '@asam-ui/ui';
// AsamAsyncChoiceExpose
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord> = {
"reload": (options?: { readonly force?: boolean; }) => Promise<AsamReloadResult<readonly AsamOption<V, I>[]>>;
"cancel": () => void;
};