浏览器对象模型(BOM,Browser Object Model)是使用 JavaScript 开发 Web 应用程序的核心,BOM 提供了与网页无关的浏览器功能对象。
- navigator 对象:浏览器及系统信息
- screen 对象:屏幕信息
window 对象
- BOM 的核心是 window 对象,表示浏览器的实例。window 对象在浏览器中有两重身份,一个是 ECMAScript 的 Global 对象,另一个是浏览器窗口的 JavaScript 接口。网页中定义的所有对象、变量和函数都以 window 作为其 Global 对象。
- var 声明的所有全局变量和函数都会变成 window 对象的属性和方法。
窗口与视口
- 窗口(window)表示浏览器窗口本身,所有 parent 最终都是指向 window
- 视口(viewport)用户可见的区域
大小
// 获取窗口大小
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
// 获取视口大小
let viewportWidth = document.documentElement.clientWidth;
let viewportHeight = document.documentElement.clientHeight;
// 获取整个文档的宽度和高度,包含不可见部分
let pageWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
let pageHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
window.addEventListener('resize', function() {
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
console.log("窗口大小已更改: ", windowWidth, windowHeight);
});
位置
let viewportX = document.documentElement.scrollLeft
let viewportY = document.documentElement.scrollTop
window.addEventListener('scroll', function() {
let viewportX = document.documentElement.scrollLeft
let viewportY = document.documentElement.scrollTop
console.log("视口水平位置: " + viewportX);
console.log("视口垂直位置: " + viewportY);
});
location 对象
- location 对象提供了当前窗口中加载文档的信息,以及通常的导航功能。
- location = window.location = document.location。
- 可以通过三方库 query-string 从 location.search 获得 query 参数。
- location.reload() 重新加载,可能是从缓存;location.reload(true) 从服务器重新加载。
| 属性 | 值 | 说明 |
|---|---|---|
| location.hash | "#contents" | URL 散列值(井号后跟零或多个字符),如果没有则为空字符串 |
| location.host | "www.wrox.com:80" | 服务器名及端口号 |
| location.hostname | "www.wrox.com" | 服务器名 |
| location.href | "www.wrox.com:80/WileyCDA/?q…" | 当前加载页面的完整 URL。location 的 toString()方法返回这个值 |
| location.pathname | "/WileyCDA/" | URL 中的路径和(或)文件名 |
| location.port | "80" | 请求的端口。如果 URL中没有端口,则返回空字符串 |
| location.protocol | "http:" | 页面使用的协议。通常是"http:"或"https:" |
| location.search | "?q=javascript" | URL 的查询字符串。这个字符串以问号开头 |
| location.username | "foouser" | 域名前指定的用户名 |
| location.password | "barpassword" | 域名前指定的密码 |
| location.origin | "www.wrox.com" | URL 的源地址。只读 |
history 对象
- histor 对象表示当前窗口首次使用以来用户的导航历史记录。
- history 提供了 pushState、replaceState 等方法,允许在不刷新页面的情况下改变 URL
react-router
- react-router 的核心是利用 React 的组件化模型来创建路由,主要包括以下组件:
-
- Router:这是最顶层组件,它接收一个 history 对象,并将其传递给子组件。Router 组件负责监听 URL 的变化,并更新子组件以反映当前的路由状态。
- Route:Route 组件用于定义路由规则。它检查当前的路径,并决定是否渲染子组件。
- Switch:Switch 组件是 Route 组件的容器,它确保同一时间只有一个 Route 被渲染。
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
createBrowserRouter,
RouterProvider,
} from "react-router-dom";
import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
loader: rootLoader,
children: [
{
path: "team",
element: <Team />,
loader: teamLoader,
},
],
},
]);
ReactDOM.createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
);
监听路由变化
import * as React from 'react';
import { useLocation } from 'react-router-dom';
function App() {
let location = useLocation();
React.useEffect(() => {
// Google Analytics
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
导航守卫
react-router 没有内置的导航守卫,需要自定义路由渲染前的逻辑来实现。
// 导入所需的钩子和组件
import { useNavigate, Navigate } from 'react-router-dom';
function ProtectedRoute({ children, isAuthenticated }) {
let navigate = useNavigate();
// 如果用户未认证,重定向到登录页面
if (!isAuthenticated) {
navigate('/login', { replace: true });
}
// 如果认证通过,渲染子组件
return children;
}
// 使用受保护的路由组件
function App() {
return (
<Router>
<ProtectedRoute isAuthenticated={isAuthenticated}>
<Dashboard />
</ProtectedRoute>
</Router>
);
}
vue-router
- vue-router 的实现原理与 react-router 类似,但是它更紧密的与 Vue 的生命周期和响应是系统集成。vue-router 主要包括以下概念:
-
- Router 实例:vue-router 的核心是 Router 实例,它管理路由映射和视图组件。
- router-view:这是一个特殊的空组件,它作为路由的入口,在其中匹配到的组件将被渲染。
import { createMemoryHistory, createRouter } from 'vue-router'
import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'
const routes = [
{ path: '/', component: HomeView },
{ path: '/about', component: AboutView },
]
const router = createRouter({
history: createMemoryHistory(),
routes,
})
createApp(App)
.use(router)
.mount('#app')
监听路由变化
- 可以通过 beforeRouteUpdate 实现
- 可以通过 watch 来监听
export default {
watch: {
'$route': function (to, from) {
console.log('路由变化了');
console.log('当前页面路由:', to);
console.log('上一个路由:', from);
},
deep: true
}
}
导航守卫
vue-router 提供了一套完整的导航守卫系统,可以在全局、路由独享及组件内定义。
// 定义全局前置守卫
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!auth.isLoggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
});
} else {
next();
}
} else {
next();
}
});
// 在路由配置中定义独享守卫
const router = new VueRouter({
routes: [
{
path: '/protected',
component: ProtectedComponent,
beforeEnter: (to, from, next) => {
if (auth.isLoggedIn()) {
next();
} else {
next('/login');
}
}
}
]
});
// 在组件内定义守卫
export default {
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
});
},
beforeRouteUpdate (to, from, next) {
// 当路由发生变化且该组件被重用时被调用
next();
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
next();
}
};