基于Stencil.js Router的嵌套与非嵌套路由及页面布局实现问询
Hey there! Let's break down how to build this Web app structure step by step—this is a super common pattern, and we can use component-based thinking to keep things clean, reusable, and easy to maintain.
The key is to split UI elements into independent, reusable components, then use routing to control when to show/hide the tab bar, and which toolbar to render. Here's how to implement it with a component-based framework (we'll use React as an example, but the logic applies to Vue, Svelte, or even vanilla JS):
2.1 Reusable Bottom TabBar Component
This component will be shared across all pages that need the tab bar. We'll use routing to highlight the active tab:
// components/TabBar.js import { NavLink } from 'react-router-dom'; const TabBar = () => { return ( <div className="tab-bar"> <NavLink to="/home" className={({ isActive }) => isActive ? "tab-item active" : "tab-item"} > <span className="tab-icon">🏠</span> <span className="tab-label">Home</span> </NavLink> <NavLink to="/profile" className={({ isActive }) => isActive ? "tab-item active" : "tab-item"} > <span className="tab-icon">👤</span> <span className="tab-label">Profile</span> </NavLink> </div> ); }; export default TabBar;
This component stays consistent across all tabbed pages, with automatic active state highlighting based on the current route.
2.2 Default Toolbar (For Tabbed Pages)
This toolbar includes the button that navigates to the fullscreen page, and can be customized with different titles/actions per page:
// components/DefaultToolbar.js import { useNavigate } from 'react-router-dom'; const DefaultToolbar = ({ title, onExtraAction }) => { const navigate = useNavigate(); const openFullscreenPage = () => { navigate('/fullscreen'); }; return ( <div className="toolbar"> <div className="toolbar-title">{title}</div> <div className="toolbar-actions"> <button onClick={openFullscreenPage} className="toolbar-btn">Open Fullscreen</button> {onExtraAction && ( <button onClick={onExtraAction} className="toolbar-btn">Extra Action</button> )} </div> </div> ); }; export default DefaultToolbar;
Pass in a title and optional onExtraAction prop to reuse this toolbar across all tabbed pages.
2.3 Fullscreen Page Toolbar (With Back Button)
This is a standalone toolbar for the fullscreen page—no tab bar here, and it includes a back button to return to the previous tabbed page:
// components/FullscreenToolbar.js import { useNavigate } from 'react-router-dom'; const FullscreenToolbar = ({ title, onCustomAction }) => { const navigate = useNavigate(); const goBack = () => { navigate(-1); // Go back to the last visited page }; return ( <div className="fullscreen-toolbar"> <button onClick={goBack} className="toolbar-btn">← Back</button> <div className="toolbar-title">{title}</div> <div className="toolbar-actions"> {onCustomAction && ( <button onClick={onCustomAction} className="toolbar-btn">Custom Action</button> )} </div> </div> ); }; export default FullscreenToolbar;
This toolbar has a distinct style and logic tailored to the fullscreen flow.
3.1 Tabbed Page Container
Create a layout component to wrap all tabbed pages—this way you don't have to repeat the tab bar and default toolbar in every page:
// layouts/TabLayout.js import TabBar from '../components/TabBar'; import DefaultToolbar from '../components/DefaultToolbar'; const TabLayout = ({ children, toolbarTitle, toolbarAction }) => { return ( <div className="tab-page-wrapper"> <DefaultToolbar title={toolbarTitle} onExtraAction={toolbarAction} /> <main className="page-content">{children}</main> <TabBar /> </div> ); }; export default TabLayout;
Use this layout for your tabbed pages like Home or Profile:
// pages/Home.js import TabLayout from '../layouts/TabLayout'; const Home = () => { const handleExtraAction = () => { alert('Home page extra action triggered!'); }; return ( <TabLayout toolbarTitle="Home" toolbarAction={handleExtraAction}> <div className="home-content"> <h1>Welcome to the Home Page</h1> <p>This page has the bottom tab bar and default toolbar</p> </div> </TabLayout> ); }; export default Home;
3.2 Fullscreen Page
This page doesn't use the tab layout—it uses the dedicated fullscreen toolbar and takes up the entire viewport:
// pages/FullscreenPage.js import FullscreenToolbar from '../components/FullscreenToolbar'; const FullscreenPage = () => { const handleCustomAction = () => { alert('Fullscreen page custom action triggered!'); }; return ( <div className="fullscreen-wrapper"> <FullscreenToolbar title="Fullscreen Detail" onCustomAction={handleCustomAction} /> <main className="fullscreen-content"> <h1>Fullscreen Page</h1> <p>No bottom tab bar here—only the back-enabled toolbar!</p> </main> </div> ); }; export default FullscreenPage;
3.3 Route Configuration (React Router Example)
Set up routing to map URLs to pages, and let the layout components handle tab bar visibility:
// App.js import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Home from './pages/Home'; import Profile from './pages/Profile'; import FullscreenPage from './pages/FullscreenPage'; function App() { return ( <Router> <Routes> {/* Tabbed pages */} <Route path="/home" element={<Home />} /> <Route path="/profile" element={<Profile />} /> {/* Fullscreen page (no tab bar) */} <Route path="/fullscreen" element={<FullscreenPage />} /> {/* Default route */} <Route path="/" element={<Home />} /> </Routes> </Router> ); } export default App;
Add these styles to ensure proper spacing and visibility:
/* Global reset */ * { margin: 0; padding: 0; box-sizing: border-box; } /* Tabbed page layout */ .tab-page-wrapper { height: 100vh; display: flex; flex-direction: column; } /* Toolbar base styles */ .toolbar { height: 56px; background: #fff; border-bottom: 1px solid #eee; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; } /* Tab bar styles */ .tab-bar { height: 56px; background: #fff; border-top: 1px solid #eee; display: flex; justify-content: space-around; align-items: center; position: fixed; bottom: 0; left: 0; right: 0; } .tab-item { display: flex; flex-direction: column; align-items: center; text-decoration: none; color: #666; } .tab-item.active { color: #1677ff; } /* Fullscreen page layout */ .fullscreen-wrapper { height: 100vh; display: flex; flex-direction: column; } .fullscreen-toolbar { height: 56px; background: #2c3e50; color: #fff; display: flex; align-items: center; padding: 0 16px; gap: 16px; } .fullscreen-toolbar .toolbar-btn { color: #fff; background: transparent; border: none; cursor: pointer; } /* Content area spacing */ .page-content { flex: 1; padding: 16px; padding-bottom: 64px; /* Make space for the fixed tab bar */ overflow-y: auto; } .fullscreen-content { flex: 1; padding: 16px; overflow-y: auto; }
If you're not using React, the logic stays the same:
- Create separate HTML templates for TabBar, DefaultToolbar, and FullscreenToolbar
- Use routing (or hash change listeners) to toggle a
has-tab-barclass on the body, then use CSS to show/hide the tab bar - Load the appropriate toolbar based on the current page
For example, in vanilla JS:
// Listen for hash changes window.addEventListener('hashchange', () => { const isTabbedPage = ['#home', '#profile'].includes(window.location.hash); document.body.classList.toggle('has-tab-bar', isTabbedPage); });
.tab-bar { display: none; } body.has-tab-bar .tab-bar { display: flex; }
内容的提问来源于stack exchange,提问作者sçuçu

