Vue 社区已经有一个官方的路由库了,为何须要另一个?前端
怎么说呢,对于 API 的喜爱每一个人都会不同吧。我是一个比较追求极致体验的人,在以前使用 React 进行开发的时候,我就是一个痴迷于一切皆组件的理念的人,我曾经丧心病狂地尝试封装<Axios>
组件,经过传递 props 来获取数据,没有尝试过的同窗可能不能领会这种近乎于偏执的追求。其实在 React 生态这种尝试很是常见,你任何能想象到的前端技术大概都能找到组件。vue
因此在后来用 Vue 的时候,就很是不习惯各类:ios
可是 Vue3 的 composition API 让我看到了但愿,曾经几乎只能经过 mixin 来扩展的功能,如今有了更好的解决方案。并且我也终于能够摆脱this
了(我真的很是讨厌this
)。我从 19 年接触 Vue3 开始就在研究 JSX 开发方式,在 Vue3 中一切皆组件的目的并不比 React 难,可是社区并无不少人追求这个方向,那么,我就本身作吧。git
因此,就有了 BestVue3 Router 这个库,看完介绍相信大家就能体会到一些这种感觉吧。github
视频教程编程
更多:api
Star、Issue和PR都是对开源最好的支持!markdown
BestVue3 Router 的核心是route的概念。路由表明着一个你应用中的"页面" 。BestVue3 Router 表明着内部包含 URLs 的路由器,也叫作"locations"。BestVue3 Router 让你定义用户访问路由渲染的 VNodes。app
一个简单的有两个页面的网页应用,"home"和"about"可能看起来相似这样:async
import { createApp } from 'vue'
import { BrowserRouter as Router, Routes, Route } from '@bv3/router'
function App() {
return (
<div> <h1>Welcome</h1> <Routes> <Route path="/" element={<Home />} /> <Route path="about" element={<About />} /> </Routes> </div>
)
}
createApp(() => (
<Router> <App /> </Router>
)).mount('#aa')
复制代码
<Router>
element提供当前[location]../api-reference.md#location)的信息给剩余的后代。这个例子使用<BrowserRouter>
。你应该只渲染一个惟一的<Router>
在你的根组件附近。
<Routes>
element是你用来定义有哪些路由以及当路由匹配当前路径时这个<Route>
element应该渲染什么内容。
在这篇教程的接下去的例子中咱们预设你已经引入来 Vue3 而且在<Router>
内渲染<App>
节点,因此咱们简明地只展现须要的<Routes>
内容。
BestVue3 Router 提供了一个 Link
组件你能够用来让你的用户在不一样的页面之间[导航]../api-reference.md#navigation)
import { Routes, Route, Link } from '@bv3/router'
function Home() {
return (
<div> <h1>Home</h1> <nav> <Link to="/">Home</Link> | <Link to="about">About</Link> </nav> </div>
)
}
function About() {
return <h1>About</h1>
}
function App() {
return (
<div> <h1>Welcome</h1> <Routes> <Route path="/" element={<Home />} /> <Route path="about" element={<About />} /> </Routes> </div>
)
}
复制代码
你能够在你的<Route path>
使用动态的:id
-相似部分来提取值用来请求数据或者渲染一些内容。useParams
hook返回一个Ref
对象,其value
是一个包含路径参数的对象。
import { Routes, Route, useParams } from '@bv3/router'
const Invoice = defineComponent({
setup() {
const paramsRef = useParams()
return () => <h1>Invoice {paramsRef.value.invoiceId}</h1>
},
})
function App() {
return (
<Routes> <Route path="invoices/:invoiceId" element={<Invoice />} /> </Routes>
)
}
复制代码
当肯定哪一个路由来渲染的时候,Routes
节点选择和当前位置最匹配的路径,一般是哪些更明确的路径。
好比,path="invoices/sent"
只会匹配/invoices/sent
,因此他比path="invoices/:invoiceId"
在匹配以/invoices
(/invoices/123
, /invoices/cupcakes
, 等)开头的 URL 时更加明确。你能够根据你的喜爱按照任意顺序组织你的代码。
import { Routes, Route, useParams } from '@bv3/router'
function Invoice() {
const { invoiceId } = useParams()
return () => <h1>Invoice {invoiceId}</h1>
}
function SentInvoices() {
return <h1>Sent Invoices</h1>
}
function App() {
return (
<Routes> <Route path="invoices/:invoiceId" element={<Invoice />} /> <Route path="invoices/sent" element={<SentInvoices />} /> </Routes>
)
}
复制代码
Routes may be nested inside one another, and their paths will nest too. Components that are used higher in the route hierarchy may render an <Outlet>
element to render their child routes.
路由能够是嵌套的,他们的路径也会是嵌套的。高层级的路由渲染的组件须要渲染一个 <Outlet>
节点来让他们的子路由能够被渲染。
import { Routes, Route, Outlet } from '@bv3/router'
function Invoices() {
return (
<div>
<h1>Invoices</h1>
{/*
这个节点渲染他的子路由,在这个例子中多是 <SentInvoices> 或者 <IndividualInvoice>
*/}
<Outlet />
</div>
)
}
const IndividualInvoice = defineComponent({
setup() {
const paramseRef = useParams()
return () => <h1>Invoice {paramseRef.value.invoiceId}</h1>
},
})
function SentInvoices() {
return <h1>Sent Invoices</h1>
}
function App() {
return (
<Routes>
<Route path="invoices" element={<Invoices />}>
<Route path=":invoiceId" element={<IndividualInvoice />} />
<Route path="sent" element={<SentInvoices />} />
</Route>
</Routes>
)
}
复制代码
注意在上面这个例子中路由是如何嵌套在父路由中的。这个嵌套的行为在建立导航和容器不变子内容根据路由变化的布局的时候很是有用。
import { Routes, Route, Link, Outlet } from '@bv3/router'
function Layout() {
return (
<div> <h1>Welcome to the app!</h1> <nav> <Link to="invoices">Invoices</Link> |{' '} <Link to="dashboard">Dashboard</Link> </nav> <div className="content"> <Outlet /> </div> </div>
)
}
function Invoices() {
return <h1>Invoices</h1>
}
function Dashboard() {
return <h1>Dashboard</h1>
}
function App() {
return (
<Routes> <Route path="/" element={<Layout />}> <Route path="invoices" element={<Invoices />} /> <Route path="dashboard" element={<Dashboard />} /> </Route> </Routes>
)
}
复制代码
相对的<Link to>
值(不以/
开始) 是相对于渲染他们的路由的路径的。下面的两个连接指向/dashboard/invoices
和/dashboard/team
由于他们都是在<Dashboard>
下渲染的。这在你修改父路径或者从新安排你的组件结构的时候很是好用由于全部你的连接自动会更新。
import { Routes, Route, Link, Outlet } from '@bv3/router'
function Home() {
return <h1>Home</h1>
}
function Dashboard() {
return (
<div> <h1>Dashboard</h1> <nav> <Link to="invoices">Invoices</Link> <Link to="team">Team</Link> </nav> <hr /> <Outlet /> </div>
)
}
function Invoices() {
return <h1>Invoices</h1>
}
function Team() {
return <h1>Team</h1>
}
function App() {
return (
<Routes> <Route path="/" element={<Home />} /> <Route path="dashboard" element={<Dashboard />}> <Route path="invoices" element={<Invoices />} /> <Route path="team" element={<Team />} /> </Route> </Routes>
)
}
复制代码
Nested routes may use path="/"
to indicate they should render at the path of the parent component. You can think about these routes like index pages for the rest of the child routes.
嵌套路由可使用path="/"
来代表他们应该在他的父路由的路径下渲染。你能够认为这些路由就像其余子路由的主页。
function App() {
return (
<Routes> <Route path="/" element={<Home />} /> <Route path="dashboard" element={<Dashboard />}> <Route path="/" element={<DashboardHome />} /> <Route path="invoices" element={<DashboardInvoices />} /> </Route> </Routes>
)
}
复制代码
When no other route matches the URL, you can render a "not found" route using path="*"
. This route will match any URL, but will have the weakest precedence so the router will only pick it if no other routes match.
当没有其余路由匹配的时候,你可使用path="*"
渲染一个"not found"路由。这个路由会匹配任何 URL,但也会具备最弱的优先级,因此路由器只会在找不到其余匹配的路由的状况下选择他。
function App() {
return (
<Routes> <Route path="/" element={<Home />} /> <Route path="dashboard" element={<Dashboard />} /> <Route path="*" element={<NotFound />} /> </Routes>
)
}
复制代码
虽然在你的应用中应该只有一个<Router>
,你能够根据须要有多个<Routes>
。每一个<Routes>
独立地选择子路由进行渲染。
function App() {
return (
<div> <Sidebar> <Routes> <Route path="/" element={<MainNav />} /> <Route path="dashboard" element={<DashboardNav />} /> </Routes> </Sidebar> <MainContent> <Routes> <Route path="/" element={<Home />}> <Route path="about" element={<About />} /> <Route path="support" element={<Support />} /> </Route> <Route path="dashboard" element={<Dashboard />}> <Route path="invoices" element={<Invoices />} /> <Route path="team" element={<Team />} /> </Route> <Route path="*" element={<NotFound />} /> </Routes> </MainContent> </div>
)
}
复制代码
你能够在任何你须要的地方渲染<Routes>
节点,包括在其余<Routes>
的子树中。除了他们会自动在渲染他们的路由的基础上构建路径以外,他们跟其余<Routes>
同样正常工做。若是你须要这么作,请确保在父路由的路径最后放上*。否则的话父路由不会匹配比他路径长的 URL,你的后辈<Routes>
永远不会展现。
function Dashboard() {
return (
<div> <p>Look, more routes!</p> <Routes> <Route path="/" element={<DashboardGraphs />} /> <Route path="invoices" element={<InvoiceList />} /> </Routes> </div>
)
}
function App() {
return (
<Routes> <Route path="/" element={<Home />} /> <Route path="dashboard/*" element={<Dashboard />} /> </Routes>
)
}
复制代码
If you need to navigate programmatically (like after the user submits a form), use the useNavigate
hook to get a function you can use to navigate.
若是你须要编程式地导航(好比在用户提交表单以后),使用useNavigate
钩子来获取一个函数帮你进行导航。
import { useNavigate } from '@bv3/router'
const Invoices = defineComponent({
setup() {
const navigate = useNavigate()
return () => (
<div> <NewInvoiceForm onSubmit={async event => { const newInvoice = await createInvoice(event.target) navigate(`/invoices/${newInvoice.id}`) }} /> </div>
)
},
})
复制代码
以上!这里咱们尚未覆盖全部的 API,可是这些绝对是最通用的场景。若是你想要再深刻学习,你能够查看完整的 API 文档。
对于咱们正在作的事情感兴趣,或者但愿可以学到更多更优质的Vue3知识,能够搜索公众号 BestVue3 关注,提供更优质的Vue3内容。