hookehuyr

fix(IconFont): 修复动态切换图标名称时图标不更新的问题

为 IconFont 组件添加 key 属性,强制其在图标名称变化时重新渲染,解决因 NutUI 组件未正确响应 props 变化导致的问题。

同时优化产品详情页的收藏图标交互与视觉:
- 将收藏按钮移至标题右侧,采用 Flexbox 布局避免长标题遮挡
- 统一使用 NutUI 标准图标名称(Heart/HeartFill)
- 为收藏按钮添加圆形背景与阴影,增强视觉反馈
- 优化热卖标签样式,采用玻璃拟态设计
...@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. ...@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5 ## [Unreleased] 5 ## [Unreleased]
6 6
7 ### Changed 7 ### Changed
8 +- 优化 "产品详情" 页面 (`src/pages/product-detail`):
9 + - 修复收藏图标状态切换无效的问题(修正图标名称为 NutUI 标准命名 `Heart`/`HeartFill`
10 + - 优化顶部操作区视觉体验,统一 "热卖" 标签与 "收藏" 按钮风格,采用玻璃拟态(Glassmorphism)设计
11 + - 增强收藏按钮交互反馈,增加白色圆形背景与阴影,确保在任意 Banner 背景下均清晰可见
12 + - 调整产品标题与收藏按钮布局:
13 + - 将收藏按钮移至标题右侧,采用 Flexbox 布局实现左右对齐
14 + - 标题自适应占据剩余空间,收藏按钮固定在右侧,避免长标题遮挡按钮
15 +
16 +### Fixed
17 +- 修复 `IconFont` 组件在动态切换 `name` 属性时图标不更新的问题:
18 + - 问题原因:NutUI 的 `IconFont` 组件在某些环境下未正确响应 props 变化
19 + - 解决方案:在 `src/components/IconFont.vue` 中添加 `:key="name"`,强制组件在图标名称变化时重新渲染
20 +
21 +### Changed
8 - 全量替换项目内 IconFont 调用为 `@nutui/icons-vue-taro``IconFont` 组件,统一使用 `class` 属性,移除自定义封装组件依赖 22 - 全量替换项目内 IconFont 调用为 `@nutui/icons-vue-taro``IconFont` 组件,统一使用 `class` 属性,移除自定义封装组件依赖
9 - 优化 "帮助中心" 页面 (`src/pages/help-center`): 23 - 优化 "帮助中心" 页面 (`src/pages/help-center`):
10 - 重构 "联系客服" 弹窗,将硬编码数据提取为 `contactMethods` 数组,并优化样式布局 24 - 重构 "联系客服" 弹窗,将硬编码数据提取为 `contactMethods` 数组,并优化样式布局
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
6 * @Description: 图标字体组件 6 * @Description: 图标字体组件
7 --> 7 -->
8 <template> 8 <template>
9 - <IconFontBase :name="name" :size="size" :color="color" :class="customClass" /> 9 + <IconFontBase :key="name" :name="name" :size="size" :color="color" :class="customClass" />
10 </template> 10 </template>
11 11
12 <script setup> 12 <script setup>
......
...@@ -13,29 +13,30 @@ ...@@ -13,29 +13,30 @@
13 :src="bannerImage" 13 :src="bannerImage"
14 mode="aspectFill" 14 mode="aspectFill"
15 /> 15 />
16 - <div class="absolute top-[32rpx] right-[32rpx] flex gap-[16rpx]"> 16 + <div class="absolute top-[32rpx] right-[32rpx] flex items-center gap-[16rpx]">
17 <!-- Hot Tag --> 17 <!-- Hot Tag -->
18 - <div class="bg-red-500 text-white text-[24rpx] px-[16rpx] py-[8rpx] rounded-full shadow-sm"> 18 + <div class="bg-red-500 text-white text-[24rpx] px-[20rpx] py-[10rpx] rounded-full shadow-sm backdrop-blur-sm bg-opacity-90">
19 热卖 19 热卖
20 </div> 20 </div>
21 + </div>
22 + </div>
23 +
24 + <!-- Product Header -->
25 + <div class="relative mt-[-40rpx] bg-white rounded-t-[40rpx] px-[40rpx] pt-[48rpx] pb-[40rpx] z-10">
26 + <div class="flex items-start justify-between mb-[24rpx]">
27 + <h1 class="text-[#1F2937] text-[44rpx] font-bold flex-1 mr-[24rpx] leading-[1.2]">终身寿险尊享版</h1>
21 <!-- Favorite Button --> 28 <!-- Favorite Button -->
22 <div 29 <div
23 - class="w-[64rpx] h-[48rpx] rounded-full shadow-md flex items-center justify-center" 30 + class="w-[72rpx] h-[72rpx] flex-shrink-0 flex items-center justify-center rounded-full bg-gray-50 active:scale-95 transition-transform"
24 - :class="isCollected ? 'bg-[#F59E0B]' : 'bg-white'"
25 @tap="toggleCollect" 31 @tap="toggleCollect"
26 > 32 >
27 <IconFont 33 <IconFont
28 - :name="isCollected ? 'StarFill' : 'Star'" 34 + :name="isCollected ? 'heart-fill' : 'heart'"
29 - :size="20" 35 + size="24"
30 - :color="isCollected ? 'white' : '#9CA3AF'" 36 + :color="isCollected ? '#EF4444' : '#9CA3AF'"
31 /> 37 />
32 </div> 38 </div>
33 </div> 39 </div>
34 - </div>
35 -
36 - <!-- Product Header -->
37 - <div class="relative mt-[-40rpx] bg-white rounded-t-[40rpx] px-[40rpx] pt-[48rpx] pb-[40rpx] z-10">
38 - <h1 class="text-[#1F2937] text-[44rpx] font-bold mb-[24rpx]">终身寿险尊享版</h1>
39 40
40 <div class="flex flex-wrap gap-[16rpx]"> 41 <div class="flex flex-wrap gap-[16rpx]">
41 <div class="px-[16rpx] py-[6rpx] bg-red-50 rounded-[8rpx]"> 42 <div class="px-[16rpx] py-[6rpx] bg-red-50 rounded-[8rpx]">
...@@ -71,7 +72,7 @@ ...@@ -71,7 +72,7 @@
71 <div class="flex flex-col gap-[32rpx]"> 72 <div class="flex flex-col gap-[32rpx]">
72 <div v-for="(feature, index) in features" :key="index" class="flex items-start"> 73 <div v-for="(feature, index) in features" :key="index" class="flex items-start">
73 <div class="w-[48rpx] h-[48rpx] rounded-full bg-blue-50 flex items-center justify-center mr-[24rpx] flex-shrink-0"> 74 <div class="w-[48rpx] h-[48rpx] rounded-full bg-blue-50 flex items-center justify-center mr-[24rpx] flex-shrink-0">
74 - <IconFont name="check" size="14" color="#2563EB" /> 75 + <IconFont name="Check" size="14" color="#2563EB" />
75 </div> 76 </div>
76 <div class="flex-1"> 77 <div class="flex-1">
77 <div class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4]">{{ feature.title }}</div> 78 <div class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4]">{{ feature.title }}</div>
......