本周继续开发模拟面试的ai聊天界面
关于悬停显示bug
上一次开发过程中,我们加入了用户气泡的编辑和重新生成的功能,并且参照一般ai聊天的界面设计把这两个按钮放到了用户气泡左侧。但是这里的代码是有问题的。
主要问题
这里存在三个问题:
- CSS选择器问题:CSS选择器没有正确匹配悬停事件与按钮显示之间的关系
- 条件显示逻辑:按钮的显示条件正确,但与CSS交互有问题
v-show="message.showActions || message.editing"
- CSS过渡设置:
message-actions
的visibility
和opacity
转换可能有冲突
解决方案
- 修改消息组件中的操作按钮显示逻辑
<!-- 修改前 -->
<div v-if="message.role === 'user'" class="message-actions" v-show="message.showActions || message.editing">
<!-- 按钮内容 -->
</div>
<!-- 修改后 -->
<div v-if="message.role === 'user'" class="message-actions" :class="{'show': message.showActions || message.editing}">
<!-- 按钮内容 -->
</div>
修改这部分代码,不再使用v-show来控制显示,而是通过CSS类来控制可见性。
- 修改CSS样式
/* 修改前 */
.message-actions {
display: flex;
align-items: center;
gap: 8px;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
margin: 0 8px;
}
.user-message .message-content-wrapper:hover .message-actions,
.message-actions.show {
opacity: 1;
visibility: visible;
}
/* 修改后 */
.message-actions {
display: flex;
align-items: center;
gap: 8px;
opacity: 0;
transition: opacity 0.3s ease;
margin: 0 8px;
}
.message:hover .message-actions,
.message-actions.show {
opacity: 1;
}
.edit-actions {
display: flex;
gap: 8px;
opacity: 1;
}
- 移除了
visibility: hidden
,因为这会阻止鼠标事件 - 简化了过渡效果
- 修改了悬停选择器,使用
.message:hover
而不是.message-content-wrapper:hover
- 修改鼠标事件监听器
确保鼠标事件添加到整个消息容器,而不仅仅是内容包装器:
<div v-for="(message, index) in messageListForShow" :key="index"
:class="['message', message.role === 'user' ? 'user-message' : 'ai-message']"
@mouseenter="message.showActions = true"
@mouseleave="message.showActions = false">
<!-- 消息内容 -->
</div>
新的问题
上述代码确实可以解决按钮显示的问题,但也产生了新的问题:
当用户点击显示分支后再收起分支,之后将鼠标移动到其他位置,用户气泡左侧的两个按钮不隐藏了。
这个问题是因为在切换分支显示状态时,message.showActions
的值没有被正确重置。当点击"显示分支"或"收起分支"按钮时,message.showActions
的true
可能被设置为并且没有机会被重置回false
。
这里我选择使用CSS限制showActions的应用范围的方案
修改CSS,让类只在鼠标悬停时生效:.show
.message:not(:hover) .message-actions:not(:has(.edit-actions)) {
opacity: 0 !important;
}
/* 编辑状态下的按钮总是显示 */
.message .message-actions:has(.edit-actions) {
opacity: 1 !important;
}
最终展示
通过解决上述问题,我们就可以实现,当用户的鼠标移动到气泡附近时按钮显示,反之则不显示
显示分支优化
伸缩式分支显示区域实现
目前,分支面板设置了固定宽度。为了让分支显示区域能够根据分支数量自动调整大小,我们需要修改分支面板的 CSS 和布局结构。
修改 HTML 结构
<!-- 分支编辑面板 -->
<div v-if="message.showBranchTag && !isLoading" class="branch-edit-panel"
:class="{ 'user-branch-panel': message.role === 'user' }">
<div class="branch-tag-list">
<div v-for="(sibling, idx) in siblingNodes.find(node => node.branchId === message.branchId)?.siblings || []"
:key="sibling.index" class="branch-tag-item"
:class="{ 'active-branch': sibling.index === currentBranchIndex }">
<!-- 显示模式 -->
<template v-if="!sibling.editing">
<span class="branch-tag-text" @click="switchBranch(sibling.index)">{{ sibling.tag }}</span>
<el-button type="text" size="mini" @click="startEditBranchTag(sibling)" class="edit-branch-btn">
<i class="el-icon-edit"></i>
</el-button>
</template>
<!-- 编辑模式 -->
<template v-else>
<el-input v-model="sibling.tag" size="mini" class="branch-tag-input"
@keyup.enter.native="saveBranchTag(sibling, message)"></el-input>
<div class="branch-tag-actions">
<el-button type="text" size="mini" @click="cancelEditBranchTag(sibling)">取消</el-button>
<el-button type="text" size="mini" @click="saveBranchTag(sibling, message)">保存</el-button>
</div>
</template>
</div>
</div>
</div>
CSS 修改方案
/* 分支编辑面板 - 自适应大小 */
.branch-edit-panel {
margin-top: 10px;
background-color: #f9fafc;
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
/* 移除固定宽度,使用自适应宽度 */
display: inline-block;
min-width: 200px;
max-width: 90%;
transition: all 0.3s ease;
align-self: flex-start;
}
.user-branch-panel {
align-self: flex-end;
}
/* 分支标签列表 - 弹性布局 */
.branch-tag-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: flex-start;
}
/* 分支标签项 */
.branch-tag-item {
display: inline-flex;
align-items: center;
background-color: #f5f7fa;
border-radius: 20px;
padding: 4px 12px 4px 4px;
border: 1px solid #ebeef5;
transition: all 0.2s ease;
/* 确保长文本能够适应空间 */
max-width: 100%;
overflow: hidden;
}
/* 分支标签文本 */
.branch-tag-text {
padding: 4px 8px;
cursor: pointer;
border-radius: 16px;
background-color: #fff;
margin-right: 8px;
border: 1px solid #ebeef5;
font-size: 12px;
transition: all 0.2s ease;
/* 确保长文本能够适应空间 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px; /* 限制最大宽度,避免太长的标签文本 */
}
关键改进
- 移除固定宽度:将分支面板从固定宽度改为
inline-block
和最小/最大宽度限制,让它根据内容自动调整 - 弹性布局:使用flex布局让分支标签能够自动换行和调整
- 文本溢出处理:对于长文本使用
text-overflow: ellipsis
防止破坏布局 - 响应式设计:设置最大宽度为百分比值,确保在不同屏幕尺寸下正常显示
编辑功能的按钮位置更改
总体来说和更改分支显示的思路差不多
将编辑确定取消按钮移至输入框右下角
要将编辑状态下的确定和取消按钮移动到输入框的右下角,我们需要修改HTML结构和CSS样式。目前这些按钮位于用户气泡左侧,我们需要将它们重新定位到输入框内部的右下角。
1. HTML结构修改
首先,我们需要调整HTML结构,将确定和取消按钮移到输入框内部或附近的位置:
<div class="message-content-wrapper">
<div class="message-content">
<div v-if="!message.editing" class="message-text"
v-html="renderMarkdown(message.content.text, message.role)">
</div>
<div v-else class="edit-input-container">
<el-input type="textarea" :rows="3" v-model="message.editText" class="edit-input"></el-input>
<!-- 编辑状态下的按钮移到这里 -->
<div class="edit-actions">
<el-button size="mini" @click="cancelEdit(message)">取消</el-button>
<el-button size="mini" type="primary" @click="sendModifiedMessage(message)">确定</el-button>
</div>
</div>
</div>
<div v-if="message.role === 'user'" class="message-actions" :class="{'show': message.showActions || message.editing}">
<el-button v-if="!message.editing" type="text" icon="el-icon-edit"
@click="startEditMessage(message)"></el-button>
<el-button v-if="!message.editing" type="text" icon="el-icon-refresh"
@click="regenerateMessage(message)"></el-button>
<!-- 移除这里的编辑按钮 -->
</div>
</div>
- 创建了一个新的
edit-input-container
包裹输入框和按钮 - 将编辑操作按钮移动到了输入框附近
- 从原来的位置移除了编辑操作按钮
2. CSS样式添加
接下来,添加新的CSS样式,使按钮位于输入框的右下角:
/* 编辑输入框容器 */
.edit-input-container {
position: relative;
width: 100%;
padding-bottom: 40px; /* 为按钮留出空间 */
}
/* 编辑输入框 */
.edit-input {
width: 100%;
}
/* 编辑操作按钮 */
.edit-actions {
position: absolute;
bottom: 8px;
right: 8px;
display: flex;
gap: 8px;
justify-content: flex-end;
}
/* 确保消息内容在编辑状态下有足够空间 */
.message-content {
min-width: 250px;
transition: all 0.3s ease;
}
/* 调整用户消息的编辑样式 */
.user-message .edit-input-container .el-textarea__inner {
background-color: rgba(64, 158, 255, 0.05);
border-color: #409eff;
}
聊天界面风格美化
先放一张成品图
这里为所有功能展示图
这部分主要做的工作时利用浏览器的开发者工具对css元素进行更改。
虽然工作简单,但是不断调试视觉效果着实是个累活。
为了满足组长的要求,并且这也是创新项目实训的关键功能点,因此对这部分的开发慎而又慎。和小组成员不断地讨论,最终实现了现在的效果,也算是达到了预期。
不多赘述了(虽然一次性开发了六个多小时
)
技术收获
界面的开发不仅是对专业知识的考查,也间接地考量着开发者的审美。
前端设计是是介于平面设计和编程技术两者之间的边缘科学
。不仅涉及到美学,心理学,平面构成,色彩搭配等平面设计的方面的知识,还涉及到html,javascript,css,asp,php等编程语言技术方面的知识。只有综合运用多种知识,才能设计出视听特效,动感十足,富于个性的web页面,才能全面展现互联网这一新型媒体的独特魅力和多维空间的超强功能。
另外,我也辅助开发了一些script
方法,利用前后端接口进行对接这种工作在web课设和数据库课设中也是广泛应用,但是由于和其他小组成员混在一起,索性也就不再赘述了(其他成员大体都会讲到)
下周任务
开发社区服务,和其他成员对接功能