注:本教程基于尚硅谷react-router-dom6教程。本教程使用react18。
概述
React-Router 是一个可以帮助开发者在 React 应用中实现路由功能的第三方库。它提供了一组 API 和组件来管理应用程序的 URL 和页面切换。使用 React-Router,可以将每个页面的路由路径与组件关联起来,当用户访问特定的 URL 时,渲染相应的组件。
React-Router 的 API 包括以下几个主要的组件:
- BrowserRouter:使用 HTML5 history API,在应用程序中提供基于浏览器的导航。
- HashRouter:使用散列值(hash)在应用程序中提供客户端路由。
- Route:渲染与指定 URL 匹配的组件。
- Switch:渲染第一个与当前 URL 匹配的 Route 或 Redirect。
- Link:生成带有指定 URL 的锚标记()以导航到不同的路由。
除了这些主要组件之外,React-Router 还提供了其他一些有用的组件和 API,如 Redirect、withRouter 和 useHistory 等。
React-Router 有以下几个库:
- react-router:React Router 的核心库,提供基础功能,如 Route、Link、history 等。
- react-router-dom:是针对 Web 应用的库,提供了 BrowserRouter、HashRouter 等路由组件。
- react-router-native:是针对移动端应用的库,提供了 NativeRouter、MemoryRouter 等路由组件。
- react-router-config:提供了静态路由配置的能力,并且可以在服务端使用。
- react-router-redux:将 React-Router 和 Redux 集成,可以将路由状态同步到 Redux Store 中。
前端开发中,我们主要关注react-router-dom
React-Router的基础用法
项目搭建
我们使用react-ceate-app搭建一个基础的react项目,然后安环react-router-dom
npm i react-router-dom
创建如下结构目录
├─ package.json
├─ public
│ ├─ bootstrap.css
│ ├─ favicon.ico
│ └─ index.html
├─ README.md
├─ src
│ ├─ App.jsx
│ ├─ index.js
│ └─ pages
│ ├─ About.jsx
│ └─ Home.jsx
样式不是我们本教程的重点,因此直接使用了bootstrap.css中定义的一些样式。如果你需要这个文件,请从云盘下载
链接: pan.baidu.com/s/1OPY3aYsK… 提取码: a2fq
注意,需要在index.html中引入bootstrp的样式
react-router-dom引入
入口文件index.js
import React from "react";
import ReactDOM from "react-dom/client";
// 导入 BrowserRouter 组件
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
BrowserRouter 是 React Router 库提供的一种路由组件,它使用 HTML5 中的 history API 来实现路由的跳转,并支持浏览器的前进后退等操作。
在 React 应用中使用 BrowserRouter 可以方便地实现页面的路由跳转和组件的渲染。使用时,需要将一个组件树放在一个 中,然后在组件中来设置路由跳转和组件渲染的规则。
路由导航设置NavLink和Link
代码及效果
App.jsx
import React from "react";
import { NavLink, Routes, Route } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
export default function App() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header">
<h2>React Router Demo</h2>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 路由链接 */}
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About />}></Route>
<Route path="/about" element={<Home />}></Route>
</Routes>
</div>
</div>
</div>
</div>
</div>
);
}
src\pages\Home.jsx
import React from "react";
export default function Home() {
return (
<div>
<h3>我是Home的内容</h3>
</div>
);
}
src\pages\About.jsx
import React from "react";
export default function About() {
return (
<div>
<h3>我是About的内容</h3>
</div>
);
}
页面效果
NavLink和Link
设置路由的第一步,需要使用NavLink标签或者Link标签,指定跳转的路由路径。
<NavLink className="list-group-item" to="/about">
About
</NavLink>
上述代码中,通过设置 to 属性来导航到指定的路由路径
NavLink 和 Link 都是 React Router 库中的组件,用于实现页面路由导航,让用户可以在单页应用中自由地切换页面视图。
Link 组件是最简单的路由导航器,它可以通过设置 to 属性来导航到指定的路由路径。例如:
<Link className="list-group-item" to="/about">
About
</Link>
NavLink的高亮效果
NavLink 组件在实现路由导航功能的同时,还提供了一些额外的样式控制功能,例如可以为当前活跃路由添加自定义样式或类名。使用时,将className的返回值写成一个函数即可
// src\App.jsx
<div className="list-group">
{/* 路由链接 */}
<NavLink className={({ isActive }) => (isActive ? "list-group-item myCustomClassName" : "list-group-item")} to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
</div>
// 引入自定义样式内容
.myCustomClassName {
background: red !important;
}
页面效果
在这个例子中,className 属性是一个函数,函数返回了样式类名。这个匿名函数接受一个参数
<NavLink className={(a) => {console.log(a);}} to="/about">
About
</NavLink>
参数是一个对象,包含isActive属性,因此,我们可以借助结构赋值方式拿到isActive。
路由组件配置Routes 和 Route
Routes 和 Route 是 react-router-dom 包提供的两个组件,用于在 React 应用程序中进行路由。它们的作用如下:
- Routes 组件是一个容器,用于定义一组 Route 组件。它内部可以包含零个或多个 Route 组件,并根据 URL 匹配其中的一个 Route 组件来渲染。
- Route 组件用于定义路由。它包括一个路径(path)和一个组件(element)。当 URL 匹配该路径时,该组件将被渲染到页面上。可以在 Route 组件中定义其他属性和方法,以根据需要实现更高级的路由功能。
例如,本示例中使用 Routes 和 Route 组件设置基本路由的示例代码:
import React from "react";
import { NavLink, Routes, Route } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
<div className="panel-body">
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About />}></Route>
<Route path="/home" element={<Home />}></Route>
</Routes>
</div>
上面的代码当 URL 匹配 /home 或 /about 时,分别加载对应的组件。
route的 caseSensitive属性
“caseSensitive”用于指定路由匹配是否区分大小写。如果设置为true,则路由匹配将区分大小写。如果设置为false,则路由匹配将不区分大小写。
路由重定向Navigate
根据上图示例,我们会发现一个问题,当url处于http://localhost:3000/时,控制台会有警告
因为,这个时候没有“/”没有对应任何路由组件。我们可以使页面处于跟路由“/”时,让他重定向到about组件,解决这个问题。
import { NavLink, Routes, Route, Navigate } from "react-router-dom";
<div className="panel-body">
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About />}></Route>
<Route path="/home" element={<Home />}></Route>
<Route path="/" element={<Navigate to="/about" />}></Route>
</Routes>
</div>
Navigate 是 react-router-dom 4.0+ 版本中的一个组件,它可以通过编程方式导航到一个特定的路由。它的用法有些类似于 Link 组件和 history.push 方法,但它可以根据一些条件来激活导航。我们看一个新demo
import { Navigate } from 'react-router-dom';
function App({ isAuth }) {
return (
{isAuth ? <Dashboard /> : <Navigate to="/login" />}
);
}
在上面的代码中,我们使用了 Navigate 组件来导航到登录页面(即 to=”/login”),当 isAuth 的值为 false 时,会自动触发导航。当 isAuth 的值为 true 时,将会显示 组件和对应子路由。
Navigate的渲染机制
Navigate只要一渲染,就会引起视图变化。我们在Home组件中添加一写代码
import React, { useState } from "react";
import { Navigate } from "react-router-dom";
export default function Home() {
const [sum, setSum] = useState(1);
return (
<div>
<h3>我是Home的内容</h3>
{sum === 2 ? <Navigate to="/about" /> : <h4>当前sum的值是:{sum}</h4>}
<button onClick={() => setSum(2)}>点击将我变成2</button>
</div>
);
}
根据上述代码,我们点击按钮时,sum === 2为真,Navigate组件渲染,然后自动跳转到了about组件
Navigate的repalce属性
replace 是 Navigate 组件的一个属性,用于在导航时替换当前的路由历史记录而不是添加新的记录。
在 React Router 中,导航时会将新的路由历史记录添加到栈顶,这会增加浏览器的回退次数和前进次数。但是,在某些情况下,这不是我们想要的行为,因为某些路由可能不应该添加到历史记录中。这时就可以通过设置 replace 属性来解决这个问题。
export default function Home() {
const [sum, setSum] = useState(1);
return (
<div>
<h3>我是Home的内容</h3>
{sum === 2 ? <Navigate to="/about" replace /> : <h4>当前sum的值是:{sum}</h4>}
<button onClick={() => setSum(2)}>点击将我变成2</button>
</div>
);
}
在上面的代码中,我们将 replace 属性设置为 true,以便使用 Navigate 组件进行路由导航时替换当前的路由历史记录。这意味着在路由导航后,浏览器的回退次数和前进次数将不会增加。
useRoutes路由表
useRoutes的使用
上述例子中。我们注册路由是这样实现的
<div className="panel-body">
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About />}></Route>
<Route path="/home" element={<Home />}></Route>
<Route path="/" element={<Navigate to="/about" />}></Route>
</Routes>
</div>
当组件很多时,这样写非常累赘,我们可以通过useRoutes解决这一问题
import React from "react";
import { NavLink, Routes, Route, Navigate, useRoutes } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
export default function App() {
// 定义路由表
const ele = useRoutes([
{ path: "/about", element: <About /> },
{ path: "/home", element: <Home /> },
{ path: "/", element: <Navigate to="/about" /> },
]);
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header">
<h2>React Router Demo</h2>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 路由链接 */}
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
{ele}
</div>
</div>
</div>
</div>
</div>
);
}
useRoutes是React Router v6中的一个Hook,用于定义和渲染路由。它接受一个配置对象作为参数,该对象用于定义路由规则和对应的组件。
例如,上述代码定义了三个路由规则,分别对应不同的组件:
const ele = useRoutes([
{ path: "/about", element: <About /> },
{ path: "/home", element: <Home /> },
{ path: "/", element: <Navigate to="/about" /> },
]);
useRoutes Hook返回的变量可以直接作为组件返回的jsx中的内容来渲染路由。
<div className="panel-body">
{/* 注册路由 */}
{ele}
</div>
项目中的优化
真实项目开发中,我们一般将配置文件抽离,方便管理
我们在src文件夹下创建routes文件夹,并创建index.js
import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
export default [
{ path: "/about", element: <About /> },
{ path: "/home", element: <Home /> },
{ path: "/", element: <Navigate to="/about" /> },
];
然后,我们在App.js中使用即可
import React from "react";
import { NavLink, useRoutes } from "react-router-dom";
import routes from "./routes";
export default function App() {
const ele = useRoutes(routes);
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header">
<h2>React Router Demo</h2>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 路由链接 */}
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
{ele}
</div>
</div>
</div>
</div>
</div>
);
}
嵌套路由
嵌套路由的使用
接下来,我们实现如图所示的嵌套路由效果。Home页面下的tab选项卡,切换时可以跳转到不同的子路由。
要实现嵌套路由,我们需要先创建对应的子路由文件
src\pages\Message.jsx
import React from "react";
export default function Message() {
return (
<div>
<ul>
<li>
<a href="/message1">message001</a>
</li>
<li>
<a href="/message2">message002</a>
</li>
<li>
<a href="/message/3">message003</a>
</li>
</ul>
</div>
);
}
src\pages\News.jsx
import React from "react";
export default function News() {
return (
<ul>
<li>news1</li>
<li>news2</li>
<li>news3</li>
</ul>
);
}
然后,我们在路由表里进行子路由配置
import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Message";
import News from "../pages/News";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{ path: "news", element: <News /> },
{ path: "message", element: <Message /> },
],
},
{ path: "/", element: <Navigate to="/about" /> },
];
子路由配置在父路由对象的children属性内。
最后,我们借助Outlet组件展示路由内容即可,src\pages\Home.jsx中
import React, { useState } from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Home() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" to="news">
News
</NavLink>
</li>
<li>
<NavLink className="list-group-item " to="message">
Message
</NavLink>
</li>
</ul>
<Outlet></Outlet>
</div>
</div>
);
}
Outlet 可以让我们更方便地定义嵌套路由。Outlet 类似于占位符,它会告诉父级路由组件在何处渲染子级路由组件。
嵌套路由to的三种写法
本示例中,匹配子路由,to有三种写法
<NavLink className="list-group-item" to="news">
News
</NavLink>
<NavLink className="list-group-item" to="/home/news">
News
</NavLink>
<NavLink className="list-group-item" to="./news">
News
</NavLink>
其余写法都会出错
路由传参
现在,我们实现一个这样的效果,单击二级路由message组件内的任意一个按钮,在三级路由显示对应的信息
Params参数的传递与接受
参数的传递
要实现Params的传递,我们需要在路由调转时,定义好格式
src\pages\Message.jsx
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: 1, title: "消息1", content: "锄禾日当午" },
{ id: 2, title: "消息2", content: "汗滴禾下土" },
{ id: 3, title: "消息3", content: "谁知盘中餐" },
{ id: 4, title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((m) => {
return (
// 路由链接
<li key={m.id}>
<Link to={`detail/${m.id}/${m.title}/${m.content}`}>{m.title}</Link>
</li>
);
})}
</ul>
<br />
{/* 路由链接 */}
<Outlet></Outlet>
</div>
);
}
上述代码中,我们使用Outlet进行message子路由展示
我们需要在src\routes\index.js中进行三级路由配置
import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Message";
import News from "../pages/News";
import Detail from "../pages/Detail";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{ path: "news", element: <News /> },
{ path: "message", element: <Message />, children: [{ path: "detail/:id/:title/:content", element: <Detail /> }] },
],
},
{ path: "/", element: <Navigate to="/about" /> },
];
注意,在定义路由时,我们的path需要进行占位detail/:id/:title/:content, 同时,我们需要定义message信息展示组件Detail.jsx
使用useParams接收参数
src\pages\Detail.jsx中
import React from "react";
import { useParams } from "react-router-dom";
export default function Detail() {
const { id, title, content } = useParams();
return (
<div>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</div>
);
}
useParams是一个React Router v5引入的新的Hook,它可以帮助我们方便地获取当前路由中的参数。如上述示例,当我们使用动态路由时detail/:id/:title/:content,我们需要获取id这个参数来显示用户特定的数据。这时就可以使用useParams来获取路由中的参数下:
const { id, title, content } = useParams();
Search参数的传递与接受
参数传递
search参数传递形式同浏览器原生的query参数
src\pages\Message.jsx
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: 1, title: "消息1", content: "锄禾日当午" },
{ id: 2, title: "消息2", content: "汗滴禾下土" },
{ id: 3, title: "消息3", content: "谁知盘中餐" },
{ id: 4, title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((m) => {
return (
// 路由链接
<li key={m.id}>
<Link to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}>{m.title}</Link>
</li>
);
})}
</ul>
<br />
{/* 路由链接 */}
<Outlet></Outlet>
</div>
);
}
search参数不需要使用占位符,因此在src\routes\index.js中,path不需要使用占位写法
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{ path: "news", element: <News /> },
{ path: "message", element: <Message />, children: [{ path: "detail", element: <Detail /> }] },
],
},
{ path: "/", element: <Navigate to="/about" /> },
];
使用useSearchParams接收参数
search参数的接收同params参数,都使用对应的Hooks函数。search参数的Hook函数名为useSearchParams
useSearchParams 用于获取当前 URL 中的查询参数,使用 useSearchParams 需要在你的组件中导入它,然后,在你的组件函数内部使用它:
// src\pages\Detail.jsx
import React from "react";
import { useSearchParams } from "react-router-dom";
export default function Detail() {
const [search, setSearch] = useSearchParams();
const id = search.get("id");
const title = search.get("title");
const content = search.get("content");
return (
<div>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</div>
);
}
页面效果
在上面的例子中,我们使用 useSearchParams 来获取当前 URL 中的查询参数。useSearchParams 返回一个元组,包含当前的查询参数对象和一个可以设置新的查询参数对象的函数 setSearchParams。
获取参数
使用useSearchParams获取参数,需要从其元素的第一个函数中获取
const [search, setSearch] = useSearchParams();
const id = search.get("id");
参数更新
我们使用元组的第二个参数setSearch方法可以更改接收到的路由参数
import React from "react";
import { useSearchParams } from "react-router-dom";
export default function Detail() {
const [search, setSearch] = useSearchParams();
const id = search.get("id");
const title = search.get("title");
const content = search.get("content");
return (
<div>
<button onClick={() => setSearch("id=1111&&title=test&content=test&time=122333445566")}>更改参数</button>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</div>
);
}
上述代码中,我们向setSearch中传递了自定义的search参数,当我点击按钮时,观察下变化
可见,setSearch可以更改search参数,也可以更新视图
state参数
state参数不会使路由url发生变化
state参数的传递
state参数的传递非常简单,标签内定义state属性即可。src\pages\Message.jsx
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: 1, title: "消息1", content: "锄禾日当午" },
{ id: 2, title: "消息2", content: "汗滴禾下土" },
{ id: 3, title: "消息3", content: "谁知盘中餐" },
{ id: 4, title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((m) => {
return (
// 路由链接
<li key={m.id}>
<Link to="detail" state={{ id: m.id, title: m.title, content: m.content }}>
{m.title}
</Link>
</li>
);
})}
</ul>
<br />
{/* 路由链接 */}
<Outlet></Outlet>
</div>
);
}
state参数的接受
使用useLocation可以接收state的参数
import React from "react";
import { useLocation } from "react-router-dom";
export default function Detail() {
const { state } = useLocation();
return (
<div>
<li>{state ? state.id : null}</li>
<li>{state ? state.title : null}</li>
<li>{state ? state.content : null}</li>
</div>
);
}
useLocation是React Router中的另一个Hook,可以获取到当前页面的URL信息,并返回一个包含pathname、search、hash、state等属性的对象。它的作用是方便在React组件中获取URL信息,并根据URL信息来进行一些操作,例如根据URL信息动态加载组件、将URL参数作为props传递给组件等。
React-Router进阶
useNavigate
编程时导航。上述示例中,我们通过Link组件或者NavLink组件实现跳转,某些情况下,我们可能需要其他形式实现跳转,比如通过一个按钮实现路由跳转。这个时候,我们就需要编程式导航。
我们看一下demo
这个案例中,我们使用按钮实现了类似Link标签的state传参跳转。它的通过useNavigate这个hook函数实现
import React, { useState } from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: 1, title: "消息1", content: "锄禾日当午" },
{ id: 2, title: "消息2", content: "汗滴禾下土" },
{ id: 3, title: "消息3", content: "谁知盘中餐" },
{ id: 4, title: "消息4", content: "粒粒皆辛苦" },
]);
const navigate = useNavigate();
function showDetail(m) {
navigate("detail", {
replace: false,
state: {
id: m.id,
title: m.title,
content: m.content,
},
});
}
return (
<div>
<ul>
{messages.map((m) => {
return (
// 路由链接
<li key={m.id}>
<Link to="detail" state={{ id: m.id, title: m.title, content: m.content }}>
{m.title}
<button onClick={() => showDetail(m)}>查看详情</button>
</Link>
</li>
);
})}
</ul>
<br />
{/* 路由链接 */}
<Outlet></Outlet>
</div>
);
}
其核心代码是
import React, { useState } from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";
export default function Message() {
// ...
const navigate = useNavigate();
function showDetail(m) {
navigate("detail", {
replace: false,
state: {
id: m.id,
title: m.title,
content: m.content,
},
});
}
return (
<div>
// ...
<button onClick={() => showDetail(m)}>查看详情</button>
// ...
</div>
);
}
navigate可以接受两个参数,第二个参数一个可选项,包含以下选项:
- replace:当为 true 时,将当前导航记录替换为新路径,而不是在历史记录中创建一个新的导航记录。
- state:一个任意类型的值,将其作为状态传递给新页面。
注意,navigate内我们定义的是state参数,因此,路由的接受也需要使用类似形式
src\pages\Detail.jsx
import React from "react";
import { useLocation } from "react-router-dom";
export default function Detail() {
const { state } = useLocation();
return (
<div>
<li>{state ? state.id : null}</li>
<li>{state ? state.title : null}</li>
<li>{state ? state.content : null}</li>
</div>
);
}
useInRouterContext
useInRouterContextle可以判断当前组件是否被组件包裹。
src\index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
这个代码中,所有App子组件都被BrowserRouter包裹。因此,我们在任意组件内打印useInRouterContext()都为true
import { NavLink, useRoutes, useInRouterContext } from "react-router-dom";
console.log(useInRouterContext()); // true
原文链接:https://juejin.cn/post/7249761605599559741 作者:石小石Orz
评论列表(1条)
这个网站是博主创建的吗