php网站怎么做后台管理,wordpress如何加数据库,旅游电子商务网站推广策略分析,郑州市建设工程信息网站一.手动创建项目
建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作 1.在目录下执行下面命令,初始化package.json文件
npm init -y2.安装react相关包以及next包
yarn add next react react-dom
// 或者
npm install --save next react…一.手动创建项目
建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作 1.在目录下执行下面命令,初始化package.json文件
npm init -y2.安装react相关包以及next包
yarn add next react react-dom
// 或者
npm install --save next react react-dom3.在package.json文件的script节点,新增以下内容 scripts: {...,dev: next, // 开发时运行build: next build, // 打包时运行start: next start // 打完包启动服务的命令}注意:Next.js 只支持React 16及以上
4.根目录下新建pages目录(这里面就是所有页面代码了,会根据这个目录的内容自动生成路由)
5.在pages里面新建index.js,放入以下内容进行测试
export default function(){return div我是pages/index下面的内容/div
}6.启动项目测试
npm run dev
// 或者
yarn run dev7.访问控制台的local地址,显示出如下页面 8.打包
npm run build
// 或者
yarn run build打完包会在项目下新建生成一个.next文件,在根目录下执行如下命令会和开发时看到的效果一致
npm run start
// 或者
yarn run start二.快速创建项目
官网文档
执行下面创建项目的命令
npx create-next-app next-create下面会出现一堆询问的配置信息,这里直接走默认就好了
定义路由
这里的页面都是统一放到app文件夹下面每个文件的page.js文件
例如直接访问localhost:3000则访问的是app/page.js文件
例如直接访问localhost:3000/user则访问的是app/user/page.js文件
export default function(){// className{text-red-500} 使用原子化css标签return div className{text-red-500}我是user/page文件/div
}如果访问的页面有很多网格效果,则去app/globals.css里面把样式都删除,只留前三行即可
页面与布局
将app/Layout.js进行改造
import { Inter } from next/font/google;
import ./globals.css;const inter Inter({ subsets: [latin] });export const metadata {title: Create Next App, // 网站标题description: Generated by create next app, // 描述信息
};export default function RootLayout({ children }) {return (html langenbody className{inter.className}app下面的layout{children}/body/html);
}新建app/user/Layout.js存入以下内容
export default function userLayout({ children }) {return (sectionuser下面的layout{children}/section);
}访问localhost:3000 访问localhost:3000/user 通过对比可以发现,app下面的就是公共的根样式,下面每个Layout.js都会继承到,然后每个文件夹下都可以定义当前路由页面的样式
链接和导航
修改下app/page.js内容如下
use client;
import Link from next/link;
import { useRouter } from next/navigation;export default function Home() {const router useRouter()return (h1 classNametext-4xl text-orange-600Hello Name/h1br/brLink href{/user}跳转到user路由/Linkbr/brbutton onClick{(){router.push(/user)}}点击跳转/user/button/);
}
滚动到新路由的指定位置处,相当于锚点链接
Link href/dashboard#settingsSettings/Link// Output
a href/dashboard#settingsSettings/a路由组
项目下新建三个路径文件
app/(marketing)/about/page.jsapp/(marketing)/bolg/page.jsapp/(marketing)/(shop)/acconut/page.js
在每个page.js里面随便写点内容,访问以下路径
localhost:3000/aboutlocalhost:3000/bolglocalhost:3000/account
可以发现都能被访问到,总结规律就是文件夹名字带括号的相当于可以忽略了
路由组不参与url的设定的
个人感觉唯一作用是用于设置共同的Layout.js
创建如下两个Layout.js文件
app/(marketing)/Layout.jsapp/(marketing)/(shop)/Layout.js
在这两个里面添加如下代码
export default function userLayout({ children }) {return (sectionmarketing下面的layout{children}/section);
}export default function userLayout({ children }) {return (sectionmarketing下面shop的layout{children}/section);
}运行后会发现,marking的Layout,js被它里面所有文件所共用,shop里面的Layout.js被shop里面的文件所共用,因为这个案例shop在marking里面的,因此shop里面的文件也共用marking里面的样式,这就是路由组,按照上面传统的方式建路由,需要每个文件单独设置自己的Layout.js,使用路由组可以达到复用性
动态路由
在app/user新建[username]文件夹,里面的page.js文件内容如下
export default function({params}){console.log(params,params);return div我是user/[username]动态路由{params.username}/div/
}将app/page.js内容修改如下
use client;
import Link from next/link;
import { useRouter } from next/navigation;export default function Home() {const router useRouter()return (h1 classNametext-4xl text-orange-600Hello Name/h1br/brLink href{/user/王二}跳转到user路由/Linkbr/brbutton onClick{(){router.push(/user/王五)}}点击跳转/user/button/);
}当点击跳转到路由时,后面的参数就是动态参数,文件名username就是参数名,可以被params.username接收到并显示到页面上
上面有个弊端就是只支持一级动态参数,如果希望多级的话可以将[username]文件名换成[…username]这样就是可以匹配到后面所有参数,如下地址
localhost:3000/user/1/2/3/4/5
效果图 但是这里建议将[…username]文件名替换为[[…username]],两者区别在于[[…username]]当动态参数为空时也会被匹配到,剩余部分两者功能一致
Loadding加载和流的处理
1.在app下面新建Loading.js组件
export default function(){return div className{text-2xl text-pink-400}Loading.../div
}2.修改app/Layout.js
import { Inter } from next/font/google;
import { Suspense } from react;
import Loading from ./loading; // 引入app/loading.js
import ./globals.css;const inter Inter({ subsets: [latin] });export const metadata {title: Create Next App, // 网站标题description: Generated by create next app, // 描述信息
};export default function RootLayout({ children }) {return (html langenbody className{inter.className}Suspense fallback{Loading/Loading} // 2.使用SusPense将页面包裹app下面的layout{children}/Suspense/body/html);
}子组件代码
这里使用了async/await模拟了一下异步,这是个细节,因为上面的loadding效果如果要出来的话,页面数据必须要是有异步效果,因为我没注意到这点,费了点时间才搞明白
export default async function Posts() {await new Promise((resolve) setTimeout(resolve, 2000));return div1111/div;
}注意:将Lodding放到app/Layout.js里面包裹的话,则针对所有页面生效,如果某个页面有不一样的loading效果的话,则需要在当前文件夹里面的Layout.js去单独引入对应的Loading.js,可以在当前文件夹里面创建个Loading.js,这样的话Loading.js的样式仅仅作用于当前文件夹下的所有页面
import { Suspense } from react;
export default function userLayout({ children }) {return (section// 这个loading效果仅作用于当前文件夹下面的所有页面Suspense fallback{div className{text-2xl text-pink-400}Loading.../div}user下面的layout{children}/Suspense/section);
}注意:必须是渲染的页面内有异步操作(如async/await)才会有Loading.js效果
错误处理
新建app/error.js,放入以下内容
use clientexport default function({error,reset}){return (divh2我是全局的错误样式处理/h2button onClick{()reset()}重试一下/button/div)
}也可以对每个页面单独定义路由样式,只需要在目标页面的文件夹内新建error.js,放入以下内容即可
例如我在app/user/error.js内加入以下内容
use clientexport default function({error,reset}){return (divh2app/user 页面内有错误啦!!!/h2button onClick{()reset()}重试一下/button/div)
}例如我们在目标的user页面加入一些错误信息
export default function Posts() {console.log(a,a); // 这里没有a变量,因此这里会报错return div1111/div;
}当我们在浏览器访问localhost:3000/user就会报出以下错误 当我们访问其他页面有错误信息时,但是没有给那个页面单独定义错误样式,则会触发全局的错误样式
例如访问: localhost:3000/about 组件化渲染
并行路线,也就是web端的组件
在app下面新建home和setting文件夹,里面都新建一个page.js文件,在里面写一点页面
在app/Layout.js里面改为如下页面代码
import { Inter } from next/font/google;
import { Suspense } from react;
import Loading from ./loading;
import ./globals.css;const inter Inter({ subsets: [latin] });export const metadata {title: Create Next App, // 网站标题description: Generated by create next app, // 描述信息
};export default function RootLayout({ children,home,setting }) {return (html langenbody className{inter.className}Suspense fallback{Loading/Loading}app下面的layout{home}{children}{setting}/Suspense/body/html);
} 可以发现组件效果已经出来了
但是上面的仅限于在Layout.js里面使用的组件,下面是可以应用到我们页面里面的组件的案例
在app平级处创建components/frame/index.js,放入以下内容
import Image from next/image;export default function({photo}){console.log(photo,photo);return Image src{photo.src} alt width{600} height{600} className{w-full object-cover aspect-square col-span-2 w-28}/Image/
}在app里面新建photo/page.js文件,插入以下内容
import Photo from /components/frame // 引入组件
export default function(){const photo {src:https://take-saas.oss-cn-hangzhou.aliyuncs.com/wechat_applets/coach/bgcimg/bgc-13.png}// 给组件传值return Photo photo{photo}/Photo
}注意:这里可能会报错图片问题(网络图片需要加一下白名单才能正常加载,如下在next.config.mjs里面进行配置)
/** type {import(next).NextConfig} */
const nextConfig {images:{domains:[take-saas.oss-cn-hangzhou.aliyuncs.com] // 这里是存放域名白名单处}
};export default nextConfig;
然后就可以看到图片正常加载了 定义404页面
在app下面新建not-found.js,放入以下内容
export default function(){return div className{text-2xl text-pink-400}访问页面不存在.../div
}当页面访问一个不存在的页面路由时,页面显示效果如下 PS:由于博客内容都是自学做的整理,在某一次排查问题时,也就是刚好博客写到这里时,刷到了一个博主的nextjs教程合集,也挺详细的,力推点击进入合集地址
三.重新创建带src文件目录的项目
跟刚刚步骤一样,只是选择配置的时候选择使用src目录
路由
路由跳转和传参,在src/pages/home/index.js加入以下代码
import Link from next/link;
import Router from next/router;function Home({ items, time }) {return (div classNameHomeLink href{/home/xiaoji}跳转到xiaoji页面/Linkbr/brLink href{home/xiaoji?name萧寂}跳转到xiaoji页面(带参数)/Linkhr/hrbutton onClick{(){Router.push(/home/xiaoji)}}跳转到xiaoji页面/buttonbr/brbutton onClick{(){Router.push(/home/xiaoji?name萧寂)}}跳转到xiaoji页面(第一种带参数)/buttonbutton onClick{(){Router.push({pathname:/home/xiaoji,query:{name:萧寂}})}}跳转到xiaoji页面(第二种带参数)/button/div);
}
export default Home;接收参数,在src/pages/home/xiaoji.js加入以下代码
import { withRouter } from next/router;function xiaoji({ router }) {return (div{router.query.name}/div/);
}// 需要withRouter包裹组件可以取到参数信息
export default withRouter(xiaoji)
路由里面的六个钩子事件
将上面的src/pages/home/index.js代码更改如下,然后查看浏览器控制台的打印语句
import Link from next/link;
import Router from next/router;function Home({ items, time }) {Router.events.on(routeChangeStart,(args){console.log(1.routeChangeStart-路由开始变化,参数为:,args);})Router.events.on(beforeHistoryChange,(args){console.log(2.beforeHistoryChange-浏览器的历史记录状态发生变化(常用于询问用户是否保存页面内容),参数为:,args);})Router.events.on(routeChangeComplete,(args){console.log(3.routeChangeComplete-路由变化结束,参数为:,args);})Router.events.on(routeChangeError,(){console.log(4.routeChangeError-路由发生错误,404不算错误);})Router.events.on(hashChangeStart,(args){console.log(5.hashChangeStart-hash值开始发生变化,参数为:,args);})Router.events.on(hashChangeComplete,(args){console.log(6.hashChangeComplete-hash值变化完成,参数为:,args);})return (div classNameHomeLink href{/home/xiaoji}跳转到xiaoji页面/Linkbr/brLink href{home/xiaoji?name萧寂}跳转到xiaoji页面(带参数)/Linkhr/hrbutton onClick{(){Router.push(/home/xiaoji)}}跳转到xiaoji页面/buttonbr/brbutton onClick{(){Router.push(/home/xiaoji?name萧寂)}}跳转到xiaoji页面(第一种带参数)/buttonbr/brbutton onClick{(){Router.push({pathname:/home/xiaoji,query:{name:萧寂}})}}跳转到xiaoji页面(第二种带参数)/buttonbr/brLink href{#xiaoji}模拟hash值发生变化/Link/div);
}
export default Home;网络请求发送
getStaticProps 和 getServerSideProps
getStaticProps 和 getServerSideProps 是 Next.js 中用于数据获取的两个重要函数它们在页面渲染时分别起到不同的作用。
1、getStaticProps
用途主要用于静态生成页面即在构建时获取数据并将其预先注入到页面中。 执行环境只在构建时运行不会在每次请求时重新运行。 数据获取可以在构建时从外部数据源获取数据并将数据作为 props 传递给页面组件。 适用情况适用于不频繁变化的静态内容如博客文章、产品页面等。 2、getServerSideProps
用途用于服务器端渲染页面即在每次请求时动态获取数据并注入到页面中。 执行环境在每次请求时在服务器端运行可以根据每次请求动态获取数据。 数据获取可以在每次请求时从外部数据源获取数据并将数据作为 props 传递给页面组件。 适用情况适用于需要在每次请求时动态获取数据的情况如用户特定数据、实时数据等。
总的来说getStaticProps 用于静态生成页面适用于不频繁变化的内容而 getServerSideProps 用于服务器端渲染页面适用于需要每次请求时动态获取数据的情况。根据页面的需求和数据更新频率您可以选择合适的函数来获取数据并注入到页面中。
getStaticProps
在src/pages/home/index.js加入以下内容
function Home({ items, time }) {return (div classNameHomeptimer: {time}/p{items.map((item) {return (h4 style{{ margin: 15px 0 }} key{item.qa_id}{item.name}/h4);})}/div);
}export async function getStaticProps() {// 在这里调用外部接口可以写各种服务端代码连数据库访问文件系统.....const resp await fetch(https://fts.jd.com/area/get?fid-1);const items await resp.json();console.log(items,items);// 此函数必须返回 { props: { 需要携带的数据 } } 对象Home 组件在构建时将接收到 items 参数。return {props: {items,time: Date.now(), // 为了方便对比yarn dev和yarn build的区别加入时间戳},};
}export default Home;浏览器访问:http://localhost:3000/home 效果图 getServerSideProps
把上面的代码替换成下面的,然后还是访问相同的路由地址
function Home({ items, time }) {return (div classNameHomeptimer: {time}/p{items.map((item) {return (h4 style{{ margin: 15px 0 }} key{item.qa_id}{item.name}/h4);})}/div);
}export async function getServerSideProps(context) {// 在这里调用外部接口可以写各种服务端代码连数据库访问文件系统.....const resp await fetch(https://fts.jd.com/area/get?fid-1);const items await resp.json();// 此函数必须返回 { props: { 需要携带的数据 } } 对象Home 组件在构建时将接收到 items 参数。return {props: {items,time: Date.now(), // 为了方便对比yarn dev和yarn build的区别加入时间戳},};
}export default Home;这里会发现其实效果是一样的,但是我在props里面返回了个时间戳,我们先运行yarn run build先打包,然后运行yarn run start执行打包后的文件再访问上面的路由地址,观察页面上的时间戳变换,可以发现getStaticProps 方法打包出来的时间戳一直是固定了的,也就是这上面的数据只在初始化就渲染一次,后续不会执行,适合作为静态页面数据获取使用,而getServerSideProps方法打包出来的运行后,时间戳是一直变化的,也就是每次都会从服务器获取数据并渲染
pages页面路由动态获取
在src/pages/home/detial.js加入以下内容
function Detail({ id }) {// 获取文章详情信息数据渲染到组件中。return div classNameDetail{id}/div;}export default Detail;export async function getStaticPaths() {const paths [{ params: { id: 1 } },{ params: { id: 2 } },];return { paths, fallback: false };}export async function getStaticProps({ params }) {const id params.id;// 根据 id 从外部数据源获取数据return { props: { id } };}浏览器访问:http://localhost:3000/home/detial/1 或者 http://localhost:3000/home/detial/2 都能进行访问,除此之外都是404,这样就是给动态参数加了限制,限制了哪些参数允许访问此页面,例如做文章详情之类的,需要传入文章id,如果id不匹配则返回404这种,可以根据后端数据内容动态渲染paths里面的id值,代码如下:
function Detail({ detailData }) {// 获取文章详情信息数据渲染到组件中。return div classNameDetail{JSON.stringify(detailData)}/div;
}export default Detail;export async function getStaticPaths() {// 调用api获取文章列表const resp await fetch(url);const items await resp.json();// 遍历文章列表获取文章id根据文章id生成所有需要预渲染的静态页面路径const paths items.map((item) ({params: { id: ${item.qa_id} }, // id的值必须是字符串类型因为动态路径参数也是字符串类型要保持一致}));// { fallback: false } 不在上述预渲染列表范围内的路径id显示404页面。// 改为true就不会受到限制,默认为falsereturn { paths, fallback: false };
}export async function getStaticProps({ params }) {
// 根据id进行动态请求数据const resp await fetch(url/${params.id});const detailData await resp.json();return {props: {detailData,},};
}getStaticPaths 函数说明
仅在构建时运行。它非常适合预渲染需要在构建时使用动态数据的类似路径如/blog/:id。当与 getStaticProps 结合使用时它会从 数据库/接口 等数据结构中生成动态页面然后 Next 可以对其进行静态服务getStaticPaths 只能和 getStaticProps 配合使用不能和 getServerSideProps 一起使用
如果fallback参数为true,则在构建时没有生成的路径不会导致404页面可以先暂时为用户提供一个临时页面同时 next 会去后台会运行 getStaticProps 函数对构建时没有生成的路径页面进行动态预渲染。可以将上面的页面进行如下改造
import { useRouter } from next/router;function Detail({ id }) {// 获取文章详情信息数据渲染到组件中。const router useRouter();if (router.isFallback) {return div正在请求请稍后.../div; // 临时页面给用户友好提示}return div classNameDetail{id}/div;}export default Detail;export async function getStaticPaths() {const paths [{ params: { id: 1 } },{ params: { id: 2 } },];return { paths, fallback: true };}export async function getStaticProps({ params }) {const id params.id;// 根据 id 从外部数据源获取数据return { props: { id } };} 组件
在src下面新建components文件夹,新建demo.js文件
export default function ({children}){return div{children}/div
}在pages/home/xiaoji.js里面使用
import Demo from /components/demo;export default function (){return Demobutton我是萧寂/button/Demo
}效果图 项目结构如下
页面css编写
行内样式
function Home({ items, time }) {return (div我是萧寂/divdiv classNameHome我是萧寂/divstyle jsx{div{color:blue;}.Home{color:red;}}/style/);
}export default Home;效果图 外部样式
在src新建static文件夹再新建index.css文件,存入以下内容
div{color: blue;
}
.Home{color: red;
}import ../../static/index.css
function Home({ items, time }) {return (div我是萧寂/divdiv classNameHome我是萧寂/div/);
}export default Home;效果和上面相同
自定义页面的Header头,用于优化SEO
单个页面自定义(建议将Head单独封装成组件,在每个页面引入使用)
import { parseSetCookie } from next/dist/compiled/edge-runtime/cookies;
import Head from next/head;
function Home({ items, time }) {return (Headtitle萧寂牛逼/titlemeta charSetutf-8/meta/Headdiv我是萧寂/div/);
}export default Home;