fix(ui): restore tab bar and detail navigation
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[777],{7914:function(e,n,t){var a=t(7842),c=t(5544),r=t(118),u=t(758),i=t.n(u),o=t(6540),s=t(1457),l=t(9703),f=t(6606),h=t(8199);function g(e,n,t){return Number.isFinite(e)?Math.min(t,Math.max(n,e)):n}function v(e){return g(e,0,100)}function d(e,n){return!Number.isFinite(e)||n<=0?0:g(Math.floor(v(e)/100*n),0,n-1)}function m(e,n,t){return Math.abs(n-e)>=t}function p(e){var n=e/750;return{left:36*n,width:Math.max(0,e-72*n)}}var b=t(4848),x=[{pagePath:"/pages/index/index",label:"\u9996\u9875",icon:(0,h.uq)("/icon/\u9996\u9875.svg"),iconActive:(0,h.uq)("/icon/\u9996\u9875-fill.svg")},{pagePath:"/pages/shop/index",label:"\u5546\u54c1",icon:(0,h.uq)("/icon/\u5546\u54c1.svg"),iconActive:(0,h.uq)("/icon/\u5546\u54c1-fill.svg")},{pagePath:"/pages/designList/index",label:"\u8bbe\u8ba1\u6e05\u5355",icon:(0,h.uq)("/icon/\u8c03\u8272\u76d8.svg"),iconActive:(0,h.uq)("/icon/\u8c03\u8272\u76d8-fill.svg")},{pagePath:"/pages/orders/index",label:"\u8ba2\u5355",icon:(0,h.uq)("/icon/\u5305\u88f9.svg"),iconActive:(0,h.uq)("/icon/\u5305\u88f9-fill.svg")},{pagePath:"/pages/profile/index",label:"\u6211\u7684",icon:(0,h.uq)("/icon/\u4e2a\u4eba.svg"),iconActive:(0,h.uq)("/icon/\u4e2a\u4eba-fill.svg")}],C=100/x.length,S=12;function P(e){var n=x.findIndex(function(n){return e.endsWith(n.pagePath)});return x[n>=0?n:0].pagePath}function T(){var e=i().getCurrentInstance().router,n=e&&e.path?e.path:"pages/index/index";return P(n)}function q(){var e=(0,o.useState)((0,s.eW)((0,s.O4)())),n=(0,c.A)(e,2),t=n[0],a=n[1],u=(0,o.useState)(T),h=(0,c.A)(u,2),g=h[0],q=h[1],N=(0,o.useState)(null),w=(0,c.A)(N,2),A=w[0],j=w[1],M=(0,o.useState)(!1),E=(0,c.A)(M,2),I=E[0],R=E[1],W=(0,o.useRef)(!1),k=(0,o.useRef)(null),O=(0,o.useRef)(0),X=(0,o.useRef)(null);(0,o.useEffect)(function(){var e=function(e){return a(e)};return i().eventCenter.on(l.Wo,e),function(){i().eventCenter.off(l.Wo,e)}},[]),(0,o.useEffect)(function(){var e=function(e){!e||"dark"!==e.theme&&"light"!==e.theme||((0,s.Rq)(e.theme),"auto"===(0,s.O4)()&&a(e.theme))},n=i();return n.onThemeChange&&n.onThemeChange(e),function(){n.offThemeChange&&n.offThemeChange(e)}},[]),(0,o.useEffect)(function(){var e=function(e){var n=i().getCurrentInstance().router,t=n&&n.path?n.path:"pages/index/index";q(P(e||t))};return i().eventCenter.on("tabBarChange",e),function(){i().eventCenter.off("tabBarChange",e)}},[]),(0,o.useEffect)(function(){(0,f.G)(t)},[t]);var y=function(e){q(P(e)),i().switchTab({url:e}),i().eventCenter.trigger("tabBarChange",e)},B=function(e){var n=e.touches&&e.touches[0];if(n){var t=p(i().getSystemInfoSync().windowWidth);X.current=t,O.current=n.clientX,W.current=!1,R(!1),k.current=null,j(null)}},F=function(e){var n=X.current,t=e.touches&&e.touches[0];if(n&&t){if(!W.current){if(!m(O.current,t.clientX,S))return;W.current=!0,R(!0)}var a=v((t.clientX-n.left)/n.width*100);k.current=a,j(a)}},J=function(e){var n=X.current;if(n){var t;if(W.current){var a;t=d(null!==(a=k.current)&&void 0!==a?a:0,x.length),W.current=!1,R(!1),i().nextTick(function(){k.current=null,j(null)})}else{var c=e.changedTouches&&e.changedTouches[0],r=c?c.clientX:O.current;t=d(v((r-n.left)/n.width*100),x.length)}var u=x[t];u&&u.pagePath!==g&&y(u.pagePath),X.current=null,O.current=0}},G=function(){X.current=null,O.current=0,W.current=!1,R(!1),k.current=null,j(null)},L=Math.max(0,x.findIndex(function(e){return e.pagePath===g}));return(0,b.jsxs)(r.Ss,{className:"tab-bar-root theme-".concat(t),children:[(0,b.jsx)(r.Ss,{className:"tab-bar-gradient"}),(0,b.jsxs)(r.Ss,{className:"custom-tab-bar theme-".concat(t),onTouchStart:B,onTouchMove:F,onTouchEnd:J,onTouchCancel:G,catchMove:!0,children:[(0,b.jsx)(r.Ss,{className:"tab-bar-caustic"}),(0,b.jsx)(r.Ss,{className:"tab-bar-rim"}),(0,b.jsx)(r.Ss,{className:"tab-indicator ".concat(I?"dragging":""),style:{left:"".concat(null===A?(L+.5)*C:A,"%")}}),x.map(function(e){var n=e.pagePath===g;return(0,b.jsxs)(r.Ss,{className:"tab-item ".concat(n?"active":""),children:[(0,b.jsx)(r._V,{className:"tab-icon-img ".concat(n?"active":""),src:n?e.iconActive:e.icon,mode:"aspectFit"}),(0,b.jsx)(r.EY,{className:"tab-label",children:e.label})]},e.pagePath)})]})]})}Component((0,a.createComponentConfig)(q,"custom-tab-bar/index"))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[907,96,76],function(){return n(7914)});e.O()}]);
|
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[777],{7914:function(n,e,t){var a=t(7842),c=t(5544),r=t(118),u=t(758),i=t.n(u),o=t(6540),s=t(1457),l=t(9703),f=t(6606),h=t(8199);function g(n,e,t){return Number.isFinite(n)?Math.min(t,Math.max(e,n)):e}function v(n){return g(n,0,100)}function p(n,e){return!Number.isFinite(n)||e<=0?0:g(Math.floor(v(n)/100*e),0,e-1)}function d(n,e,t){return Math.abs(e-n)>=t}function m(n){var e=n/750;return{left:36*e,width:Math.max(0,n-72*e)}}var b=t(4848),x=[{pagePath:"/pages/index/index",label:"\u9996\u9875",icon:(0,h.uq)("/icon/\u9996\u9875.svg"),iconActive:(0,h.uq)("/icon/\u9996\u9875-fill.svg")},{pagePath:"/pages/shop/index",label:"\u5546\u54c1",icon:(0,h.uq)("/icon/\u5546\u54c1.svg"),iconActive:(0,h.uq)("/icon/\u5546\u54c1-fill.svg")},{pagePath:"/pages/designList/index",label:"\u8bbe\u8ba1\u6e05\u5355",icon:(0,h.uq)("/icon/\u8c03\u8272\u76d8.svg"),iconActive:(0,h.uq)("/icon/\u8c03\u8272\u76d8-fill.svg")},{pagePath:"/pages/orders/index",label:"\u8ba2\u5355",icon:(0,h.uq)("/icon/\u5305\u88f9.svg"),iconActive:(0,h.uq)("/icon/\u5305\u88f9-fill.svg")},{pagePath:"/pages/profile/index",label:"\u6211\u7684",icon:(0,h.uq)("/icon/\u4e2a\u4eba.svg"),iconActive:(0,h.uq)("/icon/\u4e2a\u4eba-fill.svg")}],C=100/x.length,P=12;function S(n){var e=x.findIndex(function(e){return n.endsWith(e.pagePath)});return x[e>=0?e:0].pagePath}function T(){var n=i().getCurrentInstance().router,e=n&&n.path?n.path:"pages/index/index";return S(e)}function q(){var n=(0,o.useState)((0,s.eW)((0,s.O4)())),e=(0,c.A)(n,2),t=e[0],a=e[1],u=(0,o.useState)(T),h=(0,c.A)(u,2),g=h[0],q=h[1],N=(0,o.useState)(null),w=(0,c.A)(N,2),A=w[0],j=w[1],M=(0,o.useState)(!1),E=(0,c.A)(M,2),k=E[0],I=E[1],R=(0,o.useRef)(!1),W=(0,o.useRef)(null),O=(0,o.useRef)(0),X=(0,o.useRef)(null);(0,o.useEffect)(function(){var n=function(n){return a(n)};return i().eventCenter.on(l.Wo,n),function(){i().eventCenter.off(l.Wo,n)}},[]),(0,o.useEffect)(function(){var n=function(n){!n||"dark"!==n.theme&&"light"!==n.theme||((0,s.Rq)(n.theme),"auto"===(0,s.O4)()&&a(n.theme))},e=i();return e.onThemeChange&&e.onThemeChange(n),function(){e.offThemeChange&&e.offThemeChange(n)}},[]),(0,o.useEffect)(function(){var n=function(n){var e=i().getCurrentInstance().router,t=e&&e.path?e.path:"pages/index/index";q(S(n||t))};return i().eventCenter.on("tabBarChange",n),function(){i().eventCenter.off("tabBarChange",n)}},[]),(0,o.useEffect)(function(){(0,f.G)(t)},[t]);var y=function(n){q(S(n)),i().switchTab({url:n}),i().eventCenter.trigger("tabBarChange",n)},B=function(n){R.current||n===g||y(n)},F=function(n){var e=n.touches&&n.touches[0];if(e){var t=m(i().getSystemInfoSync().windowWidth);X.current=t,O.current=e.clientX,R.current=!1,I(!1),W.current=null,j(null)}},J=function(n){var e=X.current,t=n.touches&&n.touches[0];if(e&&t){if(!R.current){if(!d(O.current,t.clientX,P))return;R.current=!0,I(!0)}var a=v((t.clientX-e.left)/e.width*100);W.current=a,j(a)}},G=function(n){var e=X.current;if(e){var t;if(R.current){var a;t=p(null!==(a=W.current)&&void 0!==a?a:0,x.length),R.current=!1,I(!1),i().nextTick(function(){W.current=null,j(null)})}else{var c=n.changedTouches&&n.changedTouches[0],r=c?c.clientX:O.current;t=p(v((r-e.left)/e.width*100),x.length)}var u=x[t];u&&u.pagePath!==g&&y(u.pagePath),X.current=null,O.current=0}},L=function(){X.current=null,O.current=0,R.current=!1,I(!1),W.current=null,j(null)},V=Math.max(0,x.findIndex(function(n){return n.pagePath===g}));return(0,b.jsxs)(r.Ss,{className:"tab-bar-root theme-".concat(t),children:[(0,b.jsx)(r.Ss,{className:"tab-bar-gradient"}),(0,b.jsxs)(r.Ss,{className:"custom-tab-bar theme-".concat(t),onTouchStart:F,onTouchMove:J,onTouchEnd:G,onTouchCancel:L,catchMove:!0,children:[(0,b.jsx)(r.Ss,{className:"tab-bar-caustic"}),(0,b.jsx)(r.Ss,{className:"tab-bar-rim"}),(0,b.jsx)(r.Ss,{className:"tab-indicator ".concat(k?"dragging":""),style:{left:"".concat(null===A?(V+.5)*C:A,"%")}}),x.map(function(n){var e=n.pagePath===g;return(0,b.jsxs)(r.Ss,{className:"tab-item ".concat(e?"active":""),onTap:function(){return B(n.pagePath)},onClick:function(){return B(n.pagePath)},children:[(0,b.jsx)(r._V,{className:"tab-icon-img ".concat(e?"active":""),src:e?n.iconActive:n.icon,mode:"aspectFit"}),(0,b.jsx)(r.EY,{className:"tab-label",children:n.label})]},n.pagePath)})]})]})}Component((0,a.createComponentConfig)(q,"custom-tab-bar/index"))}},function(n){var e=function(e){return n(n.s=e)};n.O(0,[907,96,76],function(){return e(7914)});n.O()}]);
|
||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-2
@@ -55,6 +55,5 @@
|
|||||||
"include": []
|
"include": []
|
||||||
},
|
},
|
||||||
"editorSetting": {},
|
"editorSetting": {},
|
||||||
"libVersion": "3.17.0",
|
"libVersion": "3.17.0"
|
||||||
"isGameTourist": false
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,10 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 160rpx;
|
height: 160rpx;
|
||||||
pointer-events: none;
|
// 部分微信基础库对 pointer-events:none 的父节点命中测试不一致,
|
||||||
|
// 可能导致子节点虽然声明 auto 仍收不到点击。根容器直接参与命中,
|
||||||
|
// 背景渐变单独关闭事件,标签区域保持可点击。
|
||||||
|
pointer-events: auto;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,6 +17,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-bar-root.theme-light .tab-bar-gradient {
|
.tab-bar-root.theme-light .tab-bar-gradient {
|
||||||
|
|||||||
@@ -101,6 +101,12 @@ export default function CustomTabBar() {
|
|||||||
Taro.eventCenter.trigger('tabBarChange', url)
|
Taro.eventCenter.trigger('tabBarChange', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tapTab = (url: string) => {
|
||||||
|
// 点击标签时直接切换;拖动手势由 onTouchEnd 统一处理,避免一次手势触发两次跳转。
|
||||||
|
if (isDraggingRef.current || url === activeTab) return
|
||||||
|
switchTab(url)
|
||||||
|
}
|
||||||
|
|
||||||
const startDrag = (e: any) => {
|
const startDrag = (e: any) => {
|
||||||
const touch = e.touches && e.touches[0]
|
const touch = e.touches && e.touches[0]
|
||||||
if (!touch) return
|
if (!touch) return
|
||||||
@@ -181,7 +187,12 @@ export default function CustomTabBar() {
|
|||||||
{TABS.map((tab) => {
|
{TABS.map((tab) => {
|
||||||
const isActive = tab.pagePath === activeTab
|
const isActive = tab.pagePath === activeTab
|
||||||
return (
|
return (
|
||||||
<View key={tab.pagePath} className={`tab-item ${isActive ? 'active' : ''}`}>
|
<View
|
||||||
|
key={tab.pagePath}
|
||||||
|
className={`tab-item ${isActive ? 'active' : ''}`}
|
||||||
|
onTap={() => tapTab(tab.pagePath)}
|
||||||
|
onClick={() => tapTab(tab.pagePath)}
|
||||||
|
>
|
||||||
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
|
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
|
||||||
<Text className='tab-label'>{tab.label}</Text>
|
<Text className='tab-label'>{tab.label}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
height: 88rpx;
|
height: 88rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
@@ -75,6 +76,114 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-clear,
|
||||||
|
.search-reset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 16rpx;
|
||||||
|
min-width: 80rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 72rpx;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
&::after { border: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-clear { flex-shrink: 0; }
|
||||||
|
|
||||||
|
.search-reset {
|
||||||
|
margin-top: 24rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: var(--bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading {
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
.home-section-title { margin: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
display: block;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-section {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
padding: 28rpx 24rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1rpx solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-rail {
|
||||||
|
width: calc(100% + 48rpx);
|
||||||
|
margin: 0 -24rpx -28rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tile {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
width: 252rpx;
|
||||||
|
height: 168rpx;
|
||||||
|
margin: 0 0 28rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
vertical-align: top;
|
||||||
|
background: var(--bg-muted);
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tile:last-child { margin-right: 24rpx; }
|
||||||
|
|
||||||
|
.category-tile-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tile-shade {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-height: 84rpx;
|
||||||
|
padding: 14rpx 16rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: linear-gradient(transparent, rgba(20, 18, 16, 0.78));
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tile-name {
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 27rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tile-action {
|
||||||
|
margin-top: 5rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 20rpx;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommend-section {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
padding-top: 32rpx;
|
||||||
|
border-top: 2rpx solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results-section { margin-top: 32rpx; }
|
||||||
|
|
||||||
/* 区块标题 */
|
/* 区块标题 */
|
||||||
.home-section-title {
|
.home-section-title {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
+50
-54
@@ -1,4 +1,4 @@
|
|||||||
import { View, Text, Image, Input, Button, Swiper, SwiperItem } from '@tarojs/components'
|
import { View, Text, Image, Input, Button, Swiper, SwiperItem, ScrollView } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
@@ -70,7 +70,7 @@ const PRODUCT_IMG_MAP: Record<string, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
const { theme, resolvedTheme } = useThemeContext()
|
const { resolvedTheme } = useThemeContext()
|
||||||
const safe = useSafeArea()
|
const safe = useSafeArea()
|
||||||
useStatusBar(resolvedTheme)
|
useStatusBar(resolvedTheme)
|
||||||
const [searchKey, setSearchKey] = useState('')
|
const [searchKey, setSearchKey] = useState('')
|
||||||
@@ -81,20 +81,11 @@ export default function Index() {
|
|||||||
Taro.navigateTo({ url: `/pages/product/index?id=${categoryId}` })
|
Taro.navigateTo({ url: `/pages/product/index?id=${categoryId}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigateFromShowcase = (item: { categoryId?: string; title: string }) => {
|
const keyword = searchKey.trim().toLocaleLowerCase()
|
||||||
if (item.categoryId) {
|
const isSearching = keyword.length > 0
|
||||||
navigateToProduct(item.categoryId)
|
const filteredCategories = isSearching
|
||||||
return
|
|
||||||
}
|
|
||||||
Taro.showToast({
|
|
||||||
title: `“${item.title}”定制通道即将开放`,
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredCategories = searchKey.trim()
|
|
||||||
? products.filter(
|
? products.filter(
|
||||||
(c) => c.name.includes(searchKey) || c.desc.includes(searchKey)
|
(c) => [c.name, c.desc, c.description].some(value => value?.toLocaleLowerCase().includes(keyword))
|
||||||
)
|
)
|
||||||
: products
|
: products
|
||||||
|
|
||||||
@@ -125,19 +116,22 @@ export default function Index() {
|
|||||||
onInput={handleSearch}
|
onInput={handleSearch}
|
||||||
confirmType='search'
|
confirmType='search'
|
||||||
/>
|
/>
|
||||||
|
{searchKey.length > 0 && (
|
||||||
|
<Button className='search-clear' onClick={() => setSearchKey('')}>清除</Button>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
{searchKey.trim() && (
|
{isSearching && (
|
||||||
<View className='search-result-hint'>
|
<View className='search-result-hint'>
|
||||||
<Text className='hint-text'>
|
<Text className='hint-text'>
|
||||||
{filteredCategories.length > 0
|
{filteredCategories.length > 0
|
||||||
? `找到 ${filteredCategories.length} 个相关品类`
|
? `找到 ${filteredCategories.length} 件相关商品`
|
||||||
: '没有找到相关品类,试试看其他关键词'}
|
: '没有找到相关商品,试试看其他关键词'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 定制成品展示 */}
|
{/* 定制成品展示 */}
|
||||||
<View className='showcase-section'>
|
{!isSearching && <View className='showcase-section'>
|
||||||
<Text className='home-section-title'>定制成品展示</Text>
|
<Text className='home-section-title'>定制成品展示</Text>
|
||||||
<Swiper
|
<Swiper
|
||||||
className='showcase-swiper'
|
className='showcase-swiper'
|
||||||
@@ -164,11 +158,40 @@ export default function Index() {
|
|||||||
</SwiperItem>
|
</SwiperItem>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
</View>
|
</View>}
|
||||||
|
|
||||||
{/* 热门品类 */}
|
{/* 品类是快捷入口,与下方商品推荐采用不同布局。 */}
|
||||||
<View className='category-section'>
|
{!isSearching && (
|
||||||
<Text className='home-section-title'>热门品类</Text>
|
<View className='category-section'>
|
||||||
|
<View className='section-heading'>
|
||||||
|
<Text className='home-section-title'>热门品类</Text>
|
||||||
|
<Text className='section-subtitle'>按品类,快速开启定制</Text>
|
||||||
|
</View>
|
||||||
|
<ScrollView className='category-rail' scrollX enhanced showScrollbar={false}>
|
||||||
|
{products.map(cat => (
|
||||||
|
<View className='category-tile' key={cat.id} onTap={() => navigateToProduct(cat.id)}>
|
||||||
|
<ProductImage
|
||||||
|
className='category-tile-image'
|
||||||
|
src={cat.images[0] || PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
|
||||||
|
fallback={getProductIconImg(cat)}
|
||||||
|
mode='aspectFill'
|
||||||
|
/>
|
||||||
|
<View className='category-tile-shade'>
|
||||||
|
<Text className='category-tile-name'>{cat.name}</Text>
|
||||||
|
<Text className='category-tile-action'>去定制</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 搜索与推荐互斥,共用后端商品卡片。 */}
|
||||||
|
<View className={isSearching ? 'search-results-section' : 'recommend-section'}>
|
||||||
|
<View className='section-heading'>
|
||||||
|
<Text className='home-section-title'>{isSearching ? '搜索结果' : '为你推荐'}</Text>
|
||||||
|
{!isSearching && <Text className='section-subtitle'>挑一件好物,留下你的专属印记</Text>}
|
||||||
|
</View>
|
||||||
<View className='home-grid'>
|
<View className='home-grid'>
|
||||||
{filteredCategories.map((cat) => (
|
{filteredCategories.map((cat) => (
|
||||||
<View
|
<View
|
||||||
@@ -179,7 +202,7 @@ export default function Index() {
|
|||||||
<View className='media-card-image'>
|
<View className='media-card-image'>
|
||||||
<ProductImage
|
<ProductImage
|
||||||
className='media-card-img'
|
className='media-card-img'
|
||||||
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
|
src={cat.images[0] || PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
|
||||||
fallback={getProductIconImg(cat)}
|
fallback={getProductIconImg(cat)}
|
||||||
mode='aspectFill'
|
mode='aspectFill'
|
||||||
/>
|
/>
|
||||||
@@ -195,40 +218,13 @@ export default function Index() {
|
|||||||
{filteredCategories.length === 0 && (
|
{filteredCategories.length === 0 && (
|
||||||
<View className='empty-category'>
|
<View className='empty-category'>
|
||||||
<Image className='empty-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
|
<Image className='empty-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
|
||||||
<Text className='empty-text'>未找到匹配的品类</Text>
|
<Text className='empty-text'>{isSearching ? '未找到匹配的商品' : '暂无在售商品'}</Text>
|
||||||
<Text className='empty-sub'>尝试搜索“笔记本”、“杯垫”等</Text>
|
{isSearching && <Text className='empty-sub'>尝试搜索“笔记本”、“杯垫”等</Text>}
|
||||||
|
{isSearching && <Button className='search-reset' onClick={() => setSearchKey('')}>清除搜索,返回首页</Button>}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 为你推荐 */}
|
|
||||||
<View className='recommend-section'>
|
|
||||||
<Text className='home-section-title'>为你推荐</Text>
|
|
||||||
<View className='home-grid'>
|
|
||||||
{SHOWCASE_LIST.slice(0, 4).map((item, idx) => (
|
|
||||||
<View
|
|
||||||
key={idx}
|
|
||||||
className='media-card'
|
|
||||||
onTap={() => navigateFromShowcase(item)}
|
|
||||||
>
|
|
||||||
<View className='media-card-image'>
|
|
||||||
<ProductImage
|
|
||||||
className='media-card-img'
|
|
||||||
src={item.image}
|
|
||||||
fallback={getProductIconImg(CATEGORIES.find(category => category.id === item.categoryId))}
|
|
||||||
mode='aspectFill'
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View className='media-card-body'>
|
|
||||||
<Text className='media-card-title'>{item.title}</Text>
|
|
||||||
<Text className='media-card-desc'>{item.desc}</Text>
|
|
||||||
<Text className='media-card-price'>{item.priceText}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -282,7 +282,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: calc(env(safe-area-inset-top, 20px) + 20rpx);
|
top: calc(env(safe-area-inset-top, 20px) + 20rpx);
|
||||||
left: 30rpx;
|
left: 30rpx;
|
||||||
z-index: 50;
|
z-index: 1000;
|
||||||
width: 80rpx;
|
width: 80rpx;
|
||||||
height: 80rpx;
|
height: 80rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -294,6 +294,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
pointer-events: auto;
|
||||||
transition: opacity 0.2s ease, transform 0.15s ease;
|
transition: opacity 0.2s ease, transform 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { View, Text, ScrollView } from '@tarojs/components'
|
import { View, Text, ScrollView } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { useState, useEffect, useCallback, useMemo } from 'react'
|
import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { PRODUCTS } from '../../../utils/productConfig'
|
import { PRODUCTS } from '../../../utils/productConfig'
|
||||||
import { fetchProduct } from '../../../utils/api/product'
|
import { fetchProduct } from '../../../utils/api/product'
|
||||||
@@ -9,7 +9,6 @@ import { useSafeArea } from '../../../hooks/useSafeArea'
|
|||||||
import { useStatusBar } from '../../../hooks/useStatusBar'
|
import { useStatusBar } from '../../../hooks/useStatusBar'
|
||||||
import { useThemeContext } from '../../../context/ThemeContext'
|
import { useThemeContext } from '../../../context/ThemeContext'
|
||||||
import ThemedPageMeta from '../../../components/ThemedPageMeta'
|
import ThemedPageMeta from '../../../components/ThemedPageMeta'
|
||||||
import ScrollTopMask from '../../../components/ScrollTopMask'
|
|
||||||
import BottomActionBar from '../../../components/BottomActionBar'
|
import BottomActionBar from '../../../components/BottomActionBar'
|
||||||
import ProductImage from '../../../components/ProductImage'
|
import ProductImage from '../../../components/ProductImage'
|
||||||
|
|
||||||
@@ -21,6 +20,8 @@ export default function ShopDetailPage() {
|
|||||||
const { resolvedTheme } = useThemeContext()
|
const { resolvedTheme } = useThemeContext()
|
||||||
const [winHeight, setWinHeight] = useState(667)
|
const [winHeight, setWinHeight] = useState(667)
|
||||||
const [progress, setProgress] = useState(0)
|
const [progress, setProgress] = useState(0)
|
||||||
|
const scrollProgressRef = useRef(0)
|
||||||
|
const scrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
const safe = useSafeArea()
|
const safe = useSafeArea()
|
||||||
// 顶部为沉浸式商品图,状态栏始终使用白字。
|
// 顶部为沉浸式商品图,状态栏始终使用白字。
|
||||||
useStatusBar(resolvedTheme, { mode: 'light' })
|
useStatusBar(resolvedTheme, { mode: 'light' })
|
||||||
@@ -28,12 +29,29 @@ export default function ShopDetailPage() {
|
|||||||
const routerParams = Taro.getCurrentInstance().router
|
const routerParams = Taro.getCurrentInstance().router
|
||||||
const routerParamsValues = routerParams ? routerParams.params : undefined
|
const routerParamsValues = routerParams ? routerParams.params : undefined
|
||||||
const productId = routerParamsValues ? routerParamsValues.id : ''
|
const productId = routerParamsValues ? routerParamsValues.id : ''
|
||||||
const [product, setProduct] = useState<ProductCategory | undefined>(PRODUCTS.find(p => p.id === productId))
|
const localProduct = useMemo(() => PRODUCTS.find(p => p.id === productId), [productId])
|
||||||
|
const [product, setProduct] = useState<ProductCategory | undefined>(localProduct)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!productId) return
|
if (!productId) return
|
||||||
fetchProduct(productId).then(setProduct).catch(() => { /* 保留本地兜底 */ })
|
fetchProduct(productId).then(remote => {
|
||||||
}, [productId])
|
// 服务端优先,但介绍文案、规格和图片缺失时保留本地完整资料。
|
||||||
|
if (!localProduct) {
|
||||||
|
setProduct(remote)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setProduct({
|
||||||
|
...localProduct,
|
||||||
|
...remote,
|
||||||
|
description: remote.description || localProduct.description,
|
||||||
|
story: remote.story || localProduct.story,
|
||||||
|
scene: remote.scene || localProduct.scene,
|
||||||
|
tags: remote.tags?.length ? remote.tags : localProduct.tags,
|
||||||
|
specs: remote.specs?.length ? remote.specs : localProduct.specs,
|
||||||
|
images: remote.images?.length ? remote.images : localProduct.images,
|
||||||
|
})
|
||||||
|
}).catch(() => setProduct(localProduct))
|
||||||
|
}, [localProduct, productId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
@@ -44,19 +62,25 @@ export default function ShopDetailPage() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// 恢复原有的沉浸式收束动画;每帧只合并一次滚动状态,避免连续 setState 堆积。
|
||||||
const handleScroll = useCallback((e: any) => {
|
const handleScroll = useCallback((e: any) => {
|
||||||
const st = (e.detail && e.detail.scrollTop) || 0
|
const scrollTop = (e.detail && e.detail.scrollTop) || 0
|
||||||
const total = winHeight * 1.2
|
scrollProgressRef.current = clamp(scrollTop / (winHeight * 1.2), 0, 1)
|
||||||
const p = clamp(st / total, 0, 1)
|
if (scrollTimerRef.current !== null) return
|
||||||
setProgress(p)
|
scrollTimerRef.current = setTimeout(() => {
|
||||||
|
scrollTimerRef.current = null
|
||||||
|
setProgress(current => Math.abs(current - scrollProgressRef.current) < 0.002 ? current : scrollProgressRef.current)
|
||||||
|
}, 16)
|
||||||
}, [winHeight])
|
}, [winHeight])
|
||||||
|
|
||||||
/* Scroll-progress → multi-stage hero & content animations */
|
useEffect(() => () => {
|
||||||
|
if (scrollTimerRef.current !== null) clearTimeout(scrollTimerRef.current)
|
||||||
|
}, [])
|
||||||
|
|
||||||
const heroStyles = useMemo(() => {
|
const heroStyles = useMemo(() => {
|
||||||
const p = progress
|
const p = progress
|
||||||
|
let topCrop = 0
|
||||||
// 1. Image crop insets (vh %)
|
let bottomCrop = 0
|
||||||
let topCrop = 0, bottomCrop = 0
|
|
||||||
if (p <= 0.4) {
|
if (p <= 0.4) {
|
||||||
const t = easeOut(p / 0.4)
|
const t = easeOut(p / 0.4)
|
||||||
topCrop = lerp(0, 32, t)
|
topCrop = lerp(0, 32, t)
|
||||||
@@ -66,60 +90,36 @@ export default function ShopDetailPage() {
|
|||||||
topCrop = lerp(32, 34, t)
|
topCrop = lerp(32, 34, t)
|
||||||
bottomCrop = lerp(38, 41, t)
|
bottomCrop = lerp(38, 41, t)
|
||||||
} else {
|
} else {
|
||||||
topCrop = 34; bottomCrop = 41
|
topCrop = 34
|
||||||
|
bottomCrop = 41
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Hero translateY
|
const translateY = p <= 0.4 ? 0 : p <= 0.7 ? lerp(0, -75, (p - 0.4) / 0.3) : -75
|
||||||
let translateY = 0
|
const heroInfoOpacity = p <= 0.35 ? 1 : p <= 0.48 ? clamp(1 - (p - 0.35) / 0.13, 0, 1) : 0
|
||||||
if (p <= 0.4) translateY = 0
|
const bandOpacity = p <= 0.55 ? 0 : p <= 0.7 ? (p - 0.55) / 0.15 : 1
|
||||||
else if (p <= 0.7) translateY = lerp(0, -75, (p - 0.4) / 0.3)
|
const contentOpacity = p <= 0.05 ? 0 : p <= 0.22 ? easeOut((p - 0.05) / 0.17) : 1
|
||||||
else translateY = -75
|
const contentOffset = p <= 0.05 ? 60 : p <= 0.22 ? lerp(60, 0, easeOut((p - 0.05) / 0.17)) : 0
|
||||||
|
return { topCrop, bottomCrop, translateY, heroInfoOpacity, bandOpacity, contentOpacity, contentOffset, visibleHeight: 100 - topCrop - bottomCrop }
|
||||||
// 3. Hero bottom info opacity (always visible on open, fades after scroll)
|
|
||||||
let heroInfoOpacity = 1
|
|
||||||
if (p <= 0.35) heroInfoOpacity = 1
|
|
||||||
else if (p <= 0.48) heroInfoOpacity = clamp(1 - (p - 0.35) / 0.13, 0, 1)
|
|
||||||
else heroInfoOpacity = 0
|
|
||||||
|
|
||||||
// 4. Transition band opacity
|
|
||||||
let bandOpacity = 0
|
|
||||||
if (p <= 0.55) bandOpacity = 0
|
|
||||||
else if (p <= 0.7) bandOpacity = (p - 0.55) / 0.15
|
|
||||||
else bandOpacity = 1
|
|
||||||
|
|
||||||
// 5. Content reveal
|
|
||||||
let contentOpacity = 1, contentOffset = 0
|
|
||||||
if (p <= 0.05) { contentOpacity = 0; contentOffset = 60 }
|
|
||||||
else if (p <= 0.22) {
|
|
||||||
const t = (p - 0.05) / 0.17
|
|
||||||
contentOpacity = easeOut(t)
|
|
||||||
contentOffset = lerp(60, 0, easeOut(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Back button (fade out as hero scrolls)
|
|
||||||
let backBtnOpacity = 1
|
|
||||||
if (p <= 0.15) backBtnOpacity = clamp(1 - p / 0.15, 0, 1)
|
|
||||||
|
|
||||||
return {
|
|
||||||
topCrop,
|
|
||||||
bottomCrop,
|
|
||||||
translateY,
|
|
||||||
heroInfoOpacity,
|
|
||||||
bandOpacity,
|
|
||||||
contentOpacity,
|
|
||||||
contentOffset,
|
|
||||||
backBtnOpacity,
|
|
||||||
visibleHeight: 100 - topCrop - bottomCrop
|
|
||||||
}
|
|
||||||
}, [progress])
|
}, [progress])
|
||||||
|
|
||||||
const tone = useMemo(() => (product ? product.tone : [28, 22, 18]), [product])
|
const tone = useMemo(() => (product ? product.tone : [28, 22, 18]), [product])
|
||||||
|
const productDescription = product?.description || product?.subtitle || product?.desc || ''
|
||||||
|
const leavingRef = useRef(false)
|
||||||
|
|
||||||
|
const returnToShop = () => {
|
||||||
|
// 详情页的稳定出口是商品 Tab,避免开发者工具直达页面或异常页面栈导致返回失效。
|
||||||
|
if (leavingRef.current) return
|
||||||
|
leavingRef.current = true
|
||||||
|
const target = { url: '/pages/shop/index' }
|
||||||
|
Taro.switchTab(target).catch(() => Taro.reLaunch(target)).catch(() => {
|
||||||
|
leavingRef.current = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
return (
|
return (
|
||||||
<View className="shop-detail-page theme-dark">
|
<View className="shop-detail-page theme-dark">
|
||||||
<ThemedPageMeta darkTop />
|
<ThemedPageMeta darkTop />
|
||||||
<ScrollTopMask title="商品详情" targetSelector=".shop-back-btn" showBack />
|
|
||||||
<Text style={{ color: '#fff', padding: '40rpx' }}>商品不存在</Text>
|
<Text style={{ color: '#fff', padding: '40rpx' }}>商品不存在</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -128,7 +128,6 @@ export default function ShopDetailPage() {
|
|||||||
return (
|
return (
|
||||||
<View className="shop-detail-page theme-dark">
|
<View className="shop-detail-page theme-dark">
|
||||||
<ThemedPageMeta darkTop />
|
<ThemedPageMeta darkTop />
|
||||||
<ScrollTopMask title="商品详情" targetSelector=".shop-back-btn" showBack />
|
|
||||||
{/* Fixed Hero */}
|
{/* Fixed Hero */}
|
||||||
<View className="shop-hero-fixed">
|
<View className="shop-hero-fixed">
|
||||||
<View
|
<View
|
||||||
@@ -162,10 +161,7 @@ export default function ShopDetailPage() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View
|
<View className="shop-hero-info" style={{ opacity: heroStyles.heroInfoOpacity }}>
|
||||||
className="shop-hero-info"
|
|
||||||
style={{ opacity: heroStyles.heroInfoOpacity }}
|
|
||||||
>
|
|
||||||
<Text className="shop-hero-title">{product.name}</Text>
|
<Text className="shop-hero-title">{product.name}</Text>
|
||||||
<Text className="shop-hero-subtitle">{product.subtitle || product.desc}</Text>
|
<Text className="shop-hero-subtitle">{product.subtitle || product.desc}</Text>
|
||||||
<View className="shop-hero-price-row">
|
<View className="shop-hero-price-row">
|
||||||
@@ -193,7 +189,7 @@ export default function ShopDetailPage() {
|
|||||||
className="shop-content"
|
className="shop-content"
|
||||||
style={{ backgroundColor: `rgb(${tone[0]}, ${tone[1]}, ${tone[2]})` }}
|
style={{ backgroundColor: `rgb(${tone[0]}, ${tone[1]}, ${tone[2]})` }}
|
||||||
>
|
>
|
||||||
{/* Transition band — appears as hero scrolls away */}
|
{/* 原有的主图收束后,浮动信息条自然接替标题和价格。 */}
|
||||||
<View
|
<View
|
||||||
className="shop-band"
|
className="shop-band"
|
||||||
style={{
|
style={{
|
||||||
@@ -217,20 +213,25 @@ export default function ShopDetailPage() {
|
|||||||
{/* Main copy blocks */}
|
{/* Main copy blocks */}
|
||||||
<View
|
<View
|
||||||
className="shop-detail-body"
|
className="shop-detail-body"
|
||||||
style={{
|
style={{ opacity: heroStyles.contentOpacity, transform: `translateY(${heroStyles.contentOffset}px)` }}
|
||||||
opacity: heroStyles.contentOpacity,
|
|
||||||
transform: `translateY(${heroStyles.contentOffset}px)`
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<View className="shop-content-card">
|
<View className="shop-content-card">
|
||||||
|
<View className="shop-section">
|
||||||
|
<Text className="shop-section-title">商品介绍</Text>
|
||||||
|
<Text className="shop-section-text">{productDescription}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
{product.story && (
|
{product.story && (
|
||||||
<View className="shop-section">
|
<>
|
||||||
<Text className="shop-section-title">设计理念</Text>
|
<View className="shop-divider" />
|
||||||
<Text className="shop-section-text">{product.story}</Text>
|
<View className="shop-section">
|
||||||
</View>
|
<Text className="shop-section-title">设计理念</Text>
|
||||||
|
<Text className="shop-section-text">{product.story}</Text>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(product.story && product.scene) && (
|
{product.scene && (
|
||||||
<View className="shop-divider" />
|
<View className="shop-divider" />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -253,11 +254,11 @@ export default function ShopDetailPage() {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{((product.story || product.scene) && product.tags && product.tags.length > 0) && (
|
{product.tags && product.tags.length > 0 && (
|
||||||
<View className="shop-divider" />
|
<View className="shop-divider" />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{((product.story || product.scene || (product.tags && product.tags.length > 0)) && product.specs && product.specs.length > 0) && (
|
{product.specs && product.specs.length > 0 && (
|
||||||
<View className="shop-divider" />
|
<View className="shop-divider" />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -284,8 +285,9 @@ export default function ShopDetailPage() {
|
|||||||
{/* Back button — glass morphism circle */}
|
{/* Back button — glass morphism circle */}
|
||||||
<View
|
<View
|
||||||
className="shop-back-btn"
|
className="shop-back-btn"
|
||||||
onTap={() => Taro.navigateBack()}
|
onTap={returnToShop}
|
||||||
style={{ top: `${safe.menuButtonTop}px`, opacity: heroStyles.backBtnOpacity }}
|
onClick={returnToShop}
|
||||||
|
style={{ top: `${safe.menuButtonTop}px` }}
|
||||||
>
|
>
|
||||||
<Text className="shop-back-arrow">←</Text>
|
<Text className="shop-back-arrow">←</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -299,7 +301,7 @@ export default function ShopDetailPage() {
|
|||||||
<Text className="summary-original">¥{product.originalPrice}</Text>
|
<Text className="summary-original">¥{product.originalPrice}</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View className="btn-secondary" onTap={() => Taro.navigateBack()}>
|
<View className="btn-secondary" onTap={returnToShop} onClick={returnToShop}>
|
||||||
<Text>返回</Text>
|
<Text>返回</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className="btn-primary" onTap={() => Taro.navigateTo({ url: `/pages/product/index?id=${product.id}` })}>
|
<View className="btn-primary" onTap={() => Taro.navigateTo({ url: `/pages/product/index?id=${product.id}` })}>
|
||||||
|
|||||||
Reference in New Issue
Block a user