Vue实现一个textarea幽灵建议功能

不知道你有没有发现Bing AI聊天有个输入提示功能,在用户输入部分内容时后面会给出灰色提示文案。用户只要按下tab键就可以快速添加提示的后续内容。我将这个功能称为幽灵建议。接下来我将用Vue框架来实现这个功能。

布局样式

布局使用label标签作为容器,这样即使建议内容在上层,也不会影响输入框的输入。

html 复制代码
<label class="container">
  <textarea></textarea>
  <div class="ghost-content"></div>
</label>

样式需要确保输入框与建议内容容器除了颜色外都要一致。建议内容可以通过z-index: -1置于输入框底部,但要注意输入框必须是透明背景。

css 复制代码
.container {
  position: relative;
  display: block;
  width: 300px;
  height: 200px;
  font-size: 14px;
  line-height: 21px;
}
.container textarea {
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  font: inherit;
  color: #212121;
  background-color: #fff;
  outline: none;
}
.ghost-content {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  color: #212121;
  opacity: 0.3;
}

显示逻辑

显示逻辑比较简单,当输入框中显示输入内容时,找到匹配的内容后将其显示在建议容器中。以下是代码示例:

js 复制代码
import { ref } from 'vue'

const content = ref('') // 输入框内容
const ghostContent = ref('') // 建议内容
const suggestions = ['你好啊', '怎么学编程'] // 建议列表

const handleInput = () => {
  ghostContent.value = '' // 内容变化时,清空建议
  // 如果为空或者建议内容改变,则不进行后续匹配
  if (content.value === '') {
    return
  }
  const suggestion = suggestions.find((item) => item.startsWith(content.value))
  if (suggestion) {
    ghostContent.value = suggestion
  }
}

const handleTabKeydown = () => {
  // 监听tab键按下,将输入框内容设置为建议内容,同时清空建议内容
  content.value = ghostContent.value
  ghostContent.value = ''
}

按照以上代码的写法,已经可以实现幽灵建议的功能了。但还存在一个小问题,输入框内容和建议内容的重叠部分会显得比较粗。因此,最好将重叠部分的文字颜色设置为透明。我的解决方法是使用span标签来包裹重叠部分的内容,然后将span的文字样式设置为透明。此外,为了表示可以使用tab键,我在末尾添加了符号。改进后的代码如下:

js 复制代码
// 重复部分省略
// ...
const ghostHTML = ref('') // 建议内容HTML
const handleInput = () => {
  ghostContent.value = ''
  ghostHTML.value = ''
  if (content.value === '' || fromSuggestion) {
    fromSuggestion && (fromSuggestion = false)
    return
  }
  const suggestion = suggestions.find((item) => item.startsWith(content.value))
  if (suggestion) {
    ghostContent.value = suggestion
    ghostHTML.value = suggestion.replace(content.value, `<span>${content.value}</span>`) + ' →' // 显示内容替换
  }
}

const handleTabKeydown = () => {
  content.value = ghostContent.value
  ghostContent.value = ''
  ghostHTML.value = ''
}

最后,补充一下HTML代码。

html 复制代码
<label class="container">
  <textarea v-model="content" @input="handleInput" @keydown.tab.prevent="handleTabKeydown"></textarea>
  <div class="ghost-content" v-html="ghostHTML"></div>
</label>
  • 我们需要阻止tab按下的默认事件,按下tab键会导致切换到其他元素,使输入框失去焦点;
  • 使用v-html来绑定HTML内容。
相关推荐
大鸡爪几秒前
Vue3 组件库实战(五):Icon 图标组件的设计与实现
前端·vue.js
bluceli几秒前
前端测试实战指南:构建高质量代码的完整体系
前端·测试
行走的陀螺仪几秒前
前端公共库开发保姆级路线:从0到1复刻VueUse官方级架构(pnpm+Turbo+VitePress)
前端·架构
顽固_倔强1 分钟前
深入理解 Vue3 数据绑定实现原理
前端·面试
前端付豪1 分钟前
组件拆分重构 App.vue
前端·架构·代码规范
Wect2 分钟前
React 更新触发原理详解
前端·react.js·面试
cxxcode2 分钟前
Web 帧渲染与 DOM 准备
前端
光影少年2 分钟前
React Hooks的理解?常用的有哪些?
前端·react.js·掘金·金石计划
大鸡爪3 分钟前
Vue3 组件库实战(七):从本地到 NPM:版本管理与自动化发布指南(下)
前端·vue.js
幸福摩天轮4 分钟前
记录commonjs的一道面试题
前端