react遍历生成多个Button的单选和多选

本文介绍了一种使用React实现按钮组多选与单选的方法。通过定义按钮的状态并在点击时更新状态,实现了按钮组的选择功能。具体包括初始化按钮状态、处理多选逻辑及单选逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// 设置初始默认值

this.state:{

    btnClassName:' ',

    btnClassNameArry: [ ],

}

// 选中button,多选

handleSelect = (itemChild) => {

const { btnClassNameArry } = this.state;

// 如果点击的在数组中已经存在,则从数组删除,否则,添加到数组

if (btnClassNameArry.indexOf(itemChild) > -1) {

      btnClassNameArry.splice(btnClassNameArry.indexOf(itemChild), 1);

} else {

     btnClassNameArry.push(itemChild);

}

const newBtnClassNameArry = btnClassNameArry;

// 改变state状态值

this.setState({

       btnClassNameArry: newBtnClassNameArry,

});

}

// 选中button 单选

handleSelectSigle = (itemChild) => {

// 改变state状态值

this.setState({

       btnClassName: itemChild,

});

}

 

//渲染列表

<div className="condition-div">

{data.map((item) => (

      <Row key={item.level0}>

     <Col span={5} className="condition-firCol">

         {item.level0}

      </Col>

 

      <Col span={19} className="tableSearchCol">

         {item.level1.map((itemChild) => (

           <Button

            key={itemChild}

           // 单行操作

           // className={this.state.btnClassName === itemChild ? 'tableSearch-btn-change' : 'tableSearch-btn'}

          //多行操作

          className={this.state.btnClassNameArry.indexOf(itemChild) > -1 ? 'tableSearch-btn-change' : 'tableSearch-btn'}

          onClick={() => {

              this.handleSelect(itemChild);

          }}

     >

         {itemChild}

      </Button>

     ))

     }

   </Col>

</Row>

))

}

</div>

<think>我们将使用uni-app框架来创建一个简单的问答题考试页面。由于uni-app支持端(微信小程序、H5、App等),我们将使用Vue.js语法进行开发。 页面功能需求: 1. 显示考试题目(从题库中获取,这里我们假设有一个本地的题目数组) 2. 用户可以择答案(单选题,使用单选按钮) 3. 提交答案后,显示用户的得分每道题的正确与否 4. 可以重新开始考试 页面结构: - 题目展示区域 - 项列表(单选) - 提交按钮 - 结果显示区域(提交后显示) 我们将使用一个数组来存储题目,每个题目对象包括: - id: 题目唯一标识 - question: 题目内容 - options: 项数组,如['A. 项1', 'B. 项2', ...] - answer: 正确答案的索引(0表示第一个项) 步骤: 1. 创建页面,初始化数据:题目列表、用户择的答案、是否已提交、得分等。 2. 渲染题目项,使用radio-groupradio组件(或使用view结合点击事件模拟单选)。 3. 用户择答案时,记录择的项索引。 4. 提交时,遍历所有题目,比较用户择的答案正确答案,计算得分。 5. 显示结果:每题的对错,以及总分。 6. 提供重新开始的按钮。 注意:uni-app中,可以使用单文件组件(.vue)来编写页面。 下面是一个简单的实现示例: 文件路径:假设在uni-app项目的pages/test/test.vue 代码实现:</think>下面是一个使用 Uni-app 实现的问答题考试页面代码,包含题目展示、答题、提交评分等功能: ```vue <template> <view class="exam-container"> <!-- 顶部考试信息 --> <view class="exam-header"> <text class="title">编程知识测试</text> <view class="progress"> <text>{{ currentIndex + 1 }} / {{ questions.length }}</text> <progress :percent="(currentIndex / questions.length) * 100" show-info stroke-width="3" /> </view> </view> <!-- 题目区域 --> <scroll-view scroll-y class="question-container"> <view class="question-card"> <text class="question-text">{{ currentQuestion.question }}</text> <!-- 问答题输入框 --> <textarea v-model="userAnswers[currentIndex]" placeholder="请输入您的答案..." class="answer-input" auto-height maxlength="500" /> </view> </scroll-view> <!-- 导航按钮 --> <view class="nav-buttons"> <button class="nav-btn prev-btn" :disabled="currentIndex === 0" @click="prevQuestion" >上一题</button> <button v-if="currentIndex < questions.length - 1" class="nav-btn next-btn" @click="nextQuestion" >下一题</button> <button v-else class="nav-btn submit-btn" @click="submitExam" >提交答案</button> </view> <!-- 评分结果弹窗 --> <uni-popup ref="resultPopup" type="center"> <view class="result-card"> <text class="result-title">考试结果</text> <view class="score-display"> <text>得分:{{ score }} / {{ totalScore }}</text> <text class="score-text">{{ scorePercentage }}%</text> </view> <view class="result-details"> <view v-for="(result, index) in results" :key="index" class="result-item" > <text>Q{{ index + 1 }}: {{ result.isCorrect ? '✓' : '✗' }}</text> </view> </view> <button class="review-btn" @click="reviewAnswers">查看答案解析</button> </view> </uni-popup> </view> </template> <script> export default { data() { return { currentIndex: 0, userAnswers: [], score: 0, totalScore: 100, results: [], showResult: false, questions: [ { id: 1, question: "解释JavaScript中的闭包概念及其使用场景", answer: "闭包是函数与其词法环境的组合,允许函数访问其创建时的作用域变量。常用于数据封装、私有变量函数工厂等场景。" }, { id: 2, question: "React中useEffectuseLayoutEffect有什么区别?", answer: "useEffect在渲染完成后异步执行,不会阻塞UI渲染;useLayoutEffect在DOM更新后同步执行,会阻塞渲染,适合需要直接操作DOM的场景。" }, { id: 3, question: "什么是CSS的BFC?如何触发BFC?", answer: "块级格式化上下文(BFC)是独立的渲染区域。触发方式:float非none、position非static、display为inline-block/flex/table-cell、overflow非visible等。" } ] }; }, computed: { currentQuestion() { return this.questions[this.currentIndex]; }, scorePercentage() { return Math.round((this.score / this.totalScore) * 100); } }, methods: { nextQuestion() { if (this.currentIndex < this.questions.length - 1) { this.currentIndex++; } }, prevQuestion() { if (this.currentIndex > 0) { this.currentIndex--; } }, submitExam() { // 评分逻辑 this.score = 0; this.results = []; this.questions.forEach((q, index) => { const userAnswer = this.userAnswers[index] || ""; // 简化评分:实际应用中应使用更复杂的文本匹配算法 const isCorrect = userAnswer.trim().length > 10; // 简单长度判断 if (isCorrect) this.score += Math.round(this.totalScore / this.questions.length); this.results.push({ questionId: q.id, userAnswer, correctAnswer: q.answer, isCorrect }); }); // 显示结果弹窗 this.$refs.resultPopup.open(); }, reviewAnswers() { this.$refs.resultPopup.close(); uni.navigateTo({ url: `/pages/review/review?results=${encodeURIComponent(JSON.stringify(this.results))}` }); } } }; </script> <style scoped> .exam-container { display: flex; flex-direction: column; height: 100vh; background-color: #f5f7fa; padding: 20rpx; } .exam-header { padding: 30rpx; background: #fff; border-radius: 16rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05); margin-bottom: 20rpx; } .title { font-size: 36rpx; font-weight: bold; color: #2c3e50; } .progress { margin-top: 20rpx; } .question-container { flex: 1; margin-bottom: 20rpx; } .question-card { background: #fff; border-radius: 16rpx; padding: 30rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05); } .question-text { font-size: 32rpx; line-height: 1.6; color: #34495e; margin-bottom: 40rpx; } .answer-input { min-height: 300rpx; background: #f9f9f9; border: 1rpx solid #eee; border-radius: 12rpx; padding: 20rpx; font-size: 30rpx; margin-top: 20rpx; } .nav-buttons { display: flex; justify-content: space-between; padding: 20rpx 0; } .nav-btn { flex: 1; margin: 0 15rpx; border-radius: 50rpx; font-size: 32rpx; } .prev-btn { background: #f0f0f0; color: #7f8c8d; } .next-btn, .submit-btn { background: #3498db; color: white; } .submit-btn { background: #2ecc71; } .result-card { background: white; border-radius: 24rpx; padding: 40rpx; width: 80vw; text-align: center; } .result-title { font-size: 40rpx; font-weight: bold; color: #2c3e50; display: block; margin-bottom: 30rpx; } .score-display { font-size: 44rpx; margin: 30rpx 0; } .score-text { color: #e74c3c; font-weight: bold; } .result-details { display: flex; justify-content: center; flex-wrap: wrap; margin: 30rpx 0; } .result-item { width: 80rpx; height: 80rpx; line-height: 80rpx; border-radius: 50%; background: #ecf0f1; margin: 10rpx; font-size: 32rpx; } .review-btn { background: #9b59b6; color: white; margin-top: 30rpx; border-radius: 50rpx; } </style> ``` ### 功能说明: 1. **考试流程**: - 分页显示问答题(支持上一题/下一题导航) - 文本输入框作答 - 提交后显示得分每题结果 2. **核心功能**: - 进度条显示答题进度 - 自适应高度的答案输入框 - 简易评分逻辑(实际应用中应使用更复杂的文本匹配算法) - 结果弹窗展示得分每题对错 - 答案解析跳转功能 3. **UI 设计**: - 卡片式布局 - 响应式按钮 - 进度可视化 - 圆角设计阴影 - 合理的色彩对比 ### 使用说明: 1. 创建 `pages/exam/exam.vue` 文件并粘贴代码 2. 需要安装 uni-ui 组件库(用于弹窗组件): ```bash npm install @dcloudio/uni-ui ``` 3. 在 `pages.json` 中添加页面路由: ```json { "path": "pages/exam/exam", "style": { "navigationBarTitleText": "编程考试" } } ``` ### 实际应用建议: 1. **评分优化**: - 使用字符串相似度算法(如Levenshtein距离) - 添加关键词匹配逻辑 - 支持人工评分功能 2. **数据持久化**: ```javascript // 保存答题进度 uni.setStorageSync('exam_progress', { currentIndex: this.currentIndex, userAnswers: this.userAnswers }); ``` 3. **网络请求**: ```javascript // 从服务器获取题目 async loadQuestions() { const res = await uni.request({ url: 'https://api.example.com/questions' }); this.questions = res.data; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值