zoukankan      html  css  js  c++  java
  • [Next] 五.next自定义内容

    自定义 head

    这是默认的 head

    这样的 head 并不能满足我们的需求.next 公开了一个内置组件,用于将元素追加到<head>标签的.我们可以通过这个自定义 head

    新建 components/Head.js

    import { Fragment } from "react";
    import Head from "next/head";
    
    function MyHead() {
      return (
        <Fragment>
          <Head>
            <meta charset="utf-8"></meta>
            <meta name="referrer" content="origin"></meta>
            <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"></meta>
            <meta name="keywords" content="next.js,react.js"></meta>
            <meta content="next 简介 next.js作为一款轻量级的应用框架,主要用于构建静态网站和后端渲染网站。 next 特点 默认情况下由服务器呈现 自动代码拆分可加快页面加载速度 简单的客户端路由(基于页面) 基于"></meta>
            <title>蓝猫</title>
          </Head>
        </Fragment>
      );
    }
    
    export default MyHead;
    

    为了避免重复的标签,您<head>可以使用 key 属性,以确保标签仅呈现一次

    在 MyLayout.js 引入

    import Head from "./Head";
    
    ......
          <Fragment>
            <Head />
            <Header />
            <div className={"content"}>{children}</div>
            <Footer />
          </Fragment>
    ......
    

    添加完之后的 head 标签,但是在使用中<meta charset="utf-8"></meta>如果再添加的话就会出现两个,去掉 Head 组件中的 charset.

    自定义 app

    上面是 next 的渲染流程,next 使用 app 组件来进行初始化页面. 可以覆盖 next 自带的 app 来进行初始化

    • 在页面更改是保持持久布局
    • 当页面切换时保持状态
    • 使用自定义错误处理 componentDidCatch
    • 页面的数据注入

    新建 pages/_app.js

    import React from "react";
    import App from "next/app";
    
    class MyApp extends App {
      render() {
        const { Component, pageProps } = this.props;
        return (
          <div className="my-app">
            <Component {...pageProps} />
          </div>
        );
      }
    }
    
    export default MyApp;
    

    getInitialProps 在 App 中添加自定义设置会影响自动静态优化

    自定义 document

    • 自定义<Document>通常用于扩充<html><body>标签
    • 在服务端呈现
    • 初始化服务端时添加文档标记元素
    • 通常实现服务端渲染会使用一些 css-in-js 库,如 styled-components, glamorous 或 emotion。styled-jsx 是 Next.js 自带默认使用的 css-in-js 库

    新建 pages/_document.js

    import Document, { Html, Head, Main, NextScript } from "next/document";
    
    class MyDocument extends Document {
      static async getInitialProps(ctx) {
        const initialProps = await Document.getInitialProps(ctx);
        return { ...initialProps };
      }
    
      render() {
        return (
          <Html>
            <Head />
            <body>
              <div className="document">
                <Main />
                <div className="inner-document"></div>
                <NextScript />
              </div>
            </body>
          </Html>
        );
      }
    }
    
    export default MyDocument;
    

    钩子 getInitialProps 接收到的参数 ctx 对象都是一样的

    • 回调函数 renderPage 是会执行 React 渲染逻辑的函数(同步),这种做法有助于此函数支持一些类似于 Aphrodite 的 renderStatic 等一些服务器端渲染容器。

    注意:<Main />外的 React 组件将不会渲染到浏览器中,所以那添加应用逻辑代码。如果你页面需要公共组件(菜单或工具栏),可以参照上面说的 App 组件代替。

    自定义 renderPage

    使用 renderPage 的唯一原因是 css-in-js 库需要包裹当前应用并且在服务端渲染下也能正常工作

    static async getInitialProps(ctx) {
      const originalRenderPage = ctx.renderPage
    
      ctx.renderPage = () =>
        originalRenderPage({
          // useful for wrapping the whole react tree
          enhanceApp: App => App,
          // useful for wrapping in a per-page basis
          enhanceComponent: Component => Component,
        })
    
      // Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage`
      const initialProps = await Document.getInitialProps(ctx)
    
      return initialProps
    }
    

    自定义错误页面

    客户端和服务器端的 404 或 500 错误默认由 error.js 组件处理。

    新建 pages/_error.js 覆盖

    import React from 'react'
    
    function Error({ statusCode }) {
      return (
        <p>
          {statusCode
            ? `An error ${statusCode} occurred on server`
            : 'An error occurred on client'}
        </p>
      )
    }
    
    Error.getInitialProps = ({ res, err }) => {
      const statusCode = res ? res.statusCode : err ? err.statusCode : 404
      return { statusCode }
    }
    

    自定义配置 / 自定义 Webpack 配置 / 自定义 babel 配置

    当前的配置./next.config.js

    const fetch = require("isomorphic-unfetch");
    const withBundleAnalyzer = require("@zeit/next-bundle-analyzer");
    const withLess = require("@zeit/next-less");
    const FilterWarningsPlugin = require("webpack-filter-warnings-plugin");
    
    if (typeof require !== "undefined") {
      require.extensions[".less"] = file => {};
    }
    
    function HACK_removeMinimizeOptionFromCssLoaders(config) {
      config.module.rules.forEach(rule => {
        if (Array.isArray(rule.use)) {
          rule.use.forEach(u => {
            if (u.loader === "css-loader" && u.options) {
              delete u.options.minimize;
            }
          });
        }
      });
    }
    
    module.exports = withBundleAnalyzer(
      withLess({
        poweredByHeader: false,
        analyzeServer: ["server", "both"].includes(process.env.BUNDLE_ANALYZE),
        analyzeBrowser: ["browser", "both"].includes(process.env.BUNDLE_ANALYZE),
        bundleAnalyzerConfig: {
          server: {
            analyzerMode: "static",
            reportFilename: "../bundles/server.html"
          },
          browser: {
            analyzerMode: "static",
            reportFilename: "../bundles/client.html"
          }
        },
        exportPathMap: async function() {
          const paths = {
            "/": { page: "/" },
            "/books": { page: "/books" },
            "/article": { page: "/article" },
            "/write": { page: "/write" }
          };
    
          const res = await fetch("https://api.tvmaze.com/search/shows?q=batman");
          const data = await res.json();
          const shows = data.map(entry => entry.show);
    
          shows.forEach(show => {
            paths[`/book/${show.id}`] = {
              page: "/book/[id]",
              query: { id: show.id }
            };
          });
    
          return paths;
        },
        lessLoaderOptions: {
          javascriptEnabled: true
        },
        webpack(config) {
          config.plugins.push(
            new FilterWarningsPlugin({
              exclude: /mini-css-extract-plugin[^]*Conflicting order between:/
            })
          );
          HACK_removeMinimizeOptionFromCssLoaders(config);
          return config;
        }
      })
    );
    
    

    当前的.babelrc

    {
      "presets": ["next/babel"],
      "plugins": [
        [
          "import",
          {
            "libraryName": "antd",
            "style": "less"
          }
        ]
      ]
    }
    
    

    Doc

  • 相关阅读:
    一行Haskell语句打印勾股数
    给孩子增加学习生物的兴趣,买了个显微镜
    实现求n个随机数和为sum的haskell程序
    用haskell实现的八皇后程序
    桥牌笔记:第一墩决定成败
    读书笔记:父母离去前要做的55件事
    LINQ to SQL系列三 使用DeferredLoadingEnabled,DataLoadOption指定加载选项
    LINQ to SQL系列四 使用inner join,outer join
    Asp.Net 4.0 新特性 系列 之一 从页面标记<%%>说起
    使用javascript自动标记来自搜索结果页的关键字
  • 原文地址:https://www.cnblogs.com/mybilibili/p/11778065.html
Copyright © 2011-2022 走看看