反馈类

反馈

快速定义各类型反馈

代码演示

如何引入

<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 上。FeedbackModesemiDefault("Feedback", "mode", "popup")
type反馈内容的类型。custom 时内容写在默认插槽中。FeedbackTypesemiDefault("Feedback", "type", "emoji")
visible是否显示,配合 v-model:visible 使用。booleansemiDefault("Feedback", "visible", false)
title纯文本标题,同时作为对话框的可访问名称;同时给出 title 插槽时以插槽为准。stringsemiGlobalDefault("Feedback", "title")
textAreaPropstype 为 text 与 emoji 时多行输入框的属性。受控值键为 modelValue,监听键为 onChange;传入的 modelValue 优先于 Feedback 的内部值。FeedbackTextAreaPropssemiGlobalDefault("Feedback", "textAreaProps")
radioGroupPropstype 为 radio 时单选组的属性,写法同 RadioGroup 的属性。选项组默认没有可访问名称,请用 aria-label 命名。FeedbackRadioGroupPropssemiGlobalDefault("Feedback", "radioGroupProps")
checkboxGroupPropstype 为 checkbox 时多选组的属性,写法同 CheckboxGroup 的属性。选项组默认没有可访问名称,请用 aria-label 命名。FeedbackCheckboxGroupPropssemiGlobalDefault("Feedback", "checkboxGroupProps")
okButtonProps提交按钮的属性。未给 disabled 时按值禁用(值为空时禁用),给出后以使用方的值为准,type 为 custom 时用它控制提交;loading 取内置的挂起态与使用方的 loading 任一为真;onClick 先于内置处理调用,不会替换内置处理。ModalButtonPropssemiGlobalDefault("Feedback", "okButtonProps")
cancelButtonProps取消按钮的属性。loading 取内置的挂起态与使用方的 loading 任一为真;onClick 先于内置处理调用,不会替换内置处理。ModalButtonPropssemiGlobalDefault("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

插槽说明作用域参数
defaulttype 为 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

名称说明类型
rootPortal 内 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 触发取消