<h1>项目的创建与目录结构的详解</h1>
项目的创建
有两种创建项目的方式
- 手动创建点击查看
- create-next-app脚手架创建(主要介绍)
首先需要全局安装 create-next-app
npm install -g create-next-app
然后在一个空目录中创建 next 项目
这里使用 npx 来创建项目,低版本的 node 没有 npx,所以需要额外的安装,一般情况下,略微高点版本的 node 都自带有 npx 命令
npm install -g npx
npx create-next-app next-create
目录结构详解
components文件夹:这里是专门放置自己写的组件的,这里的组件不包括页面,指公用的或者有专门用途的组件。
node_modules文件夹:Next项目的所有依赖包都在这里,一般我们不会修改和编辑这里的内容。
pages文件夹:这里是放置页面的,这里边的内容会自动生成路由,并在服务器端渲染,渲染好后进行数据同步。
static文件夹: 这个是静态文件夹,比如项目需要的图片、图标和静态资源都可以放到这里。
.gitignore文件: 这个主要是控制git提交和上传文件的,简称就是忽略提交。
package.json文件:定义了项目所需要的文件和项目的配置信息(名称、版本和许可证),最主要的是使用
npm install
就可以下载项目所需要的所有包。
Page和Component的使用
新建一个页面且可以访问
在 page 目录下新建一个 home.js,具体代码如下
export default function Home(){
return (
<button>home页</button>
)
}
next 自动为我们配置好了路由,所以访问这个 home 页就可以直接通过 http://localhost:3000/home 访问
如果需要访问多级地址,就可以写嵌套的目录结构,比如 http://localhost:3000/article/detail
> pages
|
> ------- home目录
|
> ------- article目录
|
> ---- detail.js
使用Components来定义组件
比如我们要制作一个全局底部组件,就可以直接在 components 里面建一个 footer.js 作为 footer 组件
export default ({children}) => {
return (
<footer>
{children}
</footer>
)
}
注意:组件函数接收一个参数是个 对象,这个对象里面有一个 children 属性,这个 children 属性值就是使用的时候写进去的值
然后在页面引入这个底部组件
import Footer from '../components/footer';
使用方法就很简单了
<Footer>底部内容</Footer>
路由的跳转
标签式跳转<Link>
首先在 pages 目录下先建两个需要跳转的页面,这里以 home 和 list 为例
// home -- index.js
export default function Home() {
return (
<div>home页</div>
)
}
//list -- index.js
export default function List () {
return (
<div>list页</div>
)
}
这里我们可以通过 http://localhost:3000/home 和 http://localhost:3000/list 来访问了
然后在 page/index.js 里面写两个按钮需要点击跳转
import Link from 'next/link';
import { Fragment } from 'react';
export default function Index() {
return (
<Fragment>
<Link href="/home"><a>去home</a></Link>
<Link href="/list"><a>去列表</a></Link>
</Fragment>
)
}
现在就可以实现分别点击按钮来跳转了
用
<Link>
标签进行跳转是非常容易的,但是有一个小坑需要注意一下,就是他不支持兄弟标签并列的情况。所以需要一个标签来包裹。
<!--错误写法-->
<Link>
<span>去</span>
<span>home</span>
</Link>
<!--正确写法-->
<Link>
<a>
<span>去</span>
<span>home</span>
</a>
</Link>
函数式跳转(Router模块跳转)
需要先引入 Router
import Router from 'next/router'
我们可以通过一个按钮执行一个方法,在这个方法中通过 Router 来跳转
// Router函数式跳转的写法
import Link from 'next/link';
import Router from 'next/router';
import { Fragment } from 'react';
export default function Home() {
const goHome = () => {
Router.push('/home')
}
const goList = () => {
Router.push('/list')
}
return (
<Fragment>
{/*
<Link href="/home"><a>去home</a></Link>
<Link href="/list"><a>去列表</a></Link>
*/}
<button onClick={goHome}>去home</button>
<button onClick={goList}>去列表</button>
</Fragment>
)
}
路由跳转时的参数与接收(query)
注意:在 Next.js 中只能用 query 来传参
现在想要实现一个在首页点击去 list 传递一个参数 id 为 1
标签式传递参数<Link>
具体代码如下,直接在 Link 标签的 href 属性上拼接即可
<Fragment>
<Link href="/home"><a>去home</a></Link>
<Link href="/list?id=1"><a>去列表</a></Link>
</Fragment>
函数式传参(Router)
import Router from 'next/router';
import { Fragment } from 'react';
export default function Home() {
const goHome = () => {
Router.push('/home')
}
//方法1:拼接在push里面
const goList = () => {
Router.push('/list?id=1')
}
//方法2:以对象的形式
const goList = () => {
Router.push({
pathname:'/list',
query:{
id:1
}
})
}
return (
<Fragment>
<button onClick={goHome}>去home</button>
<button onClick={goList}>去列表</button>
</Fragment>
)
}
接收传递过来的参数
接受传递过来的参数需要用到 withRouter,所以这里先引入
import { withRouter} from 'next/router'
然后需要改写一下 List 页面
import { withRouter } from 'next/router';
import { Fragment } from 'react';
const List = ( {router} ) => {
return (
<Fragment>
<div>{router.query.id}</div>
<div>列表页</div>
</Fragment>
)
}
export default withRouter(List);
必须要将页面函数作为参数传给 withRouter 并且将 withRouter 暴露出去才可以使用传递给当前页面的参数
钩子事件
- routerChangeStart 路由发生变化时
- routerChangeComplete 路由结束变化时
- beforeHistoryChange 浏览器history触发前
- routerChangeError 路由跳转发生错误时
- hashChangeStart Hash模式转变之前
- hashChangeComplete Hash模式转变结束
import Link from 'next/link';
import Router from 'next/router';
import { Fragment } from 'react';
const Home = () => {
const goHome = () => {
Router.push('/home')
}
const goList = () => {
Router.push('/list?id=1')
}
Router.events.on('routeChangeStart',(...args)=>{
console.log('1.routeChangeStart->路由开始变化,参数为:',...args)
})
Router.events.on('routeChangeComplete',(...args)=>{
console.log('2.routeChangeComplete->路由结束变化,参数为:',...args)
})
Router.events.on('beforeHistoryChange',(...args)=>{
console.log('3,beforeHistoryChange->在改变浏览器 history之前触发,参数为:',...args)
})
Router.events.on('routeChangeError',(...args)=>{
console.log('4,routeChangeError->跳转发生错误,参数为:',...args)
})
Router.events.on('hashChangeStart',(...args)=>{
console.log('5,hashChangeStart->hash跳转开始时执行,参数为:',...args)
})
Router.events.on('hashChangeComplete',(...args)=>{
console.log('6,hashChangeComplete->hash跳转完成时,参数为:',...args)
})
return (
<Fragment>
<button onClick={goHome}>去home</button>
<button onClick={goList}>去列表</button>
</Fragment>
)
}
export default Home;
在Next中使用Axios请求数据
在
Next.js
框架中提供了getInitialProps
静态方法用来获取远端数据
首先需要安装 axios
import { withRouter } from 'next/router';
import { Fragment } from 'react';
import axios from 'axios';
// 下面请求返回的数据是什么,这里就用什么接受
// 下面请求返回的是data 所以这里用data来接收
const List = ( {router,data} ) => {
return (
<Fragment>
<div>{router.query.id}</div>
<div>列表页</div>
<ul>
{
data.map((item,index) => {
return (
<li key={index}>{item.content}</li>
)
})
}
</ul>
</Fragment>
)
}
//在这里请求
List.getInitialProps = async () => {
return new Promise((resolve,reject) => {
axios.get('xxx').then(res => {
//注意返回值
resolve(res.data)
}).catch(err => reject(err))
})
}
/*
返回的res.data为
data:[
{id:1,content:'111'},
{id:2,content:'222'},
{id:3,content:'333'},
{id:4,content:'444'}
]
*/
export default withRouter(List);
注意:需要注意的一点是返回值是什么,页面函数的参数里面就用什么来接收
使用style JSX编写页面的css样式
在
Next.js
中引入一个CSS样式是不可以用的,如果想用,需要作额外的配置。因为框架为我们提供了一个style jsx
特性,也就是把CSS用JSX的语法写出来
这里我们先在 pages 目录下新建一个 test.js 文件
function Test(){
return (
<>
{/* 必须加上下面这段style才会修改样式,{` `} 同样不可缺 */}
<style jsx>
{`
div{color:blue}
.test{color:red}
`}
</style>
<div>这是一句测试文字</div>
<div className="test">这是一句测试文字</div>
</>
)
}
export default Test;
加入了
Style jsx
代码后,Next.js
会自动加入一个随机类名,这样就防止了CSS的全局污染
动态显示样式
比如我们要点击一个按钮再让他添加这个样式
import {useState} from 'react';
function Test(){
// 定义一个color初始值为blue
const [color,setColor] = useState('blue')
// 定义一个方法来改变颜色
const changeColor = ( ) => {
setColor(color == 'blue' ? 'red' : 'blue')
}
return (
<>
<div>这是一句测试文字</div>
<div onClick={changeColor}>这是一测试文字</div>
{/* 这里要想使用上面定义的color必须使用 ${color} */}
<style jsx>
{ div { color:${color} }
}
</style>
</>
)
}
export default Test;
自定义Head,更加友好的SEO
在各个页面加入Head
首先在 pages 目录下新建一个 head.js
// 引入Head组件
import Head from 'next/head';
const Header = () => {
return (
<div>
<Head>
<title>自定义标题内容</title>
<meta charSet='utf-8' />
</Head>
</div>
)
}
export default Header;
定义全局的Head
定义全局的 Head 意义不大,但还是可以学习一下
在 components 目录下定义全局 MyHeader.js
Next 中已经为我们封装好 Head ,全局定义 Head 的话相当于对 Next 封装的 Head 再次封装,意义不大
import Head from 'next/head'
const MyHeader = ()=>{
return (
<>
<Head>
<title>全局title</title>
</Head>
</>
)
}
export default MyHeader
然后修改 pages 目录下的 head.js
// import Head from 'next/head';
import MyHeader from '../components/MyHeader'
const Header = () => {
return (
<div>
<MyHeader />
{/* <Head>
<title>自定义标题内容</title>
<meta charSet='utf-8' />
</Head> */}
</div>
)
}
export default Header;
Next框架下使用Ant Design UI
Next 默认是不支持 Css 文件的,所以我们需要先安装一个插件来让 Next 支持 Css
安装插件@zeit/next-css进行配置,让他支持css
首先在根目录下新建一个 static/css 目录,在这个目录下新建一个 test.css 文件
body{
color:green;
}
然后在 pages 目录下的 list 页面中引入
import '../../static/css/test.css';
发现并不生效,还报了一堆的错,这个时候我们需要安装插件让他支持 CSS 文件
npm install @zeit/next-css -s
安装完成之后,在项目根目录下新建 next.config.js 文件
下面这段代码是配置文件,直接复制粘贴即可
const withCss = require('@zeit/next-css')
if(typeof require !== 'undefined'){
require.extensions['.css']=file=>{}
}
module.exports = withCss({})
然后重启服务,访问 http://localhost:3000/list 发现字体颜色都变了
按需加载 Ant Design
需要安装 Ant Design 库 和 babel-plugin-import 插件
npm install antd babel-plugin-import -s
安装完成之后,在项目根目录下新建 .babelrc 文件,编写如下配置信息
{
"presets":["next/babel"], //Next.js的总配置文件,相当于继承了它本身的所有配置
"plugins":[ //增加新的插件,这个插件就是让antd可以按需引入,包括CSS
[
"import",
{
"libraryName":"antd",
"style":"css"
}
]
]
}
接下来我们去 list 页面使用 ant 组件
import { Fragment } from "react";
import Router from "next/router";
import { Button } from 'antd'; //引入ant的button组件
import '../../static/css/test.css';
const List = () => {
const goHome = () => {
Router.push({
pathname:'/'
})
}
return (
<Fragment>
{/* 使用ant的button组件 */}
<Button type="primary">Primary Button</Button>
{/* <p><button onClick={goHome}>返回首页</button></p> */}
<p>列表页</p>
</Fragment>
)
}
export default List;
打开浏览器,发现效果已经出来。
Next生产环境打包
打包:next build
运行:next start -p 80
把这两个命令修改到 package.json 中
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 80"
}
然后在终端依次执行 npm run build 和 npm run start
当我们运行 npm run build 之后报错,是因为我们在加入 Ant Design 样式时产生的,可以修改为全局引入
在 page 目录下,新建一个 _app.js
文件,然后写入下面的代码。
import App from 'next/app'
import 'antd/dist/antd.css'
export default App
然后我们在终端依次执行 npm run build 和 npm run start
发现可以部署成功了。
注意:
当打包的时候报如下错误
需要先删除 node_modules 目录
然后使用 npm cache clean --force 清除 npm 缓存
最后再次执行 npm install
然后再次在终端依次执行 npm run build 和 npm run start
根据 技术胖个人博客 学习所做的笔记
个人博客:点此进入(http://xueshuai.top)
前端交流群:1063233592