常见问题QA的前端代码

这个的后端代码参见此文

使用语言向量建立常见问题的模糊搜索-CSDN博客[这里是图片001]https://blog.csdn.net//article/details/144207262?spm=1001.2014.3001.5501

这段代码实现了一个简单的问答页面,页面分为左右两部分,左侧用于展示对话记录,右侧用于用户输入问题并提交,获取答案后在对应区域显示答案,同时会将每一轮的问答信息添加到对话记录中进行展示,整体通过 HTML 结构定义页面布局,结合 JavaScript 实现交互功能。

HTML 部分详细分析
  1. 文档结构与头部设置(<head>部分)

    问答测试

  • 首先通过<meta charset="UTF-8">指定了文档的字符编码为 UTF-8,确保能正确显示各种字符。
  • <title>标签定义了页面的标题为 "问答测试",会显示在浏览器的标题栏。
  • 内联的<style>标签中定义了页面的样式规则,用于控制页面元素的外观呈现。
  1. 页面主体结构(<body>部分)

    对话记录

    提交问题与答案显示

    请输入你的问题:

  • <body>标签内是页面的主体内容,整体采用了flex布局(由外层的.main-container类样式控制),将页面划分为左右两部分来展示不同的功能区域。
  • 左侧对话记录区域(.conversation-log-container
    • 包含一个<h2>标题标签,显示 "对话记录" 字样,用于提示该区域的作用。
    • 有一个空的<div>元素,其idconversationDiv,后续通过 JavaScript 动态往里面添加对话记录的具体内容。
  • 右侧提交问题与答案显示区域(.question-answer-container
    • 首先有一个<h1>标题标签,显示 "提交问题与答案显示",表明该区域功能。
    • 包含一个<form>表单元素,其idquestionFormaction属性指向"/process_question"(对应后端处理问题的接口,和之前 Python 代码中的服务器路由相关联),method属性为"post"表示以 POST 方式提交表单数据。表单内有一个<label>标签用于提示用户输入问题,一个<input>文本框用于用户输入具体问题(设置了required属性要求用户必须输入内容),还有一个<input>提交按钮用于提交表单。
    • 还有一个空的<div>元素,其idanswerDiv,用于在提交问题后通过 JavaScript 获取后端返回的答案并展示在此处。
CSS 样式部分详细分析(<style>内联样式)
  1. 页面整体样式(body选择器)

    body {

    font-family: Arial, sans-serif;

    background-color: #f4f4f4;

    display: flex;

    justify-content: center;

    align-items: center;

    min-height: 100vh;

    margin: 0;

    padding: 0;

    }

  • 设置了页面整体的字体为Arial或无衬线字体(sans-serif作为备选),背景颜色为浅灰色(#f4f4f4)。
  • 利用flex布局将页面内容在水平和垂直方向上进行居中对齐,设置最小高度为视口高度(100vh),并去除了页面默认的外边距和内边距。
  1. 主容器样式(.main-container选择器)

    .main-container {

    display: flex;

    width: 1000px;

    }

定义了主容器采用flex布局,宽度为1000px,用于划分左右两部分的功能区域。

3.左侧对话记录容器样式(.conversation-log-container选择器)

.conversation-log-container {
    background-color: #fff;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
    width: 450px;
    /* height: 1000px; */
}
  • 将对话记录容器的背景色设置为白色(#fff),添加了内边距为20px,设置了圆角边框(半径为5px)以及一个淡淡的阴影效果(box-shadow属性),使其在页面上有一定的立体感和视觉区分度。
  • 宽度设置为450px,可以根据实际需求调整这个宽度值,注释掉的height属性若启用可固定容器高度,目前采用默认高度由内容撑开的方式。
  1. 对话记录标题样式(h2.conversation-title选择器)

    h2.conversation-title {

    color: #333;

    }

设置对话记录标题的字体颜色为深灰色(#333),使其与整体页面风格协调且有一定的视觉层次。

5.对话记录展示区域样式(#conversationDiv选择器)

#conversationDiv {
    margin-top: 20px;
    max-height: 450px;
    overflow-y: auto;
    font-family: Arial, sans-serif;
}
  • 给对话记录展示区域添加了顶部外边距为20px,设置了最大高度为450px,并当内容超出这个高度时启用垂直滚动条(overflow-y: auto)来查看更多对话记录内容,字体同样遵循页面整体设置的Arial或无衬线字体风格。
  1. 对话记录单项样式(.conversation-item选择器)

    .conversation-item {

    margin-bottom: 10px;

    padding: 10px;

    border-bottom: 1px solid #ccc;

    white-space: pre-line; /* 让对话记录中的内容也能折行显示 */

    }

    .conversation-item:last-child {

    border-bottom: none;

    }

  • 每个对话记录单项有底部外边距为10px,内边距为10px,并且底部有一条浅灰色(#ccc)的边框用于区分不同的对话记录项,最后一项通过:last-child伪类去除了底部边框,使其视觉上更简洁。
  • white-space: pre-line属性设置让对话记录中的文本内容可以按照正常的文本换行规则进行折行显示,方便展示较长的问答内容。
  1. 问题文本样式(.question选择器)

    .question {

    font-weight: bold;

    }

将对话记录中的问题文本设置为加粗字体,便于区分问题和答案部分,增强可读性。

8.右侧提交问题与答案显示容器样式(.question-answer-container选择器)

.question-answer-container {
    background-color: #fff;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
    width: 550px;
    margin-left: 50px;
}

和左侧对话记录容器类似,设置了白色背景、内边距、圆角边框、阴影效果等,宽度设置为550px,并且通过margin-left属性设置了与左侧容器的间距为50px,使其在页面上合理布局。

9.右侧标题样式(h1.qa-title选择器)

h1.qa-title {
    color: #333;
}

设置右侧区域标题的字体颜色为深灰色(#333),保持页面整体视觉风格的一致性。

10.表单样式(form#questionForm选择器)

form#questionForm {
    text-align: center;
}

将表单内的元素在水平方向上进行居中对齐,让页面布局看起来更整齐美观。

11.标签样式(label选择器)

label {
    display: block;
    margin-bottom: 10px;
}

使每个<label>标签单独占一行显示,并设置了底部外边距为10px,方便页面排版和阅读提示信息。

12.输入框样式(input[type="text"]选择器)

input[type="text"] {
    width: 100%;
    padding: 10px;
    margin-bottom: 20px;
    border: 1px solid #ccc;
    border-radius: 3px;
}

定义了文本输入框的样式,宽度占满父容器(100%),添加了内边距为10px,底部外边距为20px,设置了浅灰色的边框以及较小的圆角边框效果,使其外观简洁且符合常见的输入框设计风格。

13.提交按钮样式(input[type="submit"]选择器)

input[type="submit"] {
    background-color: #007BFF;
    color: #fff;
    padding: 10px 20px;
    border: none;
    border-radius: 3px;
    cursor: pointer;
}

将提交按钮的背景色设置为蓝色(#007BFF,常见的按钮强调色),字体颜色为白色,添加了内边距,去除了边框,设置了小的圆角边框效果,并添加了鼠标指针悬停变为手型(cursor: pointer)的交互效果,使其在页面上很容易被识别和操作。

14.答案显示区域样式(#answerDiv选择器)

#answerDiv {
    white-space: pre-line;
    margin-top: 20px;
    word-break: break-all; /* 确保长文本能正常换行显示 */
}

和对话记录展示区域类似,设置了顶部外边距为20pxwhite-space: pre-line让内容可以按正常文本换行规则显示,同时添加了word-break: break-all属性确保长文本能在合适的位置正常换行,避免出现文本超出容器宽度而显示不全的情况。

JavaScript 部分详细分析
  1. 全局变量定义与表单提交事件监听

    // 用于存储对话记录的数组

    var conversation = [];

    document.getElementById('questionForm').addEventListener('submit', function (e) {

    e.preventDefault();

    var questionInput = document.getElementById('user_question');
    var questionText = questionInput.value;
    
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/process_question', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var answerDiv = document.getElementById('answerDiv');
            // 使用 innerHTML 将响应文本当作 HTML 内容解析,使图片、超链接等能正确显示
            answerDiv.innerHTML = xhr.responseText;
    
            // 将本次的问题和答案添加到对话记录数组中
            conversation.push({
                question: questionText,
                answer: xhr.responseText
            });
    
            // 清空输入框,方便继续提问
            questionInput.value = "";
    
            // 重新渲染对话记录展示区域
            renderConversation();
        }
    };
    xhr.send('user_question=' + encodeURIComponent(questionText));
    

    });

  • 首先定义了一个名为conversation的全局数组,用于存储每一轮问答的信息(问题和对应的答案)。
  • 通过document.getElementById获取到页面中的表单元素,并给其添加submit事件监听器。当用户提交表单时:
    • 调用e.preventDefault()阻止表单默认的提交行为,避免页面刷新。
    • 获取用户在输入框中输入的问题文本内容。
    • 创建一个XMLHttpRequest对象用于发送 HTTP 请求到后端("/process_question"这个接口,对应后端 Python 代码中处理问题的路由),设置请求方式为POST,并设置请求头的Content-Type"application/x-www-form-urlencoded"
    • xhr对象的onreadystatechange事件绑定回调函数,当请求的状态变为4(表示请求已完成)且状态码为200(表示成功)时:
      • 获取页面中用于显示答案的<div>元素,将后端返回的响应文本通过innerHTML属性赋值给该元素,这样可以解析响应文本中的 HTML 内容(比如如果答案中有图片、超链接等元素能正确显示)。
      • 将本次的问题和答案以对象的形式添加到conversation数组中。
      • 清空输入框内容,方便用户继续提问。
      • 调用renderConversation函数重新渲染对话记录展示区域,使其能及时更新显示最新的问答信息。
    • 最后通过xhr.send方法发送包含用户问题的请求数据,需要对问题文本进行encodeURIComponent编码,以符合 URL 编码规范。
  1. 对话记录渲染函数(renderConversation

    // 渲染对话记录展示区域的函数

    function renderConversation() {

    var conversationDiv = document.getElementById('conversationDiv');

    conversationDiv.innerHTML = "";

    conversation.forEach(function (item, index) {
        var conversationItem = document.createElement('div');
        conversationItem.className = 'conversation-item';
    
        var questionDiv = document.createElement('div');
        questionDiv.className = 'question';
        questionDiv.innerHTML = "Q" + (index + 1) + ": " + item.question;
    
        var answerDiv = document.createElement('div');
        answerDiv.className = 'answer';
        // 使用 innerHTML 将答案内容当作 HTML 内容解析,使图片等能正确显示
        answerDiv.innerHTML = "A" + (index + 1) + ": " + item.answer;
    
        conversationItem.appendChild(questionDiv);
        conversationItem.appendChild(answerDiv);
    
        conversationDiv.appendChild(conversationItem);
    });
    

    }

这个函数用于更新对话记录展示区域的内容,首先获取到idconversationDiv的元素,并清空其原有的innerHTML内容。然后遍历conversation数组中的每一项(每个问答对象):

  • 创建一个新的<div>元素作为对话记录单项的容器,并设置其类名为conversation-item,以应用对应的 CSS 样式。
  • 分别创建用于显示问题和答案的<div>子元素,设置相应的类名(questionanswer),并通过innerHTML将问答内容填充进去,同样可以解析 HTML 内容。
  • 将问题和答案的<div>子元素添加到对话记录单项容器中,再将该容器添加到对话记录展示区域的<div>元素内,从而实现对话记录的动态渲染和展示。
潜在的改进点和注意事项
  • 兼容性问题 :代码中使用的XMLHttpRequest在现代浏览器中基本都支持,但对于一些较老版本的浏览器可能存在兼容性问题。可以考虑使用更现代的fetchAPI 来替代,它提供了更简洁、功能更强大的异步请求方式,并且有较好的浏览器兼容性(不过需要进行适当的错误处理和功能适配)。
  • 安全性考虑 :在将后端返回的内容直接通过innerHTML解析并显示时,如果后端返回的数据不可信(比如存在恶意的 HTML、JavaScript 代码),可能会导致安全漏洞,如跨站脚本攻击(XSS)。建议对后端返回的数据进行严格的过滤和转义处理,只允许显示安全的文本内容或者对 HTML 标签进行白名单验证后再进行解析显示。
  • 响应数据格式处理优化 :目前假设后端返回的文本可以直接通过innerHTML进行解析显示,但如果后端返回的数据格式比较复杂(比如是 JSON 格式包含了多种类型的数据需要分别处理),需要进一步优化代码逻辑,对响应数据进行准确的解析和展示,例如可以通过JSON.parse先将 JSON 数据解析成 JavaScript 对象,再根据具体的结构进行相应的页面渲染操作。

完整代码如下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>问答测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            padding: 0;
        }

      .main-container {
            display: flex;
            width: 1000px;
        }

        /* 左侧对话记录样式 */
      .conversation-log-container {
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
            width: 450px;
            /* height: 1000px; */
        }

        h2.conversation-title {
            color: #333;
        }

        #conversationDiv {
            margin-top: 20px;
            max-height: 450px;
            overflow-y: auto;
            font-family: Arial, sans-serif;
        }

      .conversation-item {
            margin-bottom: 10px;
            padding: 10px;
            border-bottom: 1px solid #ccc;
            white-space: pre-line; /* 让对话记录中的内容也能折行显示 */
        }

      .conversation-item:last-child {
            border-bottom: none;
        }

      .question {
            font-weight: bold;
        }

        /* 右侧提交问题和答案显示样式 */
      .question-answer-container {
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
            width: 550px;
            margin-left: 50px;
        }

        h1.qa-title {
            color: #333;
        }

        form#questionForm {
            text-align: center;
        }

        label {
            display: block;
            margin-bottom: 10px;
        }

        input[type="text"] {
            width: 100%;
            padding: 10px;
            margin-bottom: 20px;
            border: 1px solid #ccc;
            border-radius: 3px;
        }

        input[type="submit"] {
            background-color: #007BFF;
            color: #fff;
            padding: 10px 20px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }

        #answerDiv {
            white-space: pre-line;
            margin-top: 20px;
            word-break: break-all; /* 确保长文本能正常换行显示 */
        }
    </style>
</head>

<body>
    <div class="main-container">
        <div class="conversation-log-container">
            <h2 class="conversation-title">对话记录</h2>
            <div id="conversationDiv"></div>
        </div>
        <div class="question-answer-container">
            <h1 class="qa-title">提交问题与答案显示</h1>
            <form id="questionForm" action="/process_question" method="post">
                <label for="user_question">请输入你的问题:</label><br>
                <input type="text" id="user_question" name="user_question" required><br>
                <input type="submit" value="提交">
            </form>
            <div id="answerDiv"></div>
        </div>
    </div>

    <script>
        // 用于存储对话记录的数组
        var conversation = [];

        document.getElementById('questionForm').addEventListener('submit', function (e) {
            e.preventDefault();

            var questionInput = document.getElementById('user_question');
            var questionText = questionInput.value;

            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/process_question', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var answerDiv = document.getElementById('answerDiv');
                    // 使用 innerHTML 将响应文本当作 HTML 内容解析,使图片、超链接等能正确显示
                    answerDiv.innerHTML = xhr.responseText;

                    // 将本次的问题和答案添加到对话记录数组中
                    conversation.push({
                        question: questionText,
                        answer: xhr.responseText
                    });

                    // 清空输入框,方便继续提问
                    questionInput.value = "";

                    // 重新渲染对话记录展示区域
                    renderConversation();
                }
            };
            xhr.send('user_question=' + encodeURIComponent(questionText));
        });

        // 渲染对话记录展示区域的函数
        function renderConversation() {
            var conversationDiv = document.getElementById('conversationDiv');
            conversationDiv.innerHTML = "";

            conversation.forEach(function (item, index) {
                var conversationItem = document.createElement('div');
                conversationItem.className = 'conversation-item';

                var questionDiv = document.createElement('div');
                questionDiv.className = 'question';
                questionDiv.innerHTML = "Q" + (index + 1) + ": " + item.question;

                var answerDiv = document.createElement('div');
                answerDiv.className = 'answer';
                // 使用 innerHTML 将答案内容当作 HTML 内容解析,使图片等能正确显示
                answerDiv.innerHTML = "A" + (index + 1) + ": " + item.answer;

                conversationItem.appendChild(questionDiv);
                conversationItem.appendChild(answerDiv);

                conversationDiv.appendChild(conversationItem);
            });
        }
    </script>

</body>

</html>
相关推荐
m0_748240765 分钟前
前端配置跨域的详细指南
前端
Super毛毛穗15 分钟前
Vue中<script setup></script>的主要语法元素和特性
前端·javascript·vue.js·前端框架
2401_857636391 小时前
医疗服务品质提升:SSM 与 Vue 打造医院预约挂号系统方案
前端·javascript·vue.js
余生H2 小时前
前端的Python应用指南(一):快速构建 Web 服务器 - Flask vs Node.js 对比
服务器·前端·python
白瑕2 小时前
[JavaScript] 我该怎么去写一个canvas游戏
前端·javascript
m0_748248942 小时前
前端篇-Content-Type 详解
前端
m0_748255022 小时前
新手参加2025年CTF大赛——Web题目的基本解题流程
前端·网络·安全
憨憨小江2 小时前
Vue3 基础记录
前端
SANG嘻嘻嘻3 小时前
ES6中的map和set
前端·javascript·es6
fantasy_arch3 小时前
CPU性能优化--前端优化
前端·性能优化