Node-web03_01Next

使用Next.js

创建项目

1
2
3
4
5
6
7
8
9
npm init next-app xxx-demo-1


安装好后
cd xxx-demo-1

运行
yarn dev
http://localhost:3000/

CRM开始 改内容

创建页面

  • pages/posts/first-post.js
1
2
3
4
5
6
import React from 'react';
export default function x() {
return (
<div>First Post</div>
)
}
  • 为了更好的类型提示 ,安装类型声明文件
1
yarn add --dev @types/react @types/react-dom

总结

  • 约定大于配置

Link快速导航

1
2
3
4
5
// 第一步
import Link from 'next/link'

// 第二步
<Link href="/posts/first-post"> Link标签 去 first-post</Link>
  • Link跳转的页面不会刷新,用ajax请求页面内容 (first-post.js)
  • 不会请求重复的HTML/JS/CSS
  • 自动在页面插入新内容,删除旧内容
  • 因为省了很多请求和解析过程,所以速度很快

借鉴了 以前就有的技术 客户端导航 如 pjax技术

同构代码

代码同时运行在两端

  • 组件里 console.log(1)
  • 你会发现 Node控制台/浏览器 都会输出 console.log(1)

差异

  • 不是所有代码,都会运行,有些需要用户触发 比如 btn.click
  • 不是所有API都能用,比如 window 在 Node里报错

参考 pages/posts/first-post.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { useCallback } from 'react';
import Link from 'next/link'
console.log('组件执行了')
// console.log(window) // 放开注视回报错,因为Node里没有 window
export default function x() {
const clickMe = useCallback(() => {
console.log('btn click,只在浏览器执行,不再Node控制台显示')
console.log(window)
}, [])
return (
<div>First Post
<hr />
回到首页
<hr />
<a href="/">a标签回首页,会重新请求</a>
<hr />
<Link href="/">Link回首页</Link>
<button onClick={clickMe}>btn</button>
</div>
)
}

全局配置

  • 自定义 Head
  • 全局 CSS
  • 局部 CSS

自定义 Head

  • 每个组件内你可以这样
1
2
3
4
<Head>
<title>我的Blog</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover" />
</Head>

如何修改全局 title 和 meta

  • 修改 pages/_app.js
  • 添加 <Head> 如果你想覆盖全局的 head,则在你的页面写head即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import '../styles/globals.css'
import Head from 'next/head'

function App({ Component, pageProps }) {
return (
<div className="hjx">
<Head>
<title>全局配置的title</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover" />
</Head>
<Component {...pageProps} />
</div>)
}
export default App
  • export default function App 是每个组件的根组件
  • 页面切换 App不会销毁,App里面的组件回销毁
  • 可用 App 保留全局状态

修改了 _app.js需要重启才能生效

全局CSS

  • styles/globals.css 里设置全局样式
  • pages/_app.js里引入 import '../styles/globals.css'
  • 其他地方不能 引入全局 css ,会报错

局部css

  • 可以引入 import styles from '../styles/Home.module.css'
  • 还可以jsx 写 css
1
2
3
4
5
6
7
8
9
10
11
12
13
// 类似 vue的 scoped
<style jsx>{`
a{
color:red;
}
`}</style>

// 修改全局的 css
<style jsx global>{`
body{
background:pink;
}
`}</style>

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Head from 'next/head'
import Link from 'next/link'
import styles from '../styles/Home.module.css'

export default function Home() {
return (
<div className={styles.container}>
<main className={styles.main}>
<a href="/posts/first-post">打开first-post,a标签回去first-post,会重新请求</a>
<br />
<Link href="/posts/first-post"> Link标签 去 first-post</Link>
</main>
<style jsx>{`
a{
color:red;
}
`}</style>
<style jsx global>{`
body{
background:pink;
}
`}</style>
</div>
)
}

模块化的css

  • 新建 first-post.module.css
1
2
3
4
.content{
background: pink;
border:1px solid red;
}
  • 修改 pages/posts/first-post.js
1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import styles from 'styles/first-post.module.css'
export default function x() {
return (
<>
<div>First Post
<hr />
<div className={styles.content}>1111</div>
</div>
</>

)
}

如何引入文件不是相对路径

1
2
3
4
5
// pages/_app.js 里
import '../styles/globals.css'

// 如何 不写相对路径,变成这样
import 'styles/globals.css'
  • 项目根目录 新建 jsconfig.js
1
2
3
4
5
{
"compilerOptions": {
"baseUrl": "."
}
}

使用 sass

  • yarn add sass
  • 直接 .css文件修改为 .scss即可

静态资源

next推荐放在 public/

不推荐资源放在 public里

  • public/logo.png
  • 页面里 <img src="/logo.png" />
  • 但是这样无法被缓存

正确姿势

  • 项目根目录新建 assets/images
  • 你不能直接这样,会报错
1
2
3
import png from 'assets/003.png'

<img src={png} />
  • 你需要修改配置 next.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.png$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[contenthash].[ext]',
publicPath: '/_next/static',
outputPath: 'static',
}
}

]
})
return config;
}
}

配置一个img那么麻烦, next-images 插件

1
yarn add next-images

修改配置 next.config.js

1
2
3
4
5
6
const withImages = require('next-images')
module.exports = withImages({
webpack(config, options) {
return config
}
})

代码仓库