ProgrammingCourset.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <!-- 编程课列表内容 -->
  2. <template>
  3. <div class="programming-content">
  4. <!-- 标题部分 -->
  5. <div class="top-box">
  6. <!-- 返回按钮 -->
  7. <div class="top-left-box">
  8. <div class="top-left-inner-box">
  9. <!-- 左侧返回图标 -->
  10. <div class="left-content-wrapper" @click="goBackIndex">
  11. <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
  12. <span class="left-text">返回</span>
  13. </div>
  14. </div>
  15. </div>
  16. <!-- 标题 -->
  17. <div class="top-center-box" v-if="!showVideo">
  18. <div class="top-center-inner-box">
  19. <span>{{ pageTitle }}</span>
  20. </div>
  21. </div>
  22. <!-- 课程提示 -->
  23. <div class="top-right-box">
  24. <div class="top-right-inner-box">
  25. <div class="course-info-box">{{ originalCourseTitle }}</div>
  26. </div>
  27. </div>
  28. </div>
  29. <!-- 课程部分 -->
  30. <div class="lower-box" v-if="!showVideo">
  31. <div
  32. class="content-box"
  33. ref="contentBox"
  34. @mousedown="handleMouseDown"
  35. @mousemove="handleMouseMove"
  36. @mouseup="handleMouseUp"
  37. @mouseleave="handleMouseLeave"
  38. @scroll="handleScroll"
  39. >
  40. <!-- 动态渲染课程内容 -->
  41. <div
  42. v-for="(item, index) in courseItems"
  43. :key="item.id"
  44. :class="['slide-item', { active: activeButton === index }]"
  45. :style="courseItems.length <= 3 ? { float: 'left' } : {}"
  46. @click="handleCourseItemClick(item)"
  47. >
  48. <div class="box-content">
  49. <img :src="item.image" :alt="item.title" class="box-image" />
  50. <div class="box-text">{{ item.title }}</div>
  51. </div>
  52. <!-- 星星图标组 -->
  53. <div class="star-group">
  54. <div
  55. v-for="i in getStarCount(item.contentType)"
  56. :key="i"
  57. class="star-icon"
  58. :style="{
  59. backgroundImage: `url(${i <= item.progress ? star01Image : star02Image})`,
  60. }"
  61. ></div>
  62. </div>
  63. </div>
  64. </div>
  65. </div>
  66. <!-- 底部切换按钮 -->
  67. <div v-if="!showVideo && courseItems.length > 3" class="bottom-box">
  68. <!-- 左切换按钮 -->
  69. <div class="carousel-btn prev-btn" @click="prevSlide" :class="{ 'disabled-btn': activeButton === 0 }" :disabled="activeButton === 0">
  70. <img :src="leftbtn" alt="左按钮" class="btn-image" :class="{ 'disabled-icon': activeButton === 0 }" />
  71. </div>
  72. <!-- 进度条滑块 -->
  73. <div class="line-container" v-if="courseItems.length > 0">
  74. <el-slider v-model="activeButton" :max="courseItems.length - 1" :step="1" :show-tooltip="false" />
  75. </div>
  76. <!-- 右切换按钮 -->
  77. <div class="carousel-btn next-btn" @click="nextSlide" :class="{ 'disabled-btn': activeButton >= courseItems.length - 1 }" :disabled="activeButton >= courseItems.length - 1">
  78. <img :src="rightbtn" alt="右按钮" class="btn-image" :class="{ 'disabled-icon': activeButton >= courseItems.length - 1 }" />
  79. </div>
  80. </div>
  81. <!-- 视频和编程界面 -->
  82. <Interface v-if="showVideo" :courseData="selectedCourseData" :courseList="resData" @closeVideo="showVideo = false" />
  83. </div>
  84. </template>
  85. <script setup>
  86. // 返回图标
  87. import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue';
  88. import { ref, onMounted, computed, watch } from 'vue';
  89. // 导入路由
  90. import { useRouter, useRoute } from 'vue-router';
  91. // 根据ID获取课程列表
  92. import { getBlocklyByTypeId } from '@/api/programming/index.js'
  93. // 导入图片
  94. import explanation from '@/assets/programming/explanation.png'
  95. import practice from '@/assets/programming/practice.png'
  96. import summary from '@/assets/programming/summary.png'
  97. // 导入按钮图片
  98. import leftbtn from '@/assets/programming/leftbtn.png'
  99. import rightbtn from '@/assets/programming/rightbtn.png'
  100. import Interface from './Interface.vue'
  101. // 星星图片
  102. import star02Image from '@/assets/programming/star02.png'
  103. import star01Image from '@/assets/programming/star01.png'
  104. import {Message} from "@/utils/message/Message.js";
  105. // 获取路由实例
  106. const router = useRouter()
  107. const route = useRoute()
  108. // 页面标题
  109. const pageTitle = ref('')
  110. // 保存原始的课程ID和标题
  111. const originalCourseId = ref('')
  112. const originalCourseTitle = ref('')
  113. const isDisabled = ref(false) // 课程是否只读
  114. // 类型ID(从ProgrammingList页面传递过来)
  115. const typeId = ref('')
  116. // 控制视频界面显示
  117. const showVideo = ref(false)
  118. // 动态课程项数据
  119. const courseItems = ref([])
  120. // 当前选中的课程数据
  121. const selectedCourseData = ref(null)
  122. // 保存原始API返回的数据
  123. const resData = ref([])
  124. // 当前激活的按钮索引
  125. const activeButton = ref(0)
  126. // 拖动相关变量
  127. const isDragging = ref(false)
  128. const startX = ref(0)
  129. const scrollLeft = ref(0)
  130. const hasMoved = ref(false) // 标记是否发生了移动
  131. // 获取contentBox元素的引用
  132. const contentBox = ref(null)
  133. // 根据内容类型获取星星数量
  134. const getStarCount = (contentType) => {
  135. if (contentType === 'video') {
  136. return 1; // video类型渲染1个星星
  137. } else if (contentType === 'blockly') {
  138. return 3; // blockly类型渲染3个星星
  139. }
  140. }
  141. // 上一页
  142. const prevSlide = () => {
  143. if (activeButton.value > 0) {
  144. activeButton.value -= 1;
  145. }
  146. }
  147. // 下一页
  148. const nextSlide = () => {
  149. if (activeButton.value < courseItems.value.length - 1) {
  150. activeButton.value += 1;
  151. }
  152. }
  153. // 鼠标按下事件处理函数
  154. const handleMouseDown = (e) => {
  155. // 拖拽状态为true
  156. isDragging.value = true
  157. // 初始化移动状态为false
  158. hasMoved.value = false
  159. // 计算鼠标在容器内的相对X坐标的位置 e.pageX鼠标相对于整个页面的X坐标
  160. startX.value = e.pageX - contentBox.value.offsetLeft
  161. // 记录当前容器的滚动位置
  162. scrollLeft.value = contentBox.value.scrollLeft
  163. e.stopPropagation() // 阻止事件冒泡 防止事件继续向上传播到父元素
  164. }
  165. // 鼠标移动事件处理函数
  166. const handleMouseMove = (e) => {
  167. if (!isDragging.value) return
  168. // 标记已发生移动
  169. hasMoved.value = true
  170. // 阻止默认行为和冒泡
  171. e.preventDefault()
  172. e.stopPropagation()
  173. const x = e.pageX - contentBox.value.offsetLeft
  174. const walk = (x - startX.value) * 2 // 滚动速度
  175. contentBox.value.scrollLeft = scrollLeft.value - walk
  176. }
  177. // 鼠标松开事件处理函数
  178. const handleMouseUp = () => {
  179. isDragging.value = false
  180. // 延迟重置hasMoved,确保点击事件可以正常判断
  181. setTimeout(() => {
  182. hasMoved.value = false
  183. }, 100)
  184. }
  185. // 鼠标离开事件处理函数
  186. const handleMouseLeave = () => {
  187. isDragging.value = false
  188. hasMoved.value = false
  189. }
  190. // rpx转换为像素值的辅助函数
  191. const rpxValue = (px) => {
  192. return (px / 750) * window.innerWidth;
  193. }
  194. // 滚动事件处理函数
  195. const handleScroll = () => {}
  196. // 监听activeButton变化,自动滚动到中间位置
  197. watch(activeButton, (newIndex) => {
  198. if (contentBox.value && newIndex !== -1) {
  199. // 找到对应的课程卡片元素
  200. const courseElement = contentBox.value.querySelector(`.slide-item:nth-child(${newIndex + 1})`);
  201. if (courseElement) {
  202. // 计算滚动位置,选中的卡片居中
  203. const containerWidth = contentBox.value.clientWidth;
  204. const elementLeft = courseElement.offsetLeft;
  205. const elementWidth = courseElement.offsetWidth;
  206. // 计算居中位置
  207. const scrollPosition = elementLeft - (containerWidth / 2) + (elementWidth / 2);
  208. // 平滑滚动到计算的位置
  209. contentBox.value.scrollTo({
  210. left: scrollPosition,
  211. behavior: 'smooth'
  212. });
  213. }
  214. }
  215. });
  216. // 提取课程数据获取和处理逻辑为单独函数
  217. const fetchCourseData = () => {
  218. if (typeId.value) {
  219. getBlocklyByTypeId(typeId.value).then(res => {
  220. if (res && res.data && Array.isArray(res.data)) {
  221. // 保存原始API返回的数据
  222. resData.value = res.data;
  223. resData.value.forEach(item => {
  224. item.isDisabled = isDisabled.value
  225. })
  226. // 创建图片映射,根据bcLabel显示对应图片
  227. const imageMap = {
  228. '1': explanation,
  229. '2': practice,
  230. '3': summary
  231. }
  232. // 清空旧的课程项
  233. courseItems.value = [];
  234. // 遍历接口返回的数据,设置课程项
  235. res.data.forEach((item, index) => {
  236. // 每个课程项都对应位置样式和图片
  237. const positionIndex = (index % 3) + 1
  238. const image = imageMap[item.bcLabel]; // 根据bcLabel获取图片
  239. courseItems.value.push({
  240. id: item.id,
  241. title: item.bcName,
  242. image: image,
  243. contentType: item.bcContentType,
  244. progress: item.progress, // 进度
  245. isDisabled: isDisabled.value // 保存bcLabel用于图片映射
  246. })
  247. })
  248. }
  249. })
  250. }
  251. }
  252. // 组件挂载时获取路由参数设置标题
  253. onMounted(() => {
  254. // 检查路由参数中是否有courseTitle
  255. const courseTitle = route.query.courseTitle
  256. if (courseTitle) {
  257. // 设置页面标题
  258. pageTitle.value = courseTitle
  259. }
  260. // 获取当前类型ID
  261. typeId.value = route.query.typeId
  262. // 保存原始的课程ID和标题,返回时使用
  263. originalCourseId.value = route.query.originalCourseId
  264. originalCourseTitle.value = route.query.originalCourseTitle
  265. isDisabled.value = Boolean(isDisabled.value)
  266. // 获取到topicId后,调用函数获取课程列表
  267. fetchCourseData();
  268. })
  269. // 处理课程项点击事件
  270. const handleCourseItemClick = (item) => {
  271. // 如果在拖动过程中,则不触发点击事件
  272. if (hasMoved.value) return
  273. // 如果是只读模式,不允许点击
  274. if (isDisabled.value) {
  275. Message().notifyWarning('您的账号并未开放此课程!', true)
  276. return;
  277. }
  278. if (item.contentType === 'video' || item.contentType === 'blockly') {
  279. showVideo.value = true
  280. // 查找并保存完整的课程数据
  281. const fullCourseData = resData.value.find(course => course.id === item.id)
  282. if (fullCourseData) {
  283. selectedCourseData.value = fullCourseData
  284. selectedCourseData.value.ztId = originalCourseId.value
  285. selectedCourseData.value.isDisabled = isDisabled.value
  286. }
  287. }
  288. }
  289. // 返回编程课列表
  290. const goBackIndex = () => {
  291. // 隐藏视频和游戏界面
  292. showVideo.value = false
  293. // 返回时携带原始的课程参数,使用categoryId保持与ProgrammingList.vue中参数名一致
  294. router.push({
  295. path: '/programminglist',
  296. query: {
  297. categoryId: originalCourseId.value,
  298. courseTitle: originalCourseTitle.value
  299. }
  300. })
  301. }
  302. // 监听showVideo状态变化,当从true变为false时重新获取课程数据
  303. watch(showVideo, (newValue, oldValue) => {
  304. if (oldValue === true && newValue === false) {
  305. // 当视频界面关闭时,调用函数重新获取最新的课程数据
  306. fetchCourseData();
  307. }
  308. })
  309. </script>
  310. <style scoped lang="scss">
  311. @use 'sass:math';
  312. // 定义rpx转换函数
  313. @function rpx($px) {
  314. @return math.div($px, 750) * 100vw;
  315. }
  316. .programming-content{
  317. position: fixed;
  318. top: 0;
  319. left: 0;
  320. right: 0;
  321. bottom: 0;
  322. background-image: url('@/assets/programming/list_bg03.png');
  323. background-size: cover;
  324. background-position: center;
  325. background-repeat: no-repeat;
  326. display: flex;
  327. flex-direction: column;
  328. user-select: none; /* 禁止文本选择 */
  329. }
  330. .top-box {
  331. height: 20%;
  332. display: flex;
  333. }
  334. .top-left-box,
  335. .top-right-box {
  336. flex: 1;
  337. height: 50%;
  338. display: flex;
  339. align-items: center;
  340. justify-content: center;
  341. }
  342. .top-center-box {
  343. flex: 2;
  344. display: flex;
  345. align-items: center;
  346. justify-content: center;
  347. }
  348. .top-center-inner-box{
  349. width: 100%;
  350. height: 100%;
  351. background-image: url('@/assets/programming/list_title.png');
  352. background-size: 70%;
  353. background-repeat: no-repeat;
  354. background-position: center center; /* 背景图垂直水平居中 */
  355. display: flex;
  356. align-items: center; /* 垂直居中 */
  357. justify-content: center; /* 水平居中 */
  358. cursor: pointer;
  359. position: relative; /* 相对定位 */
  360. span{
  361. font-size: rpx(16);
  362. color: white;
  363. position: relative;
  364. z-index: 1; /* 确保文字在背景图上方 */
  365. display: flex;
  366. align-items: center;
  367. justify-content: center;
  368. padding-bottom: rpx(5);
  369. }
  370. }
  371. .top-left-inner-box{
  372. display: flex;
  373. align-items: center; /* 垂直居中对齐 */
  374. width: 100%;
  375. height: 100%;
  376. .left-content-wrapper{
  377. display: flex;
  378. align-items: center; /* 保持内部元素垂直居中 */
  379. }
  380. .left-icon{
  381. font-size: rpx(14);
  382. color: white;
  383. padding-left: rpx(20);
  384. cursor: pointer;
  385. }
  386. .left-text{
  387. font-size: rpx(14);
  388. color: white;
  389. padding-left: rpx(10);
  390. cursor: pointer;
  391. }
  392. }
  393. .top-right-inner-box {
  394. width: 100%;
  395. height: 100%;
  396. display: flex;
  397. justify-content: flex-end;
  398. align-items: center;
  399. padding-right: rpx(20);
  400. .course-info-box {
  401. width: rpx(60);
  402. height: rpx(20);
  403. background-color: rgb(255, 255, 255);
  404. border-radius: rpx(15);
  405. display: flex;
  406. align-items: center;
  407. justify-content: center;
  408. color: #45300b;
  409. font-size: rpx(10);
  410. cursor: pointer;
  411. }
  412. }
  413. .lower-box {
  414. height: 75%;
  415. overflow: hidden; /* 溢出隐藏 */
  416. position: relative;
  417. display: flex;
  418. align-items: center;
  419. justify-content: center;
  420. margin-top: rpx(-25);
  421. }
  422. .content-box {
  423. width: 100%;
  424. min-width: rpx(660); /* 最小宽度 */
  425. height: 100%;
  426. overflow-x: auto; /* 水平滚动条 */
  427. overflow-y: hidden; /* 取消上下滚动 */
  428. white-space: nowrap; /* 防止元素换行 */
  429. scroll-behavior: smooth; /* 平滑滚动效果 */
  430. -webkit-overflow-scrolling: touch; /* 触摸设备支持 */
  431. position: relative;
  432. flex: 1;
  433. cursor: grab; /* 显示可抓取图标 */
  434. z-index: 2;
  435. padding: 0 rpx(30);
  436. /* 设置背景图 */
  437. background-image: url('@/assets/programming/track01.png');
  438. background-size: rpx(1360) rpx(350); /* 使用固定宽度,背景图大小一致 */
  439. background-position: left calc(-1 * rpx(50));
  440. background-repeat: no-repeat;
  441. background-attachment: local; /* 背景图跟内容一起滚动 */
  442. }
  443. /* 鼠标按下时的光标样式 */
  444. .content-box:active {
  445. cursor: grabbing;
  446. }
  447. /* 隐藏滚动条但保持滚动功能 */
  448. .content-box::-webkit-scrollbar {
  449. display: none;
  450. }
  451. .content-box {
  452. -ms-overflow-style: none;
  453. scrollbar-width: none;
  454. }
  455. .slide-item {
  456. width: rpx(130); /* 设置固定宽度 */
  457. height: rpx(110); /* 高度设置 */
  458. margin: rpx(85) rpx(40);
  459. border-radius: rpx(35);
  460. background-color: rgba(255, 255, 255);
  461. display: inline-flex;
  462. align-items: center;
  463. justify-content: center;
  464. transition: transform 0.3s ease;
  465. cursor: pointer;
  466. z-index: 2; /* 内容在背景图上方 */
  467. vertical-align: middle;
  468. position: relative;
  469. }
  470. /* 奇数项在上层 */
  471. .slide-item:nth-child(odd) {
  472. transform: translateY(-50%);
  473. }
  474. /* 偶数项在下层 */
  475. .slide-item:nth-child(even) {
  476. transform: translateY(50%);
  477. }
  478. /* 鼠标悬停放大效果 - 在保持原有垂直位置的基础上放大 */
  479. .slide-item:nth-child(odd):hover {
  480. transform: translateY(-50%) scale(1.1);
  481. z-index: 10;
  482. }
  483. .slide-item:nth-child(even):hover {
  484. transform: translateY(50%) scale(1.1);
  485. z-index: 10;
  486. }
  487. /* 默认选中第一个元素的样式 */
  488. /* 奇数项选中样式 */
  489. .slide-item:nth-child(odd).active {
  490. transform: translateY(-50%) scale(1.1);
  491. z-index: 10;
  492. box-shadow: 0 rpx(8) rpx(15) rgba(0, 0, 0, 0.3);
  493. }
  494. /* 偶数项选中样式 */
  495. .slide-item:nth-child(even).active {
  496. transform: translateY(50%) scale(1.1);
  497. z-index: 10;
  498. box-shadow: 0 rpx(8) rpx(15) rgba(0, 0, 0, 0.3);
  499. }
  500. /* 内容样式 */
  501. .box-content {
  502. display: flex;
  503. flex-direction: column;
  504. align-items: center;
  505. justify-content: center;
  506. height: 100%;
  507. width: 100%;
  508. }
  509. /* 鼠标按下时的光标样式 */
  510. .slide-item:active {
  511. cursor: grabbing;
  512. }
  513. .box-image {
  514. width: 100%;
  515. height: 90%;
  516. object-fit: contain;
  517. }
  518. .box-text {
  519. width: 100%;
  520. height: 20%;
  521. line-height: 20%;
  522. font-size: rpx(13);
  523. color: #333;
  524. text-align: center;
  525. }
  526. /* 星星图标样式 */
  527. .star-group {
  528. position: absolute;
  529. top: 100%;
  530. width: 100%;
  531. display: flex;
  532. justify-content: center;
  533. align-items: center;
  534. z-index: 3;
  535. }
  536. .star-icon {
  537. position: relative;
  538. width: rpx(23);
  539. height: rpx(23);
  540. background-size: contain;
  541. background-repeat: no-repeat;
  542. background-position: center;
  543. margin: 0 rpx(0);
  544. }
  545. /* 轮播图按钮样式 */
  546. .carousel-btn {
  547. width: rpx(40);
  548. height: rpx(40);
  549. border-radius: 50%;
  550. display: flex;
  551. align-items: center;
  552. justify-content: center;
  553. cursor: pointer;
  554. z-index: 10;
  555. transition: all 0.3s ease;
  556. }
  557. .carousel-btn:hover:not(.disabled-btn) {
  558. transform: scale(1.1);
  559. }
  560. .carousel-btn:disabled,
  561. .disabled-btn {
  562. cursor: not-allowed;
  563. box-shadow: none;
  564. }
  565. .disabled-icon {
  566. opacity: 0.5;
  567. }
  568. .prev-btn {
  569. margin-right: rpx(5);
  570. }
  571. .next-btn {
  572. margin-left: rpx(5);
  573. }
  574. .btn-icon {
  575. font-size: rpx(15);
  576. color: #333;
  577. }
  578. /* 底部切换按钮样式 */
  579. .bottom-box {
  580. height: 15%;
  581. display: flex;
  582. align-items: center;
  583. justify-content: center;
  584. }
  585. .bottom-box .carousel-btn {
  586. position: relative;
  587. top: 0;
  588. transform: none;
  589. width: rpx(40);
  590. height: rpx(40);
  591. background-color: transparent;
  592. box-shadow: none;
  593. }
  594. .bottom-box .carousel-btn:hover:not(.disabled-btn) {
  595. transform: none;
  596. }
  597. .line-container {
  598. width: 70%; /* 滑块宽度 */
  599. position: relative;
  600. display: flex;
  601. align-items: center;
  602. justify-content: space-between;
  603. /* el-slider滑块样式 */
  604. :deep(.el-slider__runway) {
  605. height: rpx(10); /* 滑块轨道高度 */
  606. background-color: rgba(228, 227, 254,0.3); /* 轨道背景色 */
  607. border-radius: rpx(10);
  608. }
  609. :deep(.el-slider__bar) {
  610. height: rpx(10); /* 滑块激活部分高度 */
  611. background-color: #2598c2; /* 激活部分颜色为蓝色 */
  612. border-radius: rpx(10);
  613. }
  614. :deep(.el-slider__button) {
  615. width: rpx(35);
  616. height: rpx(35);
  617. margin-top: rpx(-5);
  618. margin-left: rpx(-10);
  619. border: none; /* 移除边框 */
  620. background-image: url('@/assets/programming/xiaozhi.png');
  621. background-size: 100%; /* 背景图片完全覆盖按钮 */
  622. background-position: center; /* 背景图片居中 */
  623. background-repeat: no-repeat; /* 背景图片不重复 */
  624. background-color: transparent; /* 透明背景 */
  625. &:hover {
  626. transform: scale(1.1); /* 悬停时放大效果 */
  627. }
  628. &.hover,
  629. &:active {
  630. transform: scale(1.1); /* 激活时放大效果 */
  631. box-shadow: none; /* 移除阴影效果 */
  632. }
  633. }
  634. :deep(.el-slider__stop) {
  635. width: rpx(10); /* 停止点大小 */
  636. height: rpx(10); /* 停止点大小 */
  637. background-color: white; /* 停止点颜色 */
  638. opacity: 0.2;
  639. }
  640. }
  641. .btn-image {
  642. width: rpx(40);
  643. height: rpx(40);
  644. object-fit: contain;
  645. }
  646. </style>