Input 输入

用于对话的输入框组件

按需引入路径:

ts
import { McInput } from '@matechat/core';

基本用法

绑定 value 等基本参数进行使用。

0/2000
vue
<template>
  <McInput :value="inputValue" :maxLength="2000" :loading="loading" showCount @change="onInputChange" @submit="onSubmit" @cancel="onCancel">
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onInputChange = (e) => {
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  console.log('input submit---', e);
};
const onCancel = () => {
  loading.value = false;
  console.log('input cancel');
};
</script>

展示形态

通过displayType参数设置展示形态,支持的值为fullsimple,默认为full

full形态,prefix 插槽和输入框在同一行,extra 插槽和发送按钮在下方。

simple形态,prefix 插槽、输入框和发送按钮在同一行,不支持 extra 插槽。

variant参数设置为borderless,可设置不带边框。

通过sendBtnVariant参数控制发送按钮的形态,支持的值为fullsimple,默认为full

vue
<template>
  <McInput :value="inputValue" displayType="simple" :loading="loading" sendBtnVariant="simple" variant="borderless" @submit="onSubmit">
    <template #suffix>
      <div class="input-prefix-wrap">
        <i class="icon-appendix"></i>
      </div>
    </template>
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onSubmit = (e) => {
  loading.value = true;
  setTimeout(() => {
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
</script>

<style scoped lang="scss">
.input-prefix-wrap {
  height: 32px;
  line-height: 32px;
  margin-right: 8px;
  cursor: pointer;
}
</style>

提交模式

通过submitShortKey设置提交快捷键,支持的值为entershiftEnter,默认为enter

当提交快捷键为enter时,换行快捷键为shift+enter;当提交快捷键为shift+enter时,换行快捷键为enter

vue
<template>
  <McInput :value="inputValue" :loading="loading" submitShortKey="shiftEnter" @submit="onSubmit"> </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onSubmit = (e) => {
  loading.value = true;
  setTimeout(() => {
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
</script>

自定义发送按钮

通过button插槽自定义发送按钮,实现按钮 disable、loading 等状态和按钮图标、按钮文案的自定义。

0/2000
发送
vue
<template>
  <McInput :value="inputValue" :maxLength="2000" :loading="loading" showCount @change="onInputChange" @submit="onSubmit" @cancel="onCancel">
    <template #button>
      <div
        class="my-button"
        :class="{ 'disabled': !loading && !inputValue}"
        @click="onConfirm"
      >
        <span class="mc-button-content">
          <!-- 此处可自定义图标及其文案 -->
          <span>{{ loading ? '停止' : '发送' }}</span>
        </span>
      </div>
    </template>
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onInputChange = (e) => {
  inputValue.value = e;
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  inputValue.value = '';
  setTimeout(() => {
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
const onCancel = () => {
  loading.value = false;
  console.log('input cancel');
};

const onConfirm = () => {
   if(loading.value) {
    onCancel();
   } else {
    onSubmit();
   }
}
</script>

<style scoped lang="scss">
.my-button {
  display: flex;
  align-items: center;
  height: 32px;
  background: #5e7ce0;
  padding: 0 16px;
  border-radius: 20px;
  color: #fff;
}

.disabled {
  background: #beccfa;
}
</style>

自动调整高度

通过 autosize 属性让文本域自动调整高度,支持布尔值和配置对象两种形式。

  • 设置为 true:使用默认配置(最小1行,最大5行)
  • 设置为对象:可自定义最小和最大行数,如 { minRows: 2, maxRows: 10 }

默认自动调整(最小1行,最大5行)

自定义行数范围(最小2行,最大10行)

禁用自动调整

vue
<template>
  <div class="autosize-demo">
    <h4>默认自动调整(最小1行,最大5行)</h4>
    <McInput
      :value="inputValue1"
      autosize
      placeholder="输入多行文本查看自动调整效果..."
      @change="onChange1"
    />

    <h4>自定义行数范围(最小2行,最大10行)</h4>
    <McInput
      :value="inputValue2"
      :autosize="{ minRows: 2, maxRows: 10 }"
      placeholder="输入多行文本查看自定义行数效果..."
      @change="onChange2"
    />

    <h4>禁用自动调整</h4>
    <McInput
      :value="inputValue3"
      :autosize="false"
      placeholder="固定高度的文本域"
      @change="onChange3"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';

const inputValue1 = ref('');
const inputValue2 = ref('');
const inputValue3 = ref('');

const onChange1 = (e) => {
  inputValue1.value = e;
};

const onChange2 = (e) => {
  inputValue2.value = e;
};

const onChange3 = (e) => {
  inputValue3.value = e;
};
</script>

<style scoped lang="scss">
.autosize-demo {
  h4 {
    margin: 20px 0 10px;
    color: var(--devui-text);
    font-size: 14px;
  }
}
</style>

自动聚焦

通过 autofocus 属性设置输入框在组件挂载后自动获得焦点,默认为 false。当输入框被禁用时,自动聚焦不会生效。

vue
<template>
  <McInput :value="inputValue" autofocus :loading="loading" @change="onInputChange" @submit="onSubmit" @cancel="onCancel">
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onInputChange = (e) => {
  inputValue.value = e;
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  inputValue.value = '';
  setTimeout(() => {
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
const onCancel = () => {
  loading.value = false;
  console.log('input cancel');
};
</script>

提交时不自动清空输入

通过 autoClear 属性设置输入框在提交后是否自动清空内容,默认为 true。 可以通过 clearInput 方法手动清空输入框内容。

vue
<template>
  <McInput ref="mcInputRef" :value="inputValue" :autoClear="false" :loading="loading" @submit="onSubmit" @cancel="onCancel">
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const mcInputRef = ref();
const inputValue = ref('');
const loading = ref(false);

const onSubmit = (e) => {
  loading.value = true;
  setTimeout(() => {
    // 发送成功后手动清空输入框内容
    mcInputRef.value.clearInput();
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
const onCancel = () => {
  loading.value = false;
  console.log('input cancel');
};
</script>

插入主题标签

通过 ThemeTagItem 类型配置前置主题标签,支持自定义主题标签的文本内容、pop弹出提示内容等。 当前仅支持最多设置一个ThemeTag,且必须放在 formatContent 数组的第一个位置。 可通过 themeTag 插槽自定义主题标签的展示效果。

vue
<template>
  <div class="button-wrapper">
    <d-button @click="openThemeTag" style="margin-right: 8px;">插入主题标签</d-button> <d-button @click="closeThemeTag">关闭主题标签</d-button>
  </div>
  <McInput :formatContentOptions="formatContentOptions" @change="onInputChange" @submit="onSubmit">
    <template #themeTag="{ themeTag }">
      <span class="tip-tag-custom">
        <i class="icon-code-editor-close"></i>
        <span :class="['tip-tag-icon', 'icon-default']"></span>
        <span id="ai-input-prefix" class="ai-input-prefix">{{themeTag.themeTagText}}</span>
      </span>
    </template>
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const loading = ref(false);
const formatContentOptions = ref({
});
const onInputChange = (e) => {
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  console.log('input submit---', e);
};

const openThemeTag = () => {
  formatContentOptions.value = {
    formatContent: [
      {
        type: 'themeTag',
        themeTagKey: 'themeTag',// 主题标签的唯一标识
        themeTagText: '动图生成', // 主题标签的文本内容
        clearInput: false, // 关闭主题标签时是否清空对应输入框内容
        popoverContent: '点击退出技能', // 主题标签的pop弹出提示内容
      }]
  };
}

const closeThemeTag = () => {
  formatContentOptions.value = {
    formatContent: []
  };
}

</script>

<style scoped lang="scss">
  .button-wrapper {
    margin-bottom: 12px;
  }

  .tip-tag-custom {
    &:hover {
      i {
        display: inline-block;
      }

      .tip-tag-icon {
        display: none;
      }

    }
    i {
      cursor: pointer;
      width: 16px;
      height: 16px;
      margin-right: 4px;
      vertical-align: middle;
      display: none;
    }

    .tip-tag-icon {
      width: 16px;
      height: 16px;
      margin-right: 4px;
      display: inline-block;
      vertical-align: text-bottom;
      background-size: 100% 100%;
      &.icon-default {
        background-image: url('/logo.svg'); // 补一个默认图标
      }
    }
  }
</style>

插入text文本

通过 FormatTextItem 类型可插入一段文本,且支持插入多段文本。

vue
<template>
  <div class="button-wrapper">
    <d-button @click="setText">插入text文本</d-button>
  </div>
  <McInput :formatContentOptions="formatContentOptions" @change="onInputChange" @submit="onSubmit">
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const formatContentOptions = ref({
});
const loading = ref(false);

const onInputChange = (e) => {
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  console.log('input submit---', e);
};

const setText = () => {
  formatContentOptions.value = {
    formatContent: [
      {
        key: '',
        type: 'text',
        content: 'MateChat:生成式人工智能 体验设计系统&前端解决方案!!!',
        placeholder: '',
      },
      {
        key: '',
        type: 'text',
        content: '欢迎使用与共建MateChat!!!',
        placeholder: '',
      },
    ],
  };
}

</script>

<style scoped lang="scss">
  .button-wrapper {
    margin-bottom: 12px;
  }
</style>

插入格式化Input标签

通过 FormatInputItem 类型配置一个input标签,实现对输入框内某些局部文本的默认填充或占位提示;input标签可以插入多个,且插入位置不固定。

vue
<template>
  <div class="button-wrapper">
    <d-button @click="setInput">插入Input标签</d-button>
  </div>
  <McInput :formatContentOptions="formatContentOptions" @change="onInputChange" @submit="onSubmit">
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';
const formatContentOptions = ref({
});
const loading = ref(false);

const onInputChange = (e) => {
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  console.log('input submit---', e);
};

const setInput = () => {
  formatContentOptions.value = {
    formatContent: [
      {
        key: '',
        type: 'text',
        content: '我是',
        placeholder: '',
      },
      {
        key: 'input1',
        type: 'input',
        placeholder: '请输入专业',
        content: '计算机科学',
      },
      {
        key: '',
        type: 'text',
        content: '专业的本科生,帮我写一篇关于',
        placeholder: '',
      },
      {
        key: 'input2',
        type: 'input',
        placeholder: '请输入主题',
        content: '',
      },
      {
        key: '',
        type: 'text',
        content: '的论文。',
        placeholder: '',
      },
    ],
  };
}

</script>

<style lang="scss">
  .button-wrapper {
    margin-bottom: 12px;
  }
</style>

多种格式化内容自定义编排

通过 FormatContentOptions.formatContent 中多种格式化标签的自定义组合编排,按需实现对输入框内文本的多种格式化展示。

vue
<template>
  <div class="button-wrapper">
    <d-button @click="setMixTags">自定义编排插入</d-button>
  </div>
  <McInput :formatContentOptions="formatContentOptions" @change="onInputChange" @submit="onSubmit">
    <template #themeTag="{ themeTag }">
      <span class="tip-tag-custom">
        <i class="icon-code-editor-close"></i>
        <span :class="['tip-tag-icon', 'icon-default']"></span>
        <span id="ai-input-prefix" class="ai-input-prefix">{{themeTag.themeTagText}}</span>
      </span>
    </template>
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const loading = ref(false);
const formatContentOptions = ref({
});
const onInputChange = (e) => {
  console.log('input change---', e);
};
const onSubmit = (e) => {
  loading.value = true;
  console.log('input submit---', e);
};


const mixTags = [
  {
    type: 'themeTag',
    themeTagKey: 'themeTag',// 主题标签的唯一标识
    themeTagText: '文章生成', // 主题标签的文本内容
    clearInput: true, // 关闭主题标签时是否清空对应输入框内容
    popoverContent: '点击关闭主题', // 主题标签的pop弹出提示内容
  },
  {
    key: '',
    type: 'text',
    content: '帮我写一篇面向',
    placeholder: '',
  },
  {
    key: 'input1',
    type: 'input',
    placeholder: '输入目标人群',
    content: '职场人士',
  },
  {
    key: '',
    type: 'text',
    content: '关于',
    placeholder: '',
  },
  {
    key: 'input2',
    type: 'input',
    placeholder: '输入产品',
    content: '',
  },
  {
    key: '',
    type: 'text',
    content: '的宣传文案,需要直击痛点,吸引用户点击。',
    placeholder: '',
  },
];

const setMixTags = () => {
  formatContentOptions.value = {
    formatContent: mixTags,
  };
}

</script>

<style lang="scss">
  .button-wrapper {
    margin-bottom: 12px;
  }

  .tip-tag-custom {
    &:hover {
      i {
        display: inline-block;
      }

      .tip-tag-icon {
        display: none;
      }

    }
    i {
      cursor: pointer;
      width: 16px;
      height: 16px;
      margin-right: 4px;
      vertical-align: middle;
      display: none;
    }

    .tip-tag-icon {
      width: 16px;
      height: 16px;
      margin-right: 4px;
      display: inline-block;
      vertical-align: text-bottom;
      background-size: 100% 100%;
      &.icon-default {
        background-image: url('/logo.svg'); // 补一个默认图标
      }
    }
  }
</style>

自定义插槽

通过head插槽自定义输入框顶部的内容,通过extra自定义发送按钮左侧的内容。

README.md
智能体附件
vue
<template>
  <McInput :value="inputValue" :loading="loading" @submit="onSubmit">
    <template #head>
      <div class="appendix-wrap">
        <div class="appendix-item">
          <span>README.md</span>
          <i class="icon-code-editor-close"></i>
        </div>
      </div>
    </template>
    <template #extra>
      <div class="input-foot-left">
        <span><i class="icon-at"></i>智能体</span>
        <span><i class="icon-appendix"></i>附件</span>
      </div>
    </template>
  </McInput>
</template>

<script setup>
import { defineComponent, ref } from 'vue';

const inputValue = ref('');
const loading = ref(false);

const onSubmit = (e) => {
  loading.value = true;
  setTimeout(() => {
    loading.value = false;
  }, 1000);
  console.log('input submit---', e);
};
</script>

<style scoped lang="scss">
.input-foot-left {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--devui-font-size-sm);
  color: var(--devui-text);

  i {
    margin-right: 4px;
  }
}

.appendix-wrap {
  display: flex;
  padding: 4px 16px;

  .appendix-item {
    padding: 4px 8px;
    border-radius: var(--devui-border-radius);
    background-color: var(--devui-area);

    i {
      margin-left: 4px;
      cursor: pointer;
    }
  }
}
</style>