H5 中 van-popup 的使用以及题目的切换
H5 中 van-popup 的使用以及题目的切换
在移动端开发中,弹窗组件是一个常见的需求。vant 是一个轻量、可靠的移动端 Vue 组件库,其中的 van-popup 组件可以方便地实现弹窗效果。本文将介绍如何使用 van-popup 实现题目详情的弹窗展示,并实现题目的切换功能。
关键点总结
-
引入
van-popup组件:- 在 Vue 项目中引入
vant组件库,并使用van-popup组件实现弹窗效果。 -
import { createApp } from 'vue' import Vant from 'vant'const app = createApp(App) app.use(Vant) app.mount('#app')
- 在 Vue 项目中引入
-
弹窗内容的条件渲染:
- 根据不同的题目类型(如互动题和练习题),在弹窗中显示不同的内容。
-
题目详情的展示:
- 使用
computed属性计算当前题目的详情,并在弹窗中展示题目的相关信息。
- 使用
-
题目的切换:
- 通过按钮实现题目的上一题和下一题的切换,并更新当前题目的索引。
代码示例
以下是实现上述功能的关键代码片段:
questions.vue---子组件
<template><van-popup v-model:show="localVisible" position="bottom" round :style="{ height: '80%' }" @close="close"><div v-if="type === 'interactive'"><div class="picker-header"><div class="picker-title">题目详情<button @click="close" class="close-button">X</button></div><div class="picker-info"><div class="left-info"><span class="number">第{{ currentQuestion.serial_number }}题</span><span class="status">{{ getStatusText(currentQuestion.status) }}</span></div><div class="right-info"><button v-if="!isFirstQuestion" @click="prevQuestion"><van-icon name="arrow-left" /></button><span>{{ currentQuestion.serial_number }}/{{ questions.length }}</span><button v-if="!isLastQuestion" @click="nextQuestion"><van-icon name="arrow" /></button></div></div></div><div class="picker-content"><div class="section-title">课件页面</div><iframe :src="currentQuestion.previewUrl" frameborder="0"></iframe><div class="use-duration">我的用时:<span class="time-number">{{ formattedDuration.minutes }}</span>分 <span class="time-number">{{formattedDuration.seconds }}</span>秒</div></div></div><div v-else-if="type === 'practice'">// 其他内容</div></van-popup>
</template><script setup>
import { defineProps, defineEmits, computed, ref, watch } from 'vue'
import { Popup } from 'vant'const props = defineProps({visible: Boolean,questions: {type: Array,required: true,},currentQuestionIndex: {type: Number,required: true,},type: {type: String,required: true,},
})const emits = defineEmits(['close', 'changeQuestion'])const localVisible = ref(props.visible)watch(() => props.visible,newVal => {localVisible.value = newVal},
)const currentQuestion = computed(() => {const question = props.questions[props.currentQuestionIndex] || {}if (props.type === 'practice' && !question.serial_number) {question.serial_number = props.currentQuestionIndex + 1}return question
})const getStatusText = status => {switch (status) {case 1:return '正确'case 2:return '错误'case 3:return '半对半错'default:return '未作答'}
}const formatDuration = duration => {const minutes = String(Math.floor(duration / 60)).padStart(2, '0')const seconds = String(duration % 60).padStart(2, '0')return { minutes, seconds }
}const formattedDuration = computed(() => formatDuration(currentQuestion.value.use_duration))const isFirstQuestion = computed(() => props.currentQuestionIndex === 0)
const isLastQuestion = computed(() => props.currentQuestionIndex === props.questions.length - 1)const prevQuestion = () => {if (!isFirstQuestion.value) {emits('changeQuestion', props.currentQuestionIndex - 1)}
}const nextQuestion = () => {if (!isLastQuestion.value) {emits('changeQuestion', props.currentQuestionIndex + 1)}
}const close = () => {emits('close')
}
</script><style lang="less" scoped>
.picker-header {padding: 10px;
}.picker-title {font-size: 18px;font-weight: bold;justify-content: space-between;align-items: center;margin-bottom: 10px;color: #000;margin-top: 10px;display: flex;width: 100%;.close-button {background: none;border: none;font-size: 16px;margin-left: auto;color: #a9aeb8;cursor: pointer;}
}.picker-info {display: flex;justify-content: space-between;align-items: center;padding: 0 10px 0 10px;
}.left-info {display: flex;flex-direction: row;.number {margin-right: 20px;font-size: 16px;font-weight: 500;}.status {font-size: 16px;font-weight: 500;color: #1f70ff;}
}.right-info {display: flex;position: absolute;right: 10px;color: #a9aeb8;.right-icon {width: 28px;height: 28px;}
}.right-info button {background: none;border: none;font-size: 16px;cursor: pointer;margin: 0 5px;
}.picker-content {padding: 10px 20px 0 20px;
}.section-title {font-size: 16px;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #2b2f38;
}iframe {width: 100%;height: 300px;border: none;margin-bottom: 10px;
}.use-duration {font-size: 16px;color: #2b2f38;
}.time-number {font-weight: bold;color: #0074fc;font-size: 24px;
}.van-popup {height: 50%;z-index: 99999;
}.practice-content {padding: 0px 20px 0 20px;
}
</style>
courseDetail.vue---父组件
// template关键代码
<div v-for="(item, index) in period.interactive_performance.list" :key="index" :class="['performance-item',getStatusClass(item.status),{ selected: selectedQuestion === index },]" @click="selectQuestion(index, period.interactive_performance.list, 'interactive')"><span :class="getQuestionTextClass(item.status, selectedQuestion === index)">{{item.serial_number}}</span></div><div v-for="(item, index) in period.practice_detail.list" :key="index" :class="['practice-item',getStatusClass(item.status),{ selected: selectedPracticeQuestion === index },]" @click="selectPracticeQuestion(index, period.practice_detail.list, 'practice')"><div class="question-number"><span>{{ index + 1 }}</span></div>
</div><QuestionDetail :visible="showQuestionDetail" :questions="currentQuestions" :type="currentType":currentQuestionIndex="currentQuestionIndex" @close="closeQuestionDetail" @changeQuestion="changeQuestion" />// script关键代码
const selectQuestion = (index, questions, type) => {selectedQuestion.value = indexcurrentQuestions.value = questionscurrentType.value = typecurrentQuestionIndex.value = indexshowQuestionDetail.value = true
}const selectPracticeQuestion = (index, questions, type) => {selectedPracticeQuestion.value = indexcurrentQuestions.value = questionscurrentQuestionIndex.value = index// 设置 serial_number 属性currentQuestions.value.forEach((question, idx) => {question.serial_number = idx + 1})currentType.value = typeshowQuestionDetail.value = true
}
const changeQuestion = index => {currentQuestionIndex.value = index
}
数据结构


关键点解析
-
引入
van-popup组件:- 在模板中使用
<van-popup>标签,并通过v-model:show绑定弹窗的显示状态。 - 设置
position="bottom"和round属性,使弹窗从底部弹出并带有圆角。
- 在模板中使用
-
弹窗内容的条件渲染:
- 使用
v-if和v-else-if根据type属性的值渲染不同的内容。 - 当
type为interactive时,显示互动题的详情;当type为practice时,显示练习题的详情。
- 使用
-
题目详情的展示:
- 使用
computed属性计算当前题目的详情,并在弹窗中展示题目的相关信息。 - 通过
currentQuestion计算属性获取当前题目的详细信息。
- 使用
-
题目的切换:
- 通过按钮实现题目的上一题和下一题的切换,并更新当前题目的索引。
- 使用
isFirstQuestion和isLastQuestion计算属性判断当前题目是否为第一题或最后一题,以控制按钮的显示和隐藏。
大致效果



通过以上关键点的实现,我们可以在移动端应用中使用 van-popup 组件实现题目详情的弹窗展示,并实现题目的切换功能。希望本文对您有所帮助!
相关文章:
H5 中 van-popup 的使用以及题目的切换
H5 中 van-popup 的使用以及题目的切换 在移动端开发中,弹窗组件是一个常见的需求。vant 是一个轻量、可靠的移动端 Vue 组件库,其中的 van-popup 组件可以方便地实现弹窗效果。本文将介绍如何使用 van-popup 实现题目详情的弹窗展示,并实现…...
Liinux下VMware Workstation Pro的安装,建议安装最新版本17.61
建议安装最新版本17.61,否则可能有兼容性问题 下载VMware Workstation安装软件 从官网网站下载 https://support.broadcom.com/group/ecx/productdownloads?subfamilyVMwareWorkstationPro 选择所需版本 现在最新版本是17.61,否则可能有兼容性问题…...
WebRTC服务质量(05)- 重传机制(02) NACK判断丢包
WebRTC服务质量(01)- Qos概述 WebRTC服务质量(02)- RTP协议 WebRTC服务质量(03)- RTCP协议 WebRTC服务质量(04)- 重传机制(01) RTX NACK概述 WebRTC服务质量(…...
修改ubuntu apt 源及apt 使用
视频教程:修改ubuntu apt 源和apt 使用方法_哔哩哔哩_bilibili 1 修改apt源 1.1 获取阿里云ubuntu apt 源 https://developer.aliyun.com/mirror/ubuntu?spma2c6h.13651102.0.0.3e221b11mqqLBC 1.2 修改apt 源 vim /etc/apt/sources.list deb https://mirrors.aliyun.com/ub…...
深入解析 `DataFrame.groupby` 和 `agg` 的用法及使用场景
深入解析 DataFrame.groupby 和 agg 的用法及使用场景 1. groupby 的基本用法语法:示例: 2. agg 的基本用法语法:示例: 3. first、sum、lambda 的用法3.1 first示例: 3.2 sum示例: 3.3 lambda示例ÿ…...
MySQL 的锁
MySQL有哪些锁?各种锁的作用与使用场景全局锁表级锁表锁元素锁意向锁AUTO-INC 锁 行级锁记录锁间隙锁临键锁 其他共享锁排他锁乐观锁悲观锁 MySQL有哪些锁? 全局锁表级锁 a. 表锁 b. 元素锁 c. 意向锁 d. AUTO-INC 锁行级锁 a. 记录锁 b. 间隙锁 c. 临键锁 各种锁的作用与使…...
二、使用langchain搭建RAG:金融问答机器人--数据清洗和切片
选择金融领域的专业文档作为源文件 这里选择 《博金大模型挑战赛-金融千问14b数据集》,这个数据集包含若干公司的年报,我们将利用这个年报搭建金融问答机器人。 具体下载地址 这里 git clone https://www.modelscope.cn/datasets/BJQW14B/bs_challenge_…...
【Linux】-- linux 配置用户免密登录本机
比如我们要配置用户 app_tom 免密登录本机(SSH 登录自己机器时无需输入密码),你可以按照以下步骤操作: 步骤 1:切换到 app_tom 用户 首先,确保你已经以 app_tom 用户登录,或者切换到该用户&…...
泷羽sec学习打卡-brupsuite8伪造IP和爬虫审计
声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都 与本人无关,切莫逾越法律红线,否则后果自负 关于brupsuite的那些事儿-Brup-FaskIP 伪造IP配置环境brupsuite导入配置1、扩展中先配置python环境2、安…...
【uniapp蓝牙】基于native.js链接ble和非ble蓝牙
【uniapp蓝牙】基于native.js链接ble和非ble蓝牙 uniapp不是仅支持低功耗蓝牙(基础蓝牙通讯不支持),有些可能需要基础蓝牙。我现在同步我的手机蓝牙列表低功耗,基础蓝牙都支持 /*** author wzj* 通用蓝牙模块封装* 搜索 ble 和非…...
.NET Core 各版本特点、差异及适用场景详解
随着 .NET Core 的不断发展,微软推出了一系列版本来满足不同场景下的开发需求。这些版本随着时间的推移逐渐演变为统一的 .NET 平台(从 .NET 5 开始)。本文将详细说明每个版本的特点、差异以及适用场景,帮助开发者更好地选择和使用…...
Linux中自动检测并定时关闭KDialog程序
自动检测并关闭对话框的程序示例 创建并打开KDialog的脚本自动检测并定时关闭KDialog的脚本 创建并打开KDialog的脚本 #!/bin/bash kdialog --msgbox "demo"自动检测并定时关闭KDialog的脚本 #!/bin/bash# Continuously check for kdialog dialog while true; do# …...
CSS学习记录12
CSS浮动 CSSfloat属性规定元素如何浮动 CSSclear属性规定哪些元素可以在清除的元素旁边以及在哪一侧浮动。 float属性 float属性用于定位和格式化内容,例如让图像向左浮动到容器的文本那里。 float属性可以设置以下值之一: left - 元素浮动到其容器…...
【Java基础面试题016】JavaObject类中有什么主要方法,作用是什么?
equals() 作用:用于比较两个对象是否相等。默认实现比较对象的内存地址,即判断两个引用是否指向同一个对象 使用:通常会重写此方法来比较对象的内容 hashCode() 作用:返回对象的哈希值,用整数表示对象。 使用&…...
实践环境-docker安装mysql8.0.40步骤
一、docker安装mysql 8.0.40版本 1、检索镜像版本 docker search mysql:8.0.40 NAME DESCRIPTION STARS OFFICIAL mysql MySQL is a widely used, open-source relation… …...
边缘智能创新应用大赛获奖作品系列一:智能边缘计算✖软硬件一体化,开启全场景效能革命新征程
边缘智能技术快速迭代,并与行业深度融合。它正重塑产业格局,催生新产品、新体验,带动终端需求增长。为促进边缘智能技术的进步与发展,拓展开发者的思路与能力,挖掘边缘智能应用的创新与潜能,高通技术公司联…...
决策树的生成与剪枝
决策树的生成与剪枝 决策树的生成生成决策树的过程决策树的生成算法 决策树的剪枝决策树的损失函数决策树的剪枝算法 代码 决策树的生成 生成决策树的过程 为了方便分析描述,我们对上节课中的训练样本进行编号,每个样本加一个ID值,如图所示…...
蓝桥杯算法训练 黑色星期五
题目描述 有些西方人比较迷信,如果某个月的13号正好是星期五,他们就会觉得不太吉利,用古人的说法,就是“诸事不宜”。请你编写一个程序,统计出在某个特定的年份中,出现了多少次既是13号又是星期五的情形&am…...
MySQL存储引擎-存储结构
Innodb存储结构 Buffer Pool(缓冲池):BP以Page页为单位,页默认大小16K,BP的底层采用链表数据结构管理Page。在InnoDB访问表记录和索引时会在Page页中缓存,以后使用可以减少磁盘IO操作,提升效率。 ○ Page根据状态可以分…...
理解torch函数bmm
基本信息 功能描述 torch.bmm 是 PyTorch 中的一个函数,用于执行批量矩阵乘法(Batch Matrix Multiplication)。它适用于处理一批矩阵的乘法操作,特别适合于深度学习任务中的场景,比如卷积神经网络中的某些层。 参数…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
[C++错误经验]case语句跳过变量初始化
标题:[C错误经验]case语句跳过变量初始化 水墨不写bug 文章目录 一、错误信息复现二、错误分析三、解决方法 一、错误信息复现 write.cc:80:14: error: jump to case label80 | case 2:| ^ write.cc:76:20: note: crosses initialization…...
