代码演示
如何引入
<script setup lang="ts">
import { Feedback } from '@fibrous/semi-ui-vue';
</script>
基本使用
通过 v-model:visible 设置是否显示,取消、关闭和 Esc 会把它写回 false,提交按钮只触发 @ok,由使用方关闭。默认反馈展示内容是 emoji 形式。 可通过 @valueChange 获取当前选择的内容。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Feedback, type FeedbackValue } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
};
const onValueChange = (value: FeedbackValue) => {
console.log('emoji value', value);
};
</script>
<template>
<Button @click="visible = !visible">展示反馈: Popup, emoji</Button>
<Feedback v-model:visible="visible" title="您对本产品的评分是?" @ok="handleOk" @valueChange="onValueChange" />
</template>文字类型
设置 type 为 text 可获得多行输入框形式的 feedback,可通过 textAreaProps 设置多行输入框的参数。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Feedback } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
};
const textAreaProps = { maxCount: 200 };
</script>
<template>
<Button @click="visible = !visible">展示反馈: Popup, text</Button>
<Feedback v-model:visible="visible" :textAreaProps="textAreaProps" title="您对本产品的建议是?" type="text" @ok="handleOk" />
</template>单选反馈
设置 type 为 radio 可获得单选形式的 feedback,可通过 radioGroupProps 设置单选的参数。选项组默认没有可访问名称,可通过 radioGroupProps 的 aria-label 命名。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Feedback } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
};
const radioGroupProps = { options: ['访客', '开发者', '维护者'] };
</script>
<template>
<Button @click="visible = !visible">展示反馈: Popup, radio</Button>
<Feedback v-model:visible="visible" :radioGroupProps="radioGroupProps" title="您的身份是" type="radio" @ok="handleOk" />
</template>多选反馈
设置 type 为 checkbox 可获得多选形式的 feedback,可通过 checkboxGroupProps 设置多选的参数。选项组默认没有可访问名称,可通过 checkboxGroupProps 的 aria-label 命名。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Feedback } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
};
const checkboxGroupProps = { options: ['抖音', '火山', '豆包'] };
</script>
<template>
<Button @click="visible = !visible">展示反馈: Popup, checkbox</Button>
<Feedback v-model:visible="visible" :checkboxGroupProps="checkboxGroupProps" title="您最常使用以下哪些产品?" type="checkbox" @ok="handleOk" />
</template>自定义反馈内容
设置 type 为 custom 可获得自定义内容的 feedback,反馈的内容写在默认插槽中。使用自定义反馈时候,需自行控制提交按钮的禁用与否状态,用户可通过 okButtonProps 设置。
代码
<script setup lang="ts">
import { computed, ref } from 'vue';
import { Button, Feedback, TextArea } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const value = ref('');
const handleOk = () => {
visible.value = false;
};
const okButtonProps = computed(() => ({ disabled: !value.value }));
</script>
<template>
<Button @click="visible = !visible">展示反馈: Popup, custom</Button>
<Feedback v-model:visible="visible" :okButtonProps="okButtonProps" title="您对本产品的建议是?" type="custom" @ok="handleOk">
<span>这是一段自定义的内容</span>
<TextArea v-model="value" />
</Feedback>
</template>模态对话框形式
可通过 mode 反馈的形式,默认是 popup, 设置为 modal 可获得模态对话框形式的展示。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Feedback, type FeedbackValue } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
};
const onValueChange = (value: FeedbackValue) => {
console.log('emoji value', value);
};
</script>
<template>
<Button @click="visible = !visible">展示反馈: Modal, emoji</Button>
<Feedback v-model:visible="visible" mode="modal" title="Why did you choose this rating?" @ok="handleOk" @valueChange="onValueChange" />
</template>反馈完成提示
反馈完成后,可以切换展示信息提示用户本次反馈已经完成。
代码
<script setup lang="ts">
import { reactive } from 'vue';
import { IllustrationSuccess, IllustrationSuccessDark } from '@fibrous/semi-illustrations-vue';
import { Button, Empty, Feedback, TextArea } from '@fibrous/semi-ui-vue';
const createState = () => reactive({ visible: false, value: '', showThanks: false });
const popup = createState();
const modal = createState();
const emptyStyle = { padding: '30px' };
const imageStyle = { width: '150px', height: '150px' };
// The thanks view stays 200ms past the close so the exit animation still shows it.
const handleOk = (state: ReturnType<typeof createState>) => {
state.showThanks = true;
setTimeout(() => {
state.visible = false;
setTimeout(() => {
state.showThanks = false;
}, 200);
}, 1500);
};
</script>
<template>
<div>
<Button @click="popup.visible = !popup.visible">Open Feedback: Popup, Custom</Button>
<Feedback v-model:visible="popup.visible" :okButtonProps="{ disabled: !popup.value }" :title="popup.showThanks ? ' ' : 'What is your feedback on this product?'" type="custom" @ok="handleOk(popup)">
<template v-if="popup.showThanks" #footer />
<Empty v-if="popup.showThanks" :style="emptyStyle">
<template #image>
<IllustrationSuccess :style="imageStyle" />
</template>
<template #darkModeImage>
<IllustrationSuccessDark :style="imageStyle" />
</template>
<template #description>感谢您的反馈</template>
</Empty>
<template v-else>
<span>这是一段自定义的内容</span>
<TextArea v-model="popup.value" />
</template>
</Feedback>
<br />
<br />
<Button @click="modal.visible = !modal.visible">Open Feedback: Modal, Custom</Button>
<Feedback v-model:visible="modal.visible" mode="modal" :okButtonProps="{ disabled: !modal.value }" :title="modal.showThanks ? ' ' : 'What is your feedback on this product?'" type="custom" @ok="handleOk(modal)">
<template v-if="modal.showThanks" #footer />
<Empty v-if="modal.showThanks" :style="emptyStyle">
<template #image>
<IllustrationSuccess :style="imageStyle" />
</template>
<template #darkModeImage>
<IllustrationSuccessDark :style="imageStyle" />
</template>
<template #description>感谢您的反馈</template>
</Empty>
<template v-else>
<span>这是一段自定义的内容</span>
<TextArea v-model="modal.value" />
</template>
</Feedback>
</div>
</template>API 参考
FeedbackProps
除去下面参数列表所列参数外,当 mode 为 modal 时, FeedbackProps 还支持 ModalProps 中的参数,当 mode 为 popup 时, FeedbackProps 还支持 SideSheetProps 中的参数
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| mode | 展示模式:popup 是底部无遮罩的非模态面板(SideSheet),modal 是模态对话框(Modal)。未声明的属性按模式落到对应的 SideSheet 或 Modal 上。 | FeedbackMode | semiDefault("Feedback", "mode", "popup") |
| type | 反馈内容的类型。custom 时内容写在默认插槽中。 | FeedbackType | semiDefault("Feedback", "type", "emoji") |
| visible | 是否显示,配合 v-model:visible 使用。 | boolean | semiDefault("Feedback", "visible", false) |
| title | 纯文本标题,同时作为对话框的可访问名称;同时给出 title 插槽时以插槽为准。 | string | semiGlobalDefault("Feedback", "title") |
| textAreaProps | type 为 text 与 emoji 时多行输入框的属性。受控值键为 modelValue,监听键为 onChange;传入的 modelValue 优先于 Feedback 的内部值。 | FeedbackTextAreaProps | semiGlobalDefault("Feedback", "textAreaProps") |
| radioGroupProps | type 为 radio 时单选组的属性,写法同 RadioGroup 的属性。选项组默认没有可访问名称,请用 aria-label 命名。 | FeedbackRadioGroupProps | semiGlobalDefault("Feedback", "radioGroupProps") |
| checkboxGroupProps | type 为 checkbox 时多选组的属性,写法同 CheckboxGroup 的属性。选项组默认没有可访问名称,请用 aria-label 命名。 | FeedbackCheckboxGroupProps | semiGlobalDefault("Feedback", "checkboxGroupProps") |
| okButtonProps | 提交按钮的属性。未给 disabled 时按值禁用(值为空时禁用),给出后以使用方的值为准,type 为 custom 时用它控制提交;loading 取内置的挂起态与使用方的 loading 任一为真;onClick 先于内置处理调用,不会替换内置处理。 | ModalButtonProps | semiGlobalDefault("Feedback", "okButtonProps") |
| cancelButtonProps | 取消按钮的属性。loading 取内置的挂起态与使用方的 loading 任一为真;onClick 先于内置处理调用,不会替换内置处理。 | ModalButtonProps | semiGlobalDefault("Feedback", "cancelButtonProps") |
| onOk | 点击提交按钮时调用,返回后清空已填写的值;返回 Promise 时按钮保持加载,fulfill 后才清空,reject 时保留。组件不会自行关闭,由使用方把 visible 设为 false。保留为函数 prop 以读取返回值,使用方照常写 @ok。 | Type((event: MouseEvent) => void | Promise<unknown>) | undefined |
| onCancel | 取消按钮、关闭按钮、Esc(modal 模式另有点击遮罩)触发;按 Esc 时参数为原生 KeyboardEvent。返回后清空已填写的值并更新 v-model:visible;返回 Promise 时取消按钮保持加载,fulfill 后才清空并更新,reject 时保持打开。保留为函数 prop 以读取返回值,使用方照常写 @cancel。 | Type((event: MouseEvent | KeyboardEvent) => void | Promise<unknown>) | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:visible | 取消路径(取消按钮、关闭按钮、Esc,modal 模式另有遮罩)完成后触发,值为 false,供 v-model:visible 回写。提交按钮只调用 onOk,不触发该事件。 | [visible: boolean] |
| valueChange | 反馈内容变化时触发,载荷为当前值:text 为字符串,emoji 为 { emoji, text }(text 是选了「差」后填写的原因),radio 为所选项的值,checkbox 为所选值的数组。 | [value: FeedbackValue] |
| afterClose | 弹层完全关闭后触发,两种模式都会触发。 | [] |
| afterVisibleChange | 显示状态变化且动画结束后触发,仅 popup 模式发出。 | [visible: boolean] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | type 为 custom 时的反馈内容。 | any |
| content | 包裹或替换内置内容,任何 type 都可用,参数 content 是内置内容的 VNode,用 <component :is="content" /> 放置。 | FeedbackContentSlotProps |
| title | 标题,优先于 title 属性。 | any |
| footer | 替换默认的取消、提交按钮。传入空插槽时不渲染页脚区域。 | any |
| closeIcon | 关闭按钮中的图标。 | any |
| header | 仅 modal 模式:完全替换默认头部。 | any |
| icon | 仅 modal 模式:标题前的图标。 | any |
| modal | 仅 modal 模式:自定义渲染对话框本身,参数 modal 是 role=dialog 元素的 VNode,用 <component :is="modal" /> 放置。 | FeedbackModalSlotProps |
| radioLabel | 自定义 radioGroupProps.options 中每一项的文本,作用域参数为 option 与 index。 | RadioGroupOptionSlotProps |
| radioExtra | 自定义 radioGroupProps.options 中每一项的辅助文本,作用域参数为 option 与 index。 | RadioGroupOptionSlotProps |
| checkboxLabel | 自定义 checkboxGroupProps.options 中每一项的文本,作用域参数为 option 与 index。 | CheckboxGroupOptionSlotProps |
| checkboxExtra | 自定义 checkboxGroupProps.options 中每一项的辅助文本,作用域参数为 option 与 index。 | CheckboxGroupOptionSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | Portal 内 Modal 或 SideSheet 的最外层元素,未渲染时为 null。 | HTMLDivElement | null |
未声明的属性按 mode 透传给 Modal 或 SideSheet,落点与它们相同:全部 aria-* 属性落在 role="dialog" 元素上;style 在 modal 模式落在 .semi-modal 对话框盒子上,在 popup 模式落在 role="dialog" 元素上;class 与其余未声明的属性、原生事件监听落在 portal 内最外层元素上(modal 模式的 role 同样落在 role="dialog" 元素上)。textAreaProps、radioGroupProps、checkboxGroupProps 的受控值键是 modelValue,监听键是 onChange。
Accessibility
ARIA
- emoji 类型的表情是
role="radiogroup"(名称来自语言包Feedback.rating)中的原生input type="radio"(名称来自Feedback.bad、Feedback.normal、Feedback.good),选中状态由原生checked表达,遵循 APG Radio Group - 单选、多选类型的选项组默认没有可访问名称,可通过
radioGroupProps、checkboxGroupProps的aria-label命名 modal模式遵循 APG Dialog (Modal),细节同 Modal;popup模式是不带遮罩的 SideSheet,按非模态对话框处理,不设置aria-modal
键盘和焦点
- emoji 类型的表情组只有一个 Tab 停靠点,方向键切换选中的表情,键盘聚焦时表情显示主题焦点环。单选、多选类型的键盘操作沿用 RadioGroup 与 CheckboxGroup
popup模式打开时焦点移入反馈面板,但不限制 Tab,页面其余部分保持可用;按 Esc 触发取消。关闭时只在焦点仍在面板内或已落到 body 时归还给打开前的元素,用户已移到页面其他位置的焦点不动modal模式打开时焦点移入对话框,Tab 在对话框内循环,背后的页面不可交互;关闭后焦点回到打开前的元素,按 Esc 触发取消