动静表单
初始化必须给{}赋值表单的name与值,否则会报不受控(即便是遍历进去的表单)
动静款式
计划一:CSS Module + classnames
import classNames from 'classnames' function Render () { return ( <div className={ classNames( ProgressStyles.fragment, { [ProgressStyles.fragmentActive]: idx <= activeIndex } ) } key={idx}>{idx}</div> )}
Notes: CSS Modules不反对连字符、下划线连接。
.fragment { background: rgba(0, 0, 0, 0.06); flex: 1; & + & { margin: { left: 10px; }; } &Active { background: #0F68FF; }}
计划二:款式浸透
:global
:global { .ant-select-selector { border: 1px solid #E5E5E5; background: linear-gradient(125.85deg, rgba(59, 63, 238, 0.1) 0%, rgba(57, 159, 254, 0.1) 100%); @media screen and (min-width: 550px) { height: nth($lineHeight, 1)!important; line-height: nth($lineHeight, 1)!important; } @media screen and (max-width: 550px) { height: nth($lineHeight, 2)!important; line-height: nth($lineHeight, 2)!important; } } .ant-select-selection-placeholder { @include placeholder; } } :global(.swiper-slide) { cursor: pointer; }
组件定义
Slot定义
SwiperCommon组件的调用,须要用SwiperCommon外部遍历的列表项数据:
export default function Render () { return ( <SwiperCommon className="newsSwiper" metas={data.list} options={}> { (meta) => ( <section className={NewsStyles.swiperSlide} onClick={() => handleClick(meta.id)}> <div className={NewsStyles.coverWrapper}> <Image alt={meta.title} src={meta.cover} className={NewsStyles.img}/> </div> <p className={NewsStyles.slideTitle}>{meta.title}</p> <p className={NewsStyles.summary}>{meta.summary}</p> <p className={NewsStyles.date}>{meta.time}</p> </section> ) } </SwiperCommon> )}
ScopedSlot定义:
import { useEffect } from 'react';import SwiperCommonStyles from '@/styles/swiper-common.module.scss'function SwiperCommon ({ children, metas = [], className: externalClass, options = {}}) { useEffect(() => { const swiper = new Swiper(`.${externalClass || 'swiper'}`, { direction: 'horizontal', centerInsufficientSlides: true, ...options }); }, [externalClass, options]) return ( <> { metas.length && ( <div className={classNames(SwiperCommonStyles.swiper, `swiper ${externalClass}`)}> <div className={classNames(SwiperCommonStyles.swiperWrapper, 'swiper-wrapper')}> { metas.map((item, idx) => ( <div key={idx} className={classNames(SwiperCommonStyles.swiperSlide, 'swiper-slide')}> {children && children(item)} </div> )) } </div> </div> ) } </> )}export default SwiperCommon
参数解构
<!--闭合标签应用时,组件参数类型申明中蕴含children--> <NavigationBar title="This is title" > </NavigationBar> <!--空标签应用时,组件参数类型申明中不蕴含children--> <NavigationBar title="This is title" />
组件的参数解构:
import NavigationBarStyles from "../styles/navigationbar.module.scss"function Navigationbar ({ children, title = "", historyBack = false }) { return ( <div className={NavigationBarStyles.container}> {historyBack && (<div className={NavigationBarStyles.historyBack}><</div>)} <NavigationbarContent title={title}>{children}</NavigationbarContent> </div> )}export default Navigationbar
Notes:
<NavigationBar />
模式调用组件,解构进去的children
为undefined
<NavigationBar></NavigationBar>
模式调用组件,即便子节点为空,也能解构进去的children
为[]
全局SCSS变量配置
https://stackoverflow.com/questions/60951575/next-js-using-sass-variables-from-global-scss
const path = require('path');const nextConfig = (phase, { defaultConfig }) => { if ('sassOptions' in defaultConfig) { defaultConfig['sassOptions'] = { includePaths: [path.join(__dirname, 'styles')], prependData: `@import "utils.scss";`, }; } return defaultConfig;};module.exports = nextConfig;
全局可拜访变量
在根目录下定义.env
、.env.development
、.env.production
、.env.local
文件
Node环境
HOSTNAME=localhostPORT=8080HOST=http://$HOSTNAME:$PORT
Notes:
- 以上变量在Node环境中可通过
process.env.HOSTNAME
模式获取,无奈在浏览器中获取; - 能够通过
$Variable
的模式,在另一个变量定义中援用其余变量
Browser环境
NEXT_PUBLIC_API_BASEURL=http://127.0.0.1:3000
Notes:
- 以上变量能够在Node、Browser环境中可通过
process.env.NEXT_PUBLIC_API_BASEURL
模式获取 - 以
NEXT_PUBLIC_
前缀定义变量能够裸露在浏览器环境;
限度
只能通过
process.env.VarName
的模式拜访,无奈通过解构、[变量]模式拜访process.env[varName]
——> Errorconst env = process.env
——> Error
类型申明
https://dmitripavlutin.com/typescript-react-components/
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts
图片渲染
Nextjs图片渲染官网文档
- 应用
'next/image'
提供的组件,会提供图片优化 — 懒加载 - 应用
'next/image'
提供的组件,必须设定图片尺寸,图片尺寸若要依据父级尺寸,需设置父元素position: relative
,<Image layout="fill"...
— 此时生成的img
标签是相对定位的。
import Image from 'next/image';import welcomeStyles from '../styles/welcome.module.scss';export default function Home() { return ( <> <section className={welcomeStyles.navigationbar}> <h1 className='navigationbar-title'>new world</h1> </section> <section className={welcomeStyles.main}> <h2 className={welcomeStyles.title}>Welcome new world!</h2> <div className={welcomeStyles.cover}> <Image layout="fill" objectFit="cover" src="/images/entries/wel.png" alt="" /> </div> </section> </> );}
客户端渲染
useEffect(() => { import("../lib/flexible"); import("../lib/flexibleHelper"); }, []);
api Route
api定义
范指/pages/api/**/*.js
门路下的文件,该处次要是转接服务端接口,直达前端数据结构。
// /pages/api/blogexport default function handler(req, res) { // 导出的函数办法名无实际意义 res.status(200).json({ name: 'John Doe' })}
Notes: 该JavaScript是服务端代码,而非H5前端代码;
api拜访
export async function getStaticProps(context) { const res = await fetch(`${process.env.BaseUrl}/api/blog`) const features = await res.json() return { props: { features, }, }}export default function Blog ({features}) { const features = response return ( <> <News meta={features.NewsResponse} /> </> )}
Notes: 前端必须通过http(s)协定申请,所以,必须启动服务才能够拜访Api Route
导出纯动态页面
导出不须要服务配置,可独立拜访的HTML动态页面(留神:SSG也是须要服务端配置的)
- 示例中的Nextjs在13.3(不含)以下版本:
13.2.4
- 页面内的数据都是本地Mock的JSON数据
- 批改
next.config.js
配置:
const nextConfig = (phase, {defaultConfig}) => { defaultConfig.reactStrictMode = true defaultConfig.exportPathMap = async function (defaultPathMap) { return { '/': { page: '/' }, '/news': { page: '/news' }, '/blog': { page: '/blog' }, } } defaultConfig.images.unoptimized = true return defaultConfig}module.exports = nextConfig
- 配置
exportPathMap
字段,官网文档申明13.3版本以上会主动生成,无需配置 - 配置
images.unoptimized = true
,不容许优化图片,否则会报错
- 补充
package#scripts
,运行npm run export
"scripts": { "dev": "next dev", "build": "next build", "export": "next build && next export && npm run build-static-repair-index && npm run build-favicon-repair-index && npm run build-logo-repair-index", "build-static-repair-index": "replace-in-files --string \"/_next/static\" --replacement \"/_next/static\" out/index.html", "build-favicon-repair-index": "replace-in-files --string \"/favicon.ico\" --replacement \"./favicon.ico\" out/*.html", "build-logo-repair-index": "replace-in-files --string \"/logo*.png\" --replacement \"./logo*.png\" out/*.html", "start": "next start", "lint": "next lint" },
- 动态打包后的资源援用地址不对,目前没找到配置项可用,需借助于
replace-in-files
独自解决资源援用。
- 将
/out
中的动态资源部署即可