JavaScript基础回顾(九):BOM与react、vue路由

91 阅读4分钟

浏览器对象模型(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();
    }
};