关于next.js:Next14-app-Trpc-部署到-Vercel

本文应用了 MongoDB, 还没有集成的能够看一下上篇文章 Next14 app +Vercel 集成 MongoDBnext13 能够参考 trpc 文档 而且谷歌上曾经有不少问题解答,然而目前 next14 app 只看到一个我的项目中有用到 Github 仓库,目前这个仓库中服务端的上下文获取存在问题,目前找到一个有用的能够看 Issus。目前 trpc 对 next14 app 的反对进度能够看 Issus好的进入 注释 装置依赖包(这里我的依赖包版本是 10.43.1) yarn add @trpc/serve @trpc/client @trpc/react-query zod创立中间件 context.ts(我的trpc 相干文件的门路是 src/lib/trpc/)。这里我有用到 JWT 将用户信息挂载在上下文中 import { FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';import Jwt from 'jsonwebtoken';type Opts = Partial<FetchCreateContextFnOptions>;/** * 创立上下文 服务端组件中没有req resHeaders * @see https://trpc.io/docs/server/adapters/fetch#create-the-context */export function createContext(opts?: Opts): Opts & { userInfo?: Jwt.JwtPayload;} { const userInfo = {}; return { ...(opts || {}), userInfo };}export type Context = Awaited<ReturnType<typeof createContext>>;创立 trpc.ts 文件寄存实例 ...

March 4, 2024 · 6 min · jiezi

关于next.js:Next14-app-Vercel-集成-MongoDB

首先须要浏览集成文档 https://www.mongodb.com/developer/products/atlas/how-to-conne... 该文档是将从零集成(从创立账号到创立储存库)当你达到这一步的时候,你的 Vercel 中会有一个环境变量名称为 MONGODB_URI 这时候你也能够依照集成文档中 同步Vercel环境变量 进行同步,也能够间接将 MONGODB_URI变量复制到本地环境 当你做完这些后能够浏览 文档 ,该文档会教你 注意事项、以及与 Vercel 集成办法(这个咱们曾经依照下面的步骤以及集成了则能够跳过)、以及在 Atlas UI 中 治理 Vercel 连贯这里是我的 Atlas UI 面板,能够看到左上角我有一个 next 的组织,而后有一个项目名称也叫 next 有一个库叫做 Cluster0,并且我的 next 我的项目是与 Vercel 相绑定,Vercel Projects 中我绑定了两个我的项目一个 yintan 一个 blasfin。 你在你绑定的我的项目中 Database Access 菜单中能够看到有一个 vercel-admin-user-xxxxx,这是你集成 vercel 主动创立 前置步骤做完后进入代码中 正题下载 mongodb 依赖包(如果没有的话)新建 db.ts 文件,你能够在 src/server 或者 src/lib 创立。上面这段代码能够在 vercel 示例我的项目 中找到。请保障你的环境变量中有 MONGODB_URI import { MongoClient } from 'mongodb';const uri = process.env.MONGODB_URI as string; // your mongodb connection stringconst options = {};declare global { var _mongoClientPromise: Promise<MongoClient>;}class Singleton { private static _instance: Singleton; private client: MongoClient; private clientPromise: Promise<MongoClient>; private constructor() { this.client = new MongoClient(uri, options); this.clientPromise = this.client.connect(); if (process.env.NODE_ENV === 'development') { // In development mode, use a global variable so that the value // is preserved across module reloads caused by HMR (Hot Module Replacement). global._mongoClientPromise = this.clientPromise; } } public static get instance() { if (!this._instance) { this._instance = new Singleton(); } return this._instance.clientPromise; }}const clientPromise = Singleton.instance;// Export a module-scoped MongoClient promise. By doing this in a// separate module, the client can be shared across functions.export default clientPromise;在 src/app/api/db/[collection] 文件夹中新建 route.ts 文件 ...

March 3, 2024 · 2 min · jiezi

关于next.js:NextJS-Trpc-PayloadCMS-MongoDB-自定义服务器搭建

自定义服务器启动相干依赖dotenv 读取 env 文件数据express node 框架<details> <summary>根底示例如下</summary> // src/server/index.tsimport 'dotenv/config';import express from 'express';import chalk from 'chalk';const port = Number(process.env.PORT) || 3000;const app = express();const nextApp = next({ dev: process.env.NODE_ENV !== 'production', port: PORT,});const nextHandler = nextApp.getRequestHandler();const start = async () => { // 筹备生成 .next 文件 nextApp.prepare().then(() => { app.all('*', (req, res) => { return nextHandler(req, res); }); app.listen(port, () => { console.log( '\x1b[36m%s\x1b[0m', `> Ready on http://localhost:${port}` ); }); });};start();</details> ...

March 3, 2024 · 14 min · jiezi

关于next.js:nextjs-源码解析-getStaticPropsgetStaticPaths-篇

良久前写了对于 getStaticProps 和 getStaticPaths 的内容,然而半年过来了源码解析就始终遗记了,不久前有人揭示才想起来,补下坑。本文次要是解读下 getStaticProps、getStaticPaths 相干的源码,不理解这两个 API 的倡议先看下之前的文章再看。 getStaticProps首先 getStaticProps 是利用于 SSG 场景,咱们先看下 packages/next/server/render.tsx 中相干的代码: const isSSG = !!getStaticProps;const pageIsDynamic = isDynamicRoute(pathname);if (isSSG && !isFallback) { let data: UnwrapPromise<ReturnType<GetStaticProps>>; try { data = await getStaticProps!({ ...(pageIsDynamic ? { params: query as ParsedUrlQuery } : undefined), ...(isPreview ? { preview: true, previewData: previewData } : undefined), locales: renderOpts.locales, locale: renderOpts.locale, defaultLocale: renderOpts.defaultLocale }); } catch (staticPropsError: any) { // .... } // ...}isFallback 能够先不论。能够看到 getStaticProps 同样能够为异步函数,而是否为 SSG 就是由是否存在 getStaticProps 函数来决定的,SSG 场景下的 pageIsDynamic 则必须配合 getStaticPaths 应用,能够看到 getStaticProps 会接管几个参数: ...

August 15, 2023 · 4 min · jiezi

关于next.js:NextjsCookie鉴权续期退出登录

前言之前写过对于next.js鉴权操作cookie的文章,Next.js-cookie鉴权+续期1和Next.js-cookie鉴权+续期2,最近chatgpt十分火,于是我问它next.js鉴权最佳实际,上面是它的答复: 设置正当的 cookie 有效期:正当的 cookie 有效期应该依据网站的特点来确定,通常倡议将其设置为肯定工夫内(如 30 分钟)。援用定时刷新 cookie 的有效期:能够通过服务器端的 HTTP 拦截器来监测每个申请的 cookie 是否行将过期,当发现其行将过期时,立刻从新设置一个新的 cookie,并在响应头中返回给客户端。援用前端优化提醒弹窗:通过前端 JavaScript 实现 cookie 弹窗过期揭示,将其联合到用户体验优化计划之中,提供清晰的提醒,帮忙用户解决 cookie 续期或是否敞开要求。 援用风控,管制 cookie 的数据权限:依据用户的操作行为等危险因素,为 cookie 设置不同的权限级别,限度 cookie 的数据权限。 援用应用 HTTPS 协定:采纳 HTTPS 协定,可保障传输过程中传输平安。 在实践中,续期策略须要依据不同网站的业务场景,以及用户的应用习惯,思考相应的细节状况。于是我又问,cookie轮询操作是不是影响服务器性能,于是它答复我: 在用户沉闷期间,页面会始终更新并续期 cookie。为了查看 cookie 是否过期并续期它,能够在页面中应用 useEffect 监听 window 对象的 focus 事件,当用户回到页面时查看 cookie 是否过期。如果 cookie 快要过期,就续期它。于是我又问,应用 useEffect 监听 window 对象的 focus 事件好还是轮询好,上面是它的答复: 应用 window.addEventListener("focus", handleFocus) 更好,因为它可能响应用户的交互行为,缩小不必要的拜访和资源耗费。如果应用轮询,每隔固定的工夫距离就会向服务器发送申请,这可能会节约用户的工夫和网络带宽,对服务器也会造成额定的压力。而应用 window.addEventListener("focus", handleFocus) 到用户呈现交互行为时才会进行操作,这是更高效和精确的形式。于是,我就又把之前的鉴权颠覆了,应用了chatgpt举荐的形式,分享给大家。 操作前端操作首先在布局页面监听用户的动作,而后调用验证cookie的操作,如果快要过期则返回以set-cookie的形式返回给前端浏览器中保留,否则不做解决,这样比轮询操作既简略又不便,又不会频繁发动申请耗费服务器性能。 layout.js // 监听用户动作,如果页面被点击就申请cookie是否将要过期,如果是则返回新cookie,否则不做anything useEffect(() => { setMounted(true) // 判断是否是客户端 if (process.browser && isLogin){ window.addEventListener("focus", handleFocus); return () => { window.removeEventListener("focus", handleFocus); }; } }, []) // 验证cookie是否将要过期,如果是返回新cookie写入到浏览器 async function handleFocus(){ const res = await dispatch(refreshCookie()) if (res.payload.status === 40001){ confirm({ title: '登录已过期', icon: <ExclamationCircleFilled />, content: '您的登录已过期,请从新登录!', okText: '确定', cancelText: '勾销', onOk() { // 从新登录 location.href = '/login' }, onCancel() { // 刷新以后页面 location.reload() }, }); } }咱们把之前操作中的axiosInstance.interceptors.response.use(function (response)代码全副移除掉,只剩下上面的代码: ...

May 8, 2023 · 4 min · jiezi

关于next.js:Nextjs水合作用

前言最近在看三国演义,开篇第一段话:话说天下大势,分久必合,合久必分。我把这段话用来解释next.js+redux水合作用再失当不过了。 什么是水合?水合是咱们在next.js我的项目中引入next-redux-wrapper插件之后给出的一个新概念,它是连贯和对立客户端和服务端数据的一个重要纽带。 英文名叫HYDRATE,中文叫水合又叫水化,我在网上搜寻的答复: 水合物指的是含有水的化合物,其范畴相当宽泛。其中水能够以配位键与其余局部相连,如水合金属离子,也能够是以共价键相结合,如水合三氯乙醛。也能够指是天然气中某些组分与水分在肯定温度、压力条件下造成的红色晶体,外观相似致密的冰雪,密度为0.88\~0.90 g/cm^3^。水合物是一种笼形晶体包络物,水分子借氢键联合造成笼形结晶,气体分子被突围在晶格之中。看得我一头雾水,于是联合我本人的了解我来解释下何为水合,如果解释的不对,也心愿大家对我批评指正。 艰深的说就是同一个水源进去多个分支的水流,最初水流又从新汇聚成新的水源,再反复这个过程。有点相似git下面的分支,有一个总分支master,还有子分支dev/test/uat等等,离开开发完又合并到总分支master。 不晓得我这样解释能不能帮忙你们了解,而在代码层面就是:关上一个新页面,或者切换新的路由的时候,Redux数据源Store会分流到所有Pages中的页面,最初在Reducer中合并服务端和客户端数据成新的Store数据源,再反复这样的过程。 具体的过程next-redux-wrapper插件官网给出了解释: Using next-redux-wrapper ("the wrapper"), the following things happen on a request: Phase 1: getInitialProps/getStaticProps/getServerSideProps The wrapper creates a server-side store (using makeStore) with an empty initial state. In doing so it also provides the Request and Response objects as options to makeStore.In App mode: The wrapper calls the _app's getInitialProps function and passes the previously created store.Next.js takes the props returned from the _app's getInitialProps method, along with the store's state.In per-page mode: The wrapper calls the Page's getXXXProps function and passes the previously created store.Next.js takes the props returned from the Page's getXXXProps method, along with the store's state.Phase 2: SSR ...

April 19, 2023 · 3 min · jiezi

关于next.js:Nextjs实战记录

动静表单初始化必须给{}赋值表单的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外部遍历的列表项数据: ...

April 18, 2023 · 3 min · jiezi

关于next.js:Nextjs页面重复渲染水合问题

案例我从2020年开始始终应用next.js做为我的前端SSR框架,应用@reduxjs/toolkit做为全局状态管理器,应用next-redux-wrapper帮助next.js连贯和合并redux中store数据并且放弃不变,否则会导致数据反复渲染性能问题,然而最近发现一个很奇怪的问题:就是router.push路由跳转的时候导致以后页面反复渲染问题! 换句话说也就是:我从PageA跳转到PageB,应该是只有PageB页面才会渲染,然而当初岂但PageB渲染了,PageA也渲染了!!! 剖析与操作通过我应用排除代码的形式剖析发现,原来每次路由导航的时候都会触发useSelector这个办法,而这个办法是react-redux插件的。 为什么会导航的时候会触发useSelector呢?我又在网上搜寻相干话题,终于被我找到一篇文章react-redux应用useSelector获取数据导致组件反复渲染的问题 通过redux中的hooks – useSelector 获取store中的数据时,只有store中的数据产生了扭转,即便组件中并没有获取批改的数据,组件也会进行从新渲染。也就是说造成反复渲染的起因是因为redux中store数据源变动了导致的。 于是咱们应用文中提到的设置useSelector的第2个参数,雷同的时候返回true会阻止反复渲染,不同的时候返回false从新渲染的机制,咱们应用了lodash的isEqual办法来判断。 留神:react-redux自带的shallowEqual办法是浅比拟,所以是数组对象的状况下比拟是有问题的,所以这里咱们应用了lodash的isEqual办法来深度比拟判断。 import _ from 'lodash'const {userInfo, latestNews, likeUrls, reportUrls} = useSelector((state) => state.home, (_old, _new)=>{ console.log('old=',_old,',new=',_new) return _.isEqual(_old, _new) });然而问题是,我只是做了一个路由跳转为什么会导致redux中store数据源前后不统一呢? 于是我加了个打印日志的代码,如下: 发现的确不一样了,而且次要集中在latestNews, likeUrls, reportUrls这三个数据源上,而userInfo不变。 这是为什么呢?于是我又看了一下next-redux-wrapper文档,发现外面这段代码和一段形容: State reconciliation during hydrationEach time when pages that have getStaticProps or getServerSideProps are opened by user the HYDRATE action will be dispatched. This may happen during initial page load and during regular page navigation. The payload of this action will contain the state at the moment of static generation or server side rendering, so your reducer must merge it with existing client state properly.翻译成中文 ...

March 2, 2023 · 1 min · jiezi

关于next.js:Nextjs用户认证和刷新token方案

前言最近在应用Next.js的时候发现用户认证和刷新token时候跟之前单页面利用SPA的token认证和刷新token计划有所出入,实现起来也更简单,于是本人参考B站、掘金、思否和简书的SSR网站折腾了一段时间终于解决了这个问题,分享给大家做参考,如果你们感觉文中有不妥的中央也心愿不吝指出。 单页面利用TOKEN认证和刷新计划咱们在用SPA做后盾管理系统认证受权的时候,始终采纳的是jwt token计划,这套计划简略而高效,流程如下: 1、用户登录胜利后盾生成jwt token并返回给前端保留到localstorage 2、前端接口通过axios申请头上携带Authorization: token 传递给后盾做认证 3、后盾通过前端传递过去的token验证是否通过 4、如果token过期,能够通过axios的拦截器拦挡401状态码并带上refresh_token从后盾获取新token并保留到localstorage中 上面是axios拦截器的应用,参考 axios.interceptors.response.use( error => { /* *当响应码为 401 时,尝试刷新令牌。 */ if (status == 401) { return axios.post('/api/login/refresh', {}, { headers: { 'Authorization': 'Bearer ' + getRefreshToken() } }).then(async response => { const data = response.data.data setToken(data.token) setRefreshToken(data.refreshToken) error.response.config.headers['Authorization'] = 'Bearer ' + data.token return await axios(error.response.config).then(res => res.data) }).catch(error => { //清理token store.dispatch('user/resetToken') this.router.push('/login') return Promise.reject(error) }) } }) ...

August 19, 2022 · 5 min · jiezi

关于next.js:Nextjs-服务端操作Cookie

前言最近应用next.js开发过程中发现服务端set-cookie返回设置到浏览器不胜利,于是钻研了一下如何解决,分享给大家。 操作前后台cookie如何互相传递?1、前端如何传递cookie到后盾? 前端通过axios(或者fetch也能够)调用后盾接口的时候通过request申请头header的cookie属性(前端是你的浏览器中存在Cookie)带到后盾,前提是要同源,如:前端地址是:www.baidu.com,后盾是:www.baiud.com/api或者api.baidu.com,这样的能力拜访浏览器中的cookie。 2、后盾如何传递cookie到前端? 后盾通过response申请头header的set-cookie属性带到前端浏览器,主动就能写到指定域名下。 理解next.js的执行过程const pageA = (props) => { return <div> this is Page A</div>}export async function getServerSideProps(context) { const res = await axios({ url: "http://www.baidu.com/api/getUserList", data: xxx }); const data = res?.data; return { props: { data } }}export default pageA;下面是一段非常简单的next.js页面的代码,它分为两局部,页面pageA和服务端获取接口数据getServerSideProps,当刷新页面或者首次关上页面时首先执行的是getServerSideProps办法,执行实现 之后才到pageA办法体中,是这样一个执行过程。 这也是SSR渲染最外围的中央,先从后盾返回数据再渲染出页面,缩小SPA解释js的等待时间。 留神:getServerSideProps办法只有在页面第一次渲染的时候才执行(或者刷新页面、跳转页面),前面就不会再进来了。 next.js客户端如何传递cookie到后盾?首先咱们看一个问题就是下面的http://www.baidu.com/api/getUserList接口是没方法传递cookie到后盾的,为什么不能把cookie传递到后盾呢?怎么能力传递cookie到后盾呢? 首先答复第一个问题,因为getServerSideProps执行在服务端所以是拿不到浏览器外面的cookie的,这时候须要通过next.js的context属性拿到。 答复第二个问题,只有通过上面的代码手动指定,这也是SSR非凡的中央。 axios.defaults.headers.cookie = context.req.headers.cookie || null当然如果页面曾经渲染完,这时候你通过页面管制接口的拜访的时候就不必这么麻烦,因为浏览器会主动帮你把cookie带到接口的申请头:request header cookie上。 next.js服务端如何传递cookie到客户端浏览器?曾经理解如何将cookie从客户端传递到服务端之后 ,咱们再来解决如何将cookie从服务端传递到客户端浏览器中,下面曾经讲过后盾是通过接口中返回的response申请头中的set-cookie属性传递过去的,如果是SPA那么间接就能够设置到Cookie中,然而咱们是SSR是next.js当然没那么简略了,那么咱们如何设置呢? 要做两步操作:1、对axios返回申请头做设置2、getServerSideProps办法中再次设置set-cookie const axiosInstance = axios.create({ baseURL: `http://www.baidu.com/api`, withCredentials: true,});axiosInstance.interceptors.response.use(function (response) { axiosInstance.defaults.headers.setCookie = response.headers['set-cookie'] return response;}, function (error) { // 超出 2xx 范畴的状态码都会触发该函数。 // 对响应谬误做点什么 return Promise.reject(error);});export default axiosInstance;下面的axiosInstance.defaults.headers.setCookie = response.headers['set-cookie']代码就是把后盾返回的set-cookie属性赋值给axiosInstance.defaults.headers.setCookie,而后,回到getServerSideProps办法中,再在最初返回给浏览器中,如下所示: ...

August 17, 2022 · 3 min · jiezi

关于next.js:NextjsReactNode系统实战搞定SSR服务器渲染内附文档源码

Next.js+React+Node零碎实战,搞定SSR服务器渲染内附文档源码下载地址:百度网盘Java 诊断工具 Arthas-实操案例实操案例排查函数调用异样通过curl 请求接口只能看到返回异样,然而看不到具体的请求参数和堆栈信息。shell@Alicloud:~$ curl{"timestamp":1655435063042,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码查看UserController的 参数/异样在Arthas里执行:watch com.example.demo.arthas.user.UserController * '{params, throwExp}'复制代码 第一个参数是类名,反对通配第二个参数是函数名,反对通配 拜访watch命令会打印调用的参数和异样再次通过curl 调用可能在arthas外面查看到具体的异样信息。把获取到的后果开展,可能用-x参数:watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2复制代码返回值表达式在下面的例子里,第三个参数是返回值表达式,它实际上是一个ognl表达式,它反对一些内置对象: loaderclazzmethodtargetparamsreturnObjthrowExpisBeforeisThrowisReturn 比如返回一个数组:watch com.example.demo.arthas.user.UserController * '{params[0], target, returnObj}'复制代码条件表达式watch命令反对在第4个参数里写条件表达式,比如:当拜访 user/1 时,watch命令没有输入当拜访 user/101 时,watch会打印出后果。 当异样时捕捉watch命令反对-e选项,示意只捕捉抛出异样时的请求:watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e复制代码按照耗时进行过滤watch命令反对按请求耗时进行过滤,比如:watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'复制代码热更新代码这个也是真的秀。 拜访 http://localhost:61000/user/0 ,会返回500异样:shell@Alicloud:~$ curl http://localhost:61000/user/0{"timestamp":1655436218020,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码通过热更新代码,修改这个逻辑。jad反编译UserControllerjad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java复制代码jad反编译的后果保存在 /tmp/UserController.java文件里了。再打开一个Terminal 窗口,而后用vim来编辑/tmp/UserController.java:vim /tmp/UserController.java复制代码比如当 user id 小于1时,也失常返回,不抛出异样:@GetMapping(value={"/user/{id}"})public User findUserById(@PathVariable Integer id) { logger.info("id: {}", (Object)id);if (id != null && id < 1) { return new User(id, "name" + id); // throw new IllegalArgumentException("id < 1");}return new User(id.intValue(), "name" + id);}复制代码sc查找加载UserController的ClassLoader[arthas@1266]$ sc -d *UserController | grep classLoaderHash classLoaderHash 19469ea2复制代码classLoaderHash 是19469ea2,前面需要使用它。mc保存好/tmp/UserController.java之后,使用mc(Memory Compiler)命令来编译,并且通过-c或者--classLoaderClass参数指定ClassLoader: ...

August 16, 2022 · 2 min · jiezi

关于next.js:NextjsReactNode系统实战搞定SSR服务器渲染

Next.js+React+Node零碎实战,搞定SSR服务器渲染百度网盘链接Java 基础常见学识点&面试题总结面向对象基础面向对象和面向过程的区别两者的次要区别在于解决问题的形式不同: 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。面向对象会先抽象出对象,而后用对象执行方法的形式解决问题。 另外,面向对象开发的程序一般更易保护、易复用、易扩大。相干 issue : 面向过程 :面向过程性能比面向对象高??成员变量与局部变量的区别 语法形式 :从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可能被 public,private,static 等修饰符所润饰,而局部变量不能被访问控制修饰符及 static 所润饰;然而,成员变量和局部变量都能被 final 所润饰。存储形式 :从变量在内存中的存储形式来看,如果成员变量是使用 static 润饰的,那么这个成员变量是属于类的,如果没有使用 static 润饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。生存工夫 :从变量在内存中的生存工夫上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而主动生成,随着方法的调用结束而沦亡。默认值 :从变量是否有默认值来看,成员变量如果没有被赋初始值,则会主动以类型的默认值而赋值(一种情况例外:被 final 润饰的成员变量也必须显式地赋值),而局部变量则不会主动赋值。 创建一个对象用什么运算符?对象实体与对象引用有何不同?new 运算符,new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可能指向 0 个或 1 个对象(一根绳子可能不系气球,也可能系一个气球);一个对象可能有 n 个引用指向它(可能用 n 条绳子系住一个气球)。对象的相等和引用相等的区别 对象的相等一般比较的是内存中存放的内容是否相等。引用相等一般比较的是他们指向的内存地址是否相等。 类的构造方法的作用是什么?构造方法是一种非凡的方法,次要作用是实现对象的初始化工作。如果一个类没有申明构造方法,该程序能正确执行吗?如果一个类没有申明构造方法,也可能执行!因为一个类即使没有申明构造方法也会有默认的不带参数的构造方法。如果咱们自己增加了类的构造方法(无论是否有参),Java 就不会再增加默认的无参数的构造方法了,咱们一直在人不知;鬼不觉地使用构造方法,这也是为什么咱们在创建对象的时候前面要加一个括号(因为要调用无参的构造方法)。如果咱们重载了有参的构造方法,记得都要把无参的构造方法也写进去(无论是否用到),因为这可能帮助咱们在创建对象的时候少踩坑。构造方法有哪些个性?是否可被 override?构造方法个性如下: 名字与类名雷同。没有返回值,但不能用 void 申明结构函数。生成类的对象时主动执行,无需调用。 构造方法不能被 override(重写),然而可能 overload(重载),所以你可能看到一个类中有多个结构函数的情况。面向对象三大特色封装封装是指把一个对象的状态信息(也就是属性)躲藏在对象外部,不容许内部对象间接拜访对象的外部信息。然而可能提供一些可能被外界拜访的方法来操作属性。就好像咱们看不到挂在墙上的空调的外部的整机信息(也就是属性),然而可能通过遥控器(方法)来管制空调。如果属性不想被外界拜访,咱们大可不必提供方法给外界拜访。然而如果一个类没有提供应外界拜访的方法,那么这个类也没有什么意义了。就好像如果没有空调遥控器,那么咱们就无奈操控空凋制冷,空调本身就没有意义了(当然现在还有很多其余方法 ,这里只是为了举例子)。public class Student { private int id;//id属性私有化private String name;//name属性私有化//获取id的方法public int getId() { return id;}//设置id的方法public void setId(int id) { this.id = id;}//获取name的方法public String getName() { return name;}//设置name的方法public void setName(String name) { this.name = name;}}复制代码继承不同类型的对象,相互之间常常有肯定数量的共同点。例如,小明同学、小红同学、小李同学,都共享学生的个性(班级、学号等)。同时,每一个对象还定义了额定的个性使得他们不同凡响。例如小明的数学比较好,小红的性情惹人喜爱;小李的力量比较大。继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可能减少新的数据或新的功能,也可能用父类的功能,但不能选择性地继承父类。通过使用继承,可能疾速地创建新的类,可能提高代码的重用,程序的可维护性,俭约大量创建新类的工夫 ,提高咱们的开发效率。对于继承如下 3 点请记住: ...

June 15, 2022 · 2 min · jiezi

关于next.js:NextjsReactNode系统实战搞定SSR服务器渲染

Next.js+React+Node零碎实战,搞定SSR服务器渲染超清原画 残缺无密 获取ZY:网盘链接hashCode() 和 equals()的区别equals()equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同。 在万物皆对象的 Java 体系中,零碎把判断对象是否相等的权力交给程序员。具体的措施是把 equals() 方法写到 Object 类中,并让所有类继承 Object 类。 这样程序员就能在自定义的类中重写 equals() 方法, 从而实现自己的比较逻辑。 hashCode()hashCode() 的意义是哈希值, 哈希值是经哈希函数运算后失去的后果,哈希函数能够保障雷同的输出能够失去雷同的输入(哈希值),然而不能够保障不同的输出总是能得出不同的输入。 当输出的样本量足够大时,是会产生哈希冲突的,也就是说不同的输出产生了雷同的输入。 暂且不谈冲突,就雷同的输出能够产生雷同的输入这点而言,是及其宝贵的。它使得零碎只需要通过简略的运算,在工夫复杂度O(1)的情况下就能得出数据的映射关系,根据这种个性,散列表应运而生。 一种支流的散列表实现是:用数组作为哈希函数的输入域,输出值通过哈希函数计算后失去哈希值。而后根据哈希值,在数组种找到对应的存储单元。当发生冲突时,对应的存储单元以链表的形式保存冲突的数据。 两者关系在大多数编程实践中,归根结底会落实到数据的存取问题上。 在汇编语言期间,你需要老诚恳实地对每个数据操作编写存取语句。 而随着期间发展到明天,咱们都用更便利灵活的高级语言编写代码,比如 Java。 Java 以面向对象为中心思想,封装了一系列操作数据的 api,升高了数据操作的复杂度。 但在咱们对数据进行操作之前,首先要把数据按照肯定的数据结构保存到存储单元中,否则操作数据将无从谈起。 然而不同的数据结构有各自的个性,咱们在存储数据的时候需要抉择合适的数据结构进行存储。 Java 根据不同的数据结构提供了丰富的容器类,便利程序员抉择适合业务的容器类进行开发。 通过继承关系图咱们看到 Java 的容器类被分为 Collection 和 Map 两大类,Collection 又可能进一步分为 List 和 Set。 其中 Map 和 Set 都是不容许元素重复的,严格来说Map存储的是键值对,它不容许重复的键值。 值得注意的是:Map 和 Set 的绝大多数实现类的底层都会用到散列表结构。 讲到这里咱们提取两个关键字不容许重复和散列表结构, 回顾 hashCode() 和 equals() 的个性,你是否想到了些什么货色呢?equals()力不从心下面提到 Set 和 Map 不存放重复的元素(key),这些容器在存储元素的时必须对元素做出判断:在以后的容器中有没有和新元素雷同的元素? 你可能会想:这容易呀,间接调用元素对象的 equals() 方法进行比较不就行了吗? ...

May 1, 2022 · 1 min · jiezi

关于next.js:NextjsReactNode系统实战搞定SSR服务器渲染MKW

download:Next.js+React+Node零碎实战,搞定SSR服务器渲染 复制下哉课程ZY:https://www.97yrbl.com/t-1391.html @Componentpublic class RedisUtil { public static RedisUtil util; public RedisUtil(@Autowired JedisPool jedisPool) { this.jedisPool = jedisPool; RedisUtil.util = this; } public static RedisUtil getInstance(){ return util; } @Autowired private JedisPool jedisPool; /** * 向Redis中存值,永恒无效 */ public String set(String key, String value) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.set(key, value); } catch (Exception e) { return "0"; } finally { jedis.close(); } } /** * 依据传入Key获取指定Value */ public String get(String key) { Jedis jedis = null; String value; try { jedis = jedisPool.getResource(); value = jedis.get(key); } catch (Exception e) { return "0"; } finally { jedis.close(); } return value; } /** * 校验Key值是否存在 */ public Boolean exists(String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.exists(key); } catch (Exception e) { return false; } finally { jedis.close(); } } /** * 删除指定Key-Value */ public Long del(String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.del(key); } catch (Exception e) { return 0L; } finally { jedis.close(); } } /** * 分布式锁 * @param key * @param value * @param time 锁的超时工夫,单位:秒 * * @return 获取锁胜利返回"OK",失败返回null */ public String getDistributedLock(String key,String value,int time){ Jedis jedis = null; String ret = ""; try { jedis = jedisPool.getResource(); ret = jedis.set(key, value, new SetParams().nx().ex(time)); return ret; } catch (Exception e) { return null; } finally { jedis.close(); } } public void pub(){ jedisPool.getResource().publish("test","msg"); } }

April 16, 2022 · 2 min · jiezi

关于next.js:使用-NextjsLeanCloud-和-Tailwind-CSS-创建全栈应用

理解如何应用 LeanCloud 创立数据库并应用 Next.js 创立带有服务端的应用程序。前言通过本教程您将理解到: 应用 LeanCloud 作为收费数据库应用 Next.js 开发一个蕴含前后端的利用将利用公布到 Vercel应用 Tailwind 轻松设置款式咱们将创立一个用于影视剧打分利用,我将它部署在 rec.zehao.me,残缺源码我放在 2eha0/records 创立 Next.js 利用应用 Next.js 官网模板创立我的项目 & npx create-next-app --example with-tailwindcss my-app该指标曾经为您配置好以下内容: Next.js 最新版本TypeScriptTailwind CSS & 主动去除未应用的类名Next.js API 路由示例创立前端组件当初咱们能够开始创立组件了,pages/index.tsx 是利用的入口文件,咱们先来批改整体布局 // pages/index.tsximport type { NextPage } from 'next'import Head from 'next/head'const Home: NextPage = () => { return ( <div className='mx-[3.5rem] min-w-[15rem] max-w-full sm:mx-auto sm:w-[30rem] font-sans'> <Head> <title>我看过的</title> <meta name="viewport" content="width=device-width" /> <link rel="icon" href="/favicon.ico" /> </Head> <h1 className='text-slate-300 flex justify-between items-center text-xl sm:text-5xl my-8 sm:my-20'> <span>我看过的</span> <span className='text-xs sm:text-xl'>电影 / 动漫 / 剧 / 书</span> </h1> </div> )}export default Home接下来,咱们须要为利用增加一个卡片组件,用于显示影视作品的信息,新建 components/card.tsx 文件 ...

April 4, 2022 · 5 min · jiezi

关于next.js:Nextjs页面之间跳转添加loading-bar功能

前言next.js框架是支流的SSR框架,弱小的开箱即用加上社区十分沉闷让它可能在泛滥框架中怀才不遇。最近为了实现next.js页面之间来回跳转加上loading成果晋升用户体验写下这篇文章,心愿可能帮忙到大家。 操作首先,咱们来剖析一下实现原理,首先路由之间跳转启动与完结要有监听事件,用到的就是next.js的router监听事件 有了监听事件咱们就可能很好的管制页面之间的跳转。 接着咱们须要一个loading bar置顶到页面最下面,这里咱们会用到@tanem/react-nprogress这个插件。 yarn add @tanem/react-nprogress 接着,咱们关上这个地址,复制外面的代码到咱们的我的项目中。 1、新建globalLoading.js import React from 'react';import { useNProgress } from '@tanem/react-nprogress';const GlobalLoading = ({ isRouteChanging, }) => { const { animationDuration, isFinished, progress } = useNProgress({ isAnimating: isRouteChanging, }) return ( <> <style jsx>{` .container { opacity: ${isFinished ? 0 : 1}; pointerevents: none; transition: opacity ${animationDuration}ms linear; } .bar { background: #29d; height: 2px; left: 0; margin-left: ${(-1 + progress) * 100}%; position: fixed; top: 0; transition: margin-left ${animationDuration}ms linear; width: 100%; z-index: 1031; } .spinner { box-shadow: 0 0 10px #29d, 0 0 5px #29d; display: block; height: 100%; opacity: 1; position: absolute; right: 0; transform: rotate(3deg) translate(0px, -4px); width: 100px; } `}</style> <div className="container"> <div className="bar"> <div className="spinner" /> </div> </div> </> )};export default GlobalLoading;2、批改_app.js ...

December 25, 2021 · 2 min · jiezi

关于next.js:Nextjs-云开发Webify-打造绝佳网站

Next.js酷在哪里?之前应用 Next.js + strapi 做了一个简略博客站点也顺道写了一篇 Next.js 扼要教程,之后 Next 自身始终在迅猛发展。利用代 js 能力来说做到了: 极佳的开发体验极佳的网站最佳的”动“,“静”均衡从个性上来说,反对: SSR(Server Side Rendering)提供 getServerSideProps 办法,在用户拜访时申请数据,实用于实时数据页面。SSG(Static Site Generation)提供 getStaticProps,getStaticPaths 办法来事后生产动态页面;而更酷的一点是:应用 fallback,revalidate 来反对肯定的动态性。 这种能“动”的 SSG 天然是我所须要的,放弃动态拜访,而又能在我新增修改文章的时候,站点可能自动更新。绝佳!! 为什么还须要来Webify“折腾”一番?既然下面曾经很酷了,为什么会有明天的文章,为什么还须要折腾一番? 起因也很简略:老本略高,为了不错的访问速度,你须要一台性能不错的虚拟机,肯定的带宽。对于个别集体博客,投入不划算。 在这里就隆重地有请咱们的解决方案:腾讯云开发Webify,简略来说就是相似 vercel 的 Serverless 托管服务,不过反对更多的框架,而且是国内服务商,便宜且访问速度一流。 有图为证: 而且当初托管,能收费领300元无门槛代金券,香啊~感兴趣的能够点击下方链接理解一下:https://cloud.tencent.com/developer/article/1871549 CloudBase Webify实战对于个别文章应用相似 github 治理的就简略了,Webify反对版本 Github、Gitlab、Gitee 服务商,据说行将反对 Coding: Vue.js (vue-cli)React.js (create-react-app)HexoGatsby.jsAngularNext.js SSGNuxt.js SSG以及主动适配框架以本博客 next 为例,Webify实际上应用时了 next export 的能力,构建后,间接部署动态文件到 server。 如果你的博客文章,间接应用 md,git 治理,看到这里就OK了,git 提交,Webify主动会重新部署你的站点。cool~~ 问题是如果你的站点数据来源于相似 strapi 这种 serverless cms 怎么办?next export 不反对next SSG中“动”的个性(fallback,revalidate)。 Webify高阶——自动化Webify其实办法也很简略,加一个桥接服务,让你的 serverless cms 的更新变动到 git 就好。 ...

September 10, 2021 · 1 min · jiezi

关于next.js:nextjs动态路由Dynamic-Routes

const detail = () => { // pages/news/[id].jsx // next只反对query不反对params,as参数是为了好看 router.push({ pathname:'/news', query:{ id: 1 }, }, '/news/1')

September 2, 2021 · 1 min · jiezi

关于next.js:Nextjs-集成状态管理器和Cookie

前言最近我的项目中应用SSR框架next.js,过程中会遇到token存储,状态治理等一系列问题,当初总结并记录下来分享给大家。 Token存储SSR和SPA最大的区别就是SSR会辨别客户端Client和服务端Server,并且SSR之间只能通过cookie能力在Client和Server之间通信,例如:token信息,以往咱们在SPA我的项目中是应用localStorage或者sessionStorage来存储,然而在SSR我的项目中Server端是拿不到的,因为它是浏览器的属性,要想客户端和服务端同时都能拿到咱们能够应用Cookie,所以token信息只能存储到Cookie中。 那么咱们选用什么插件来设置和读取Cookie信息呢?插件也有好多种,比方:cookie、js-cookie、react-cookie、nookie、set-cookie-parser等等,然而它们有个最大的问题就是须要手动去管制读取和设置,有没有一种插件或者中间件主动获取和设置token呢?答案是必定的,就是接下来咱们要用到的next-redux-cookie-wrapper这个插件,它是next-redux-wrapper插件举荐的,而next-redux-wrapper插件是连贯redux中store数据的插件,接下来会讲到。 数据长久化SSR我的项目咱们不倡议数据做长久化,除了下面的token以及用户名等数据量小的数据须要长久化外,其它的都应该从后盾接口返回,否则就失去了应用SSR的目标(间接从服务端返回带有数据的html)了,还不如去应用SPA来得间接。 状态治理如果你的我的项目不是很大,且组件不是很多,你齐全不必思考状态治理,只有当组件数量很多且数据一直变动的状况下你须要思考状态治理。 咱们晓得Next.js也是基于React,所以基于React的状态管理器同样实用于Next.js,比拟风行的状态治理有: mobxreduxredux-toolkit(redux的简化版)recoil(react官网出品)rematch(模块化做得比拟好的)这里有一篇文章专门介绍比照它们的,大家能够看看哪种比拟适宜本人。 最初咱们选用的是redux的轻量级版本:redux-toolkit。 上面咱们会集成redux-toolkit插件及共享cookie插件next-redux-cookie-wrapper以及连贯next.js服务端与redux store数据通信办法getServerSideProps的插件next-redux-wrapper。 集成状态管理器Redux及共享Token信息首先咱们先创立next.js我的项目,创立完之后,咱们执行上面几个步骤来一步步实现集成。 创立store/axios.js文件批改pages/_app.js文件创立store/index.js文件创立store/slice/auth.js文件0. 创立store/axios.js文件创立axios.js文件目标是为了对立治理axios,不便slice中axios的设置和获取。 store/axios.js import axios from 'axios';import createAuthRefreshInterceptor from 'axios-auth-refresh';import * as cookie from 'cookie';import * as setCookie from 'set-cookie-parser';// Create axios instance.const axiosInstance = axios.create({ baseURL: `${process.env.NEXT_PUBLIC_API_HOST}`, withCredentials: false,});export default axiosInstance;1、批改pages/_app.js文件应用next-redux-wrapper插件将redux store数据注入到next.js。 pages/_app.js import {Provider} from 'react-redux'import {store, wrapper} from '@/store'const MyApp = ({Component, pageProps}) => { return <Component {...pageProps} />}export default wrapper.withRedux(MyApp)2、创立store/index.js文件应用@reduxjs/toolkit集成reducer并创立store,应用next-redux-wrapper连贯next.js和redux,应用next-redux-cookie-wrapper注册要共享到cookie的slice信息。store/index.js import {configureStore, combineReducers} from '@reduxjs/toolkit';import {createWrapper} from 'next-redux-wrapper';import {nextReduxCookieMiddleware, wrapMakeStore} from "next-redux-cookie-wrapper";import {authSlice} from './slices/auth';import logger from "redux-logger";const combinedReducers = combineReducers({ [authSlice.name]: authSlice.reducer});export const store = wrapMakeStore(() => configureStore({ reducer: combinedReducers, middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend( nextReduxCookieMiddleware({ // 在这里设置你想在客户端和服务器端共享的cookie数据,我设置了上面三个数据,大家按照本人的需要来设置就好 subtrees: ["auth.accessToken", "auth.isLogin", "auth.me"], }) ).concat(logger)}));const makeStore = () => store;export const wrapper = createWrapper(store, {storeKey: 'key', debug: true});创立store/slice/auth.js文件创立slice,通过axios调用后盾接口返回token和user信息并保留到reducer数据中,下面的nextReduxCookieMiddleware会主动设置和读取这里的token和me及isLogin信息。 ...

August 31, 2021 · 4 min · jiezi

关于next.js:Github-访问量统计

基于 Firebase 数据库和 Next.js 框架的 GitHub Profile 的访问量统计图标. 操作指南第一步: ForkFork 以后我的项目. 第二步: 配置 Firebase注册您集体的 Firebase 账户: 点击 开始 并 增加我的项目.创立实时数据库并抉择 测试模式.数据库的构造应如下图所示: 请将规定都改成 true: 第三步: 部署在 Vercel用您的 Github 账号登入到 Vercel.抉择方才 fork 的我的项目.找到 设置, 增加 环境变量, 名称 输出为 FIRE_BASE_URL 并输出第二步中创立的 Firebase 数据库链接: 最初, 您能够抉择最新推上去的 commit 并重新部署, 不出所料的话所有都会顺利. 第四步: 更新 Github Profile只需在 README.md 中插入下方的代码: ![](https://{您本人的 vercel 域名}/api/counter)参考我的项目当初 GitHub 有很多优良的访问量统计的开源我的项目,我筛选其中两个我最喜爱的我的项目供大家学习参考: Tool from antonkomarev - 这是我过来几个月最长应用的我的项目,然而最近可能用户增多了,延时很高遂弃.Tool from Ryan Lanciaux - 极客 UI, 如果想本人部署在 Glitch 上的话要留神服务器会进入睡眠的问题.共享源码在 GitHub, 喜爱的加个星~ 欢送任何 issue 和 PR! ...

June 19, 2021 · 1 min · jiezi

关于next.js:致力于带给开发者最佳体验Nextjs-11-版本发布

昨晚 next.js.cons 召开 ,会议公布了 next.js 11 版本以及 next.js Live,来看看重要内容! 新个性:Conformance:提供精心制作的解决方案以反对用户最佳体验的零碎。性能改良:进一步优化以改善冷启动工夫,以便您能够更快地开始编码。next/script:主动优先加载第三方脚本以进步性能。next/image:缩小布局移位,通过主动尺寸检测和反对含糊占位符发明更晦涩的视觉体验。Webpack 5:当初默认为所有 Next.js 应用程序启用,这能够为所有 Next.js 开发人员带来这些益处。创立反馈应用程序迁徙(试验):主动转换创立反馈应用程序以兼容 Next.js。Next.js Live(预览版):与您的团队实时在浏览器中编写代码。通过运行并参考上面的迁徙指南立刻更新。 https://nextjs.org/blog/next-... npm i next@latest react@latest react-dom@latest Conformance即便有弱小的工具和框架中的主动优化,网站所有者和应用程序开发人员也常常被要求成为 UX 品质主题的专家,例如性能、安全性和可拜访性。随着性能的增加和团队的扩大,开发人员须要以不同的形式思考。 通过他们致力于构建大型 Web 应用程序(如搜寻和地图),Google 曾经证实,随着团队和应用程序的扩大,框架能够在放弃品质方面施展关键作用。通过利用弱小的默认和爱护零碎,它们使开发人员可能更多地关注性能和产品。 明天,Google 的网络平台团队曾经开始应用 Conformance for Next.js 来开源他们的零碎。 Conformance 是一个零碎,它提供精心设计的解决方案和规定以反对最佳加载和 Core Web Vitals,并进一步增加反对其余品质方面,如安全性和可拜访性。这些解决方案使您的团队无需记住所有最新规定以获得最佳加载性能,同时依然让您可能灵便地为您的应用程序做出正确的抉择。 除了由性能钻研反对的许多根底优化外,Next.js 11 当初开箱即用地反对 ESLint,以便在开发过程中更轻松地捕捉特定于框架的问题,并为您的团队设置指导方针,以确保即便在扩大时也能获得最佳实际。 要开始应用 ESLint,请在降级到 Next.js 11 后运行。ESLint 集成实用于新的和现有的 Next.js 应用程序,提供一组新规定来帮忙开发人员构建更好的应用程序。 npx next lint $ npx next lintWe created the .eslintrc file for you and included the base Next.js ESLint configuration../pages/about.js7:9  Warning: Do not include stylesheets manually. See: https://nextjs.org/docs/messages/no-css-tags.  @next/next/no-css-tags10:7  Warning: External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts.  @next/next/no-sync-scripts./pages/index.js4:10  Warning: Do not use the HTML <a> tag to navigate to /about/. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages.  @next/next/no-html-link-for-pagesNeed to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules✨  Done in 1.94s.性能优化从 Next.js 10 开始,咱们始终专一于改善 Next.js 的开发者体验。在 10.1 和 10.2 中,咱们将启动工夫缩短了 24%,并通过 React Fast Refresh 将更改的解决工夫再缩小了 40%。仅仅通过放弃 Next.js 更新,您就曾经取得了这些惊人的速度改良。 ...

June 16, 2021 · 1 min · jiezi

关于next.js:Nextjs

NextjsNextjs是什么?Nextjs长处Nextjs详解basic featurespages每个页面是和路由相干的,路由又是基于文件名称的Nextjs为每个页面提前生成html,而不是全副由客户端javaScript生成,预渲染会使页面性能和SEO更好两种模式的预渲染:动态生成和服务端渲染 动态渲染:在构建阶段生成html并且在每个申请中复用服务端渲染:每次申请中生成html出于性能思考,咱们倡议应用动态生成而不是服务器端出现。动态生成的页面能够被CDN缓存,不须要额定的配置来进步性能 RoutingDynamic RoutesCatch all routesnext/link or next/routershallow routing在扭转路由时不运行获取数据的形式,比方 getServerSideProps, getStaticProps, and getInitialProps.

March 31, 2021 · 1 min · jiezi

关于next.js:Nextjs梳理

NextjsNextjs v10内置Image组件实现主动图片优化性能<img src="/profile-picture.jpg" width="400" height="400" alt="Profile Picture">import Image from 'next/image'<Image src="/profile-picture.jpg" width="400" height="400" alt="Profile Picture">实现懒加载 在看到图片时再渲染图片尺寸固定,防止渲染时布局发生变化从新渲染界面图片自适应安装属性属性名必填作用备注src是图片起源 width是图片宽度layout="fill" 可不填height是图片高度layout="fill" 可不填layout否当视口扭转大小时,图像的布局行为属性值见下方loader否用于解析url的自定义函数()=>stringsizes否图片大小layout="responsive" or layout="fill"quality否优化图片1-100 默认75priority否优先级预渲染的优先级较高layout属性值 fixed:图片固定 不会因为视口的扭转而扭转图片的大小intrinsic:视图窗口较小时放大图片 但不会放大图片responsive:随着视图窗口的变动而自适应fill:将图片拉伸到父元素尺寸国际化路由依据路由来判断翻译成哪种语言 Subpath routing(/nl-nl/blog and /en/blog) // next.config.js module.exports = { i18n: { locales: ['en', 'nl'], defaultLocale: 'en' } }Domain routing(example.nlandexample.com) // next.config.jsmodule.exports = { i18n: { locales: ['en', 'nl'], domains: [ { domain: 'example.com', defaultLocale: 'en' }, { domain: 'example.nl', defaultLocale: 'nl' } ] }}禁止国际化映射// next.config.jsmodule.exports = { i18n: { localeDetection: false, },}Next.js Analytics掂量用户理论性能并加以调整 ...

March 10, 2021 · 2 min · jiezi

关于next.js:NextJSAliplayer阿里云播放器在NextJS的实现

阿里云播放器阐明文档 思考在目前的阿里云播放器中,没有提供相干的npm包,所以对开发来说非常不敌对。在明天的开发过程中接触到了NextJS,因为我的项目须要所以进行了NextJS的阿里云播放器接入,以下是过程记录。 因为NextJS不能获取到window和document,故勾销用createElement异步创立引入脚本和款式。运行步骤组件引入 {this.state.showPlayer&&<Apliplayer config={playerConfig} onGetInstance={instance => console.log('player ', instance)}></Aliplayer>}应用state对播放器进行显示是因为播放器在文件没有配置残缺的状况下先单独实现渲染,导致无奈获取到配置文件,所以须要再配置实现时再将播放器进行展现 相干文件 components/aliplayer/index.js //播放器外围文件pages/player.js //组件调用页面实现形式一、创立相干代码 index.js //组件代码import React, {Component} from 'react'class Aliplayer extends Component { state = { id: null, config: null, onGetInstance: null, } componentWillMount() { const id = `aliplayer-${Math.floor(Math.random() * 1000000)}`; this.setState({id}) } componentDidMount() { let {config, onGetInstance} = this.props if (!config) { throw new Error('Missing Aliplayer config'); } const player = this.player const {id} = this.state if (!id || player.current) { return } const Aliplayer = window.Aliplayer; if (player.current) { return } player.current = new Aliplayer({ ...config, "id": id, }, (player) => { onGetInstance && onGetInstance(player); }); } render() { const {id} = this.state return (<div ref={ref => this.player = ref} id={id}></div>) }}export default Aliplayerplayer.js此次将资源文件通过援用该组件的Head插入,因为在组件引入资源文件时会产生申请不到 new Aliplayer()。如果调用的页面比拟多,能够放在母版页进行引入, ...

January 4, 2021 · 2 min · jiezi

关于next.js:基于NextjsReact仿微信桌面端nextjs聊天室

我的项目介绍Next.js一款比拟热门的React服务器端渲染框架。让你的网页领有SEO能力。Next-Webchat基于next+react+redux+antd+rlayer等技术实现的仿微信PC网页端聊天我的项目。实现了音讯表情混合发送、图片/视频预览、拖拽/粘贴截图发送、红包/朋友圈等性能。 技术框架技术架构:next.js+react+RreduxUI组件库:Antd (蚂蚁金服react组件库)字体图标:阿里iconfont图标库弹窗组件:RLayer(react.js自定义对话框)虚构滚动:RScroll(react.js自定义滚动条)成果预览 如果想让你的网页也能领有SEO性能,那么Next.js是一个不错的抉择。只有会React,上手就很容易了。https://www.nextjs.cn/https://github.com/vercel/nex... Next|React自定义弹窗组件我的项目中用到的所有弹窗均是本人开发的RLayer组件。RLayer 基于react.js开发的PC端自定义弹框组件。反对超过30+参数自在配置,通过笨重的布局设计、极简的调用形式来解决简单的弹出层性能,为您呈上不一样的弹窗成果。感兴趣的话,能够去看看之前的这篇分享文章。https://segmentfault.com/a/11... Next|React自定义滚动条组件我的项目中用到的滚动条也是本人开发的一款PC桌面端虚构丑化滚动条组件RScroll。Rscroll.js反对原生滚动条、是否自动隐藏、滚动条大小/层级/色彩等性能。 Next公共模板新建layouts/index.js文件用于页面主入口模板。 function Layout(props) { const router = useRouter() // 拦挡验证 useEffect(() => { // ... }, []) return ( <> {/* 配置公共head信息 */} <Head> <title>Next.js聊天室</title> <link rel="icon" href="/favicon.ico" /> <meta name="keywords" content="Next.js|React.js|Next.js聊天室|Next.js仿微信|React聊天实例"></meta> <meta name="description" content="Next-WebChat 基于Next.js+React+Redux构建的服务端渲染聊天应用程序"></meta> </Head> <div className="next__container flexbox flex-alignc flex-justifyc"> <div className={utils.classNames('next__wrapper')} style={{ backgroundImage: `url(${props.skin})` }}> <div className="next__board flexbox"> {/* 右上角按钮 */} <WinBar {...props} /> {/* 侧边栏 */} <Sidebar {...props} /> {/* 两头栏 */} <Middle /> {/* 主体布局 */} <div className="nt__mainbox flex1 flexbox flex-col"> {props.children} </div> </div> </div> </div> </> )}Head组件用于配置一些页面SEO信息,如:title、keyword、description及图标icon等信息。 ...

December 28, 2020 · 3 min · jiezi

关于next.js:nextjs-根据生产环境和测试环境打不同的包

dev环境和test环境以及pro环境的接口不一样,因为上线之前毕竟是须要测试的。这就须要咱们来打不同的包来便于测试。在nextjs中,只须要简略的配置就能够实现咱们须要的工作,我之前做的时候是依据官网文档写的建设 .env.development , .env.production以及 .env.test,然而打test包之后总是报一个有限循环的bug,试了很久也没解决,如果有相熟的小伙伴欢送留言探讨。 目前我用的是另一个办法。 咱们建设好nextjs框架之后,找到package.json这个文件,批改其中的 "scripts": { "dev": "NEXT_PUBLIC_DOMAIN_ENV=development next dev", "build": "NEXT_PUBLIC_DOMAIN_ENV=production next build && next export", "start": "next start", "test":"NEXT_PUBLIC_DOMAIN_ENV=test next build && next export" }其中 next build && next export 是打包动态文件到cdn用的。次要是后面加了 NEXT_PUBLIC_DOMAIN_ENV=test 至关重要。而后我在根目录加了个config文件夹,新建servicePath当做接口地址文件,相熟react和vue框架的同学应该对这个很相熟了,axios获取接口的时候用这个很不便(当然文件夹跟文件名称并不是固定的,小伙伴们能够依据本人的须要来取),以下附上我的servicePath.js的内容 let ipUrl = null; //接口if(process.env.NEXT_PUBLIC_DOMAIN_ENV==="production"){ //生产环境接口地址 ipUrl="http://127.0.0.1:7001"}else { //开发以及测试环境接口地址(我这里开发环境和测试环境是一样的接口) ipUrl="http://128.0.0.1:7005"}let servicePath = { getArticleList: ipUrl + "/getArticleList", //首页接口};export default servicePath;而后在你的页面里引入import servicePath from '../config/servicePath' 剩下的应用就不跟大家过多介绍啦。 最初npm run build 就是生产环境打包,npm run test 就是测试环境打包。 ...

November 25, 2020 · 1 min · jiezi

关于next.js:cssvarsponyfill-在ie环境下使用问题nextjs-构建

css-vars-ponyfill通过css变量来实现网页换肤的过程中,会呈现兼容性问题。 为了解决ie,qq,百度浏览器等兼容性问题,引入css-vars-ponyfill,然而在ie浏览器下,css-vars-ponyfill 的在nextjs下体现不佳,次要缺点是因为页面是服务端渲染,因而用户在看到界面后,动静主题色等款式不能很快渲染好,而是有一个过渡的工夫(css-vars-ponyfill 仅反对client-side),色彩会存在显著替换的过程用户体验差。通过浏览源码能够看到,cssVars须要等到浏览器contentLoaded之后,才会触发,否则始终监听dom的data content事件,这就导致了体验上的问题。 解决方案1.解析速度通过把间接去除document.readyState !== 'loading' 这样的限度条件使得浏览器在解析到,而后更改css-vars-ponyfill 的引入形式(旧的引入形式是在nextjs中的mainjs中引入module,而后间接调用cssVars(),这样在调用到ponyfill的脚本前还会解析其余不相干的chunk,为了更快的解析css变量,须要手动抉择插入地位),更改之后的css-vars-ponyfill 通过找到css变量的地位(nextjs 通过将不同组件下的style,对立打包在header外面),而后将更改后的ponyfill 插入到style 之后进行调用,这一步抉择在服务端渲染的 _document.tsx 文件中更改。 2.解析稳定性通过手动更改文件解析地位,以及对源码的条件触发机制进行相干更改,首页色彩渲染速度有了肯定晋升。然而仍存在一个问题,即通过路由跳转的界面,如果有新的style chunk,插入时不能进行无效的css变量解析(已尝试配置cssVars的option 关上MutationObserver)。因而,解决方案是通过判断UA,来让ie等浏览器下所有的路由通过a标签跳转,触发css-ponyfill的从新解析执行。 export function browser() { const UA = window.navigator.userAgent if (UA.includes("qqbrowser")) return "qqbrowser" if (UA.includes("baidu")) return "baidu" if (UA.includes("Opera")) return "Opera" if (UA.includes("Edge")) return "Edge" if (UA.includes("MSIE") || (UA.includes("Trident") && UA.includes("rv:11.0"))) return "IE" if (UA.includes("Firefox")) return "Firefox" if (UA.includes("Chrome")) return "Chrome" if (UA.includes("Safari")) return "Safari"}type CommonLinkProps = { children: ReactElement href?: string target?: string outerLink?: boolean styles?: unknown}export default function CustomLink(props: CommonLinkProps) { const { children, href, target, as, outerLink, styles = emptyStyles } = props const [isIE, setIE] = useState<boolean>(false) const cloneEl = (c: ReactElement, props?: any) => React.cloneElement(c, { href: as ?? href, target, ...props }) useEffect(() => { if (["IE", "qqbrowser", "baidu"].includes(browser())) { setIE(true) } }, []) function renderLink() { if (Children.only(children).type === "a") { const node = cloneEl(children as ReactElement) return node } else { let fn: () => void | null = null if (outerLink) { fn = () => { window.open(as ?? href) } } else { fn = () => { window.location.href = as ?? href } } const node = cloneEl(children as ReactElement, { onClick: () => { fn() }, }) return node } } return ( <> {!href ? ( children ) : isIE ? ( renderLink() ) : ( <Link {...props}>{children}</Link> )} <style jsx>{styles}</style> </> )}这里children的type 抉择了ReactElement,而不是插槽中通常反对的ReactNode 次要是不想思考直接插入字符串这种状况,会减少问题的复杂度,因而间接在type这层做限度。还有Fragments 也没有思考,且没有找到无效的Fragments 类型,没法在ReactNode 中把它Omit掉,nextjs 外面的Link 如果首层插入了Fragments 后,也无奈失常跳转,可能起因也是无奈再Fragments 下面绑定无效的事件吧,目前Fragments(16.13.1) 只反对key属性,心愿后续能够优化。 ...

August 16, 2020 · 2 min · jiezi

Next引入Antd和Sass

这里并不是Next引入Antd或者Sass教程!!这篇文章讲的是如何在next里同时引入sass和antd 问题起源我想在Next里引入Antd框架,跟着网上教程将antd引入到框架中后,我又想引入scss但这时候就报错了。因为next本身支持解析css,网上的文档和教程包括官方文档都是@next/css,或者@next/sass两个插件引用其一来达到支持css和scss的效果。像这样: // scssconst withSass = require('@zeit/next-sass')module.exports = withSass({})//cssconst withCSS = require('@zeit/next-css')module.exports = withCSS({ /* config options here */})但是两个插件只能取其一,如果你引入过antd就知道,想使用antd需要在全局import 'antd/dist/antd.css',而引入了这个css文件那么就需要用上next-css插件,用了这个插件我们就用不了next-scss,这就是问题的所在了。 解决办法在这里就不具体写怎么在next里单独引入antd或者scss了,因为网上的其它教程和官方文档已经跟详细了我在这里假设你已经会单独引用antd和scss了。next官方有一个插件能实现我们的需求 :* next-compose-plugins他能让我们同时引用多个插件 npm install --save next-compose-pluginsnext.config.js改成这样 // next.config.jsconst withSass = require('@zeit/next-sass')const withCss = require('@zeit/next-css');const withPlugins = require("next-compose-plugins");module.exports = withPlugins([withSass,withCss], { webpack: (config) => { return config },});_app.js文件不变 import App from 'next/app'import 'antd/dist/antd.css'export default App然后我在public/assets/css下新建了一个test.scss这个文件有简单的css样式 .test{ color: red;}pages/index.js将其引入 import { Button } from 'antd';import '../public/assets/css/test.scss'...一些代码...<Button>测试按钮</Button> //antd按钮组件<h1 className="title test">Welcome to Next.js!</h1> //test.scss文件测试最后看看效果:antd的按钮样式有了,test.scss的标题变红样式也有了。完工! ...

October 18, 2019 · 1 min · jiezi

魅族官网基于-nextjs-重构实践总结与分享

项目背景俗话说,脱离业务谈代码的都是耍流氓。在此我先简单介绍下重构项目的背景。 截图镇楼:魅族官网首页 在 2015 年,公司前端大佬猫哥基于 FIS3 深度定制开发了一套前端工程体系 mz-fis,该框架经历3年来的网站改版升级需求,都很好的完成了需求任务。 但随着项目越来越大,以及前端技术快速迭代。老项目的痛点越发明显。 此次重构解决了那些痛点1.随着项目越来越大,前端编译打包流程巨慢。(算上图片视频等资源,仓库有3.9G大小)2.运营需要经常改动网站内容,由于需要SEO,哪怕改几个字也需要前端打包发布。3.旧框架的核心还是Jquery,虽然结果3年开发积累了很多组件,但在数据维护、模块化以及开发体验上已经落后了。 以上痛点想必手上有老项目的,都感同身受。改起来伤筋动骨,但不改吧工作效率太低了。 此次重构需要满足哪些要求再说说重构的基本要求,咱得渐进增强而不是优雅降级。:D 1.支持SEO,也就是说需要服务端渲染。2.解放前端、测试劳动力,让运营在网站内容管理平台编辑数据后发布,官网及时生效。(不同于传统AJAX,这里数据需要SEO)。3.支持多国语言。4.需要新旧框架同存,同域名下无缝对接,要求两套工作流都可以正常工作。(一些不频繁改动的页面,可以不改,减少重构成本)。5.更快的页面性能、更畅快的开发体验和更好可维护性。 此次重构技术选型首先,服务端渲染 SSR 是没跑了,它可以更快渲染首屏,同时对 SEO 更友好。 于是我在带着鸭梨与小兴奋寻遍各大SSR方案后,最终选择了 Next.jsNext.js 是一个轻量级的 React 服务端渲染应用框架。目前在 github 已获得 4W+ 的 star。 之所以火爆,是因为它有以下优点:1.默认服务端渲染模式,以文件系统为基础的客户端路由2.代码自动分隔使页面加载更快3.简洁的客户端路由(以页面为基础的)4.以webpack的热替换为基础的开发环境5.使用React的JSX和ES6的module,模块化和维护更方便6.可以运行在其他Node.js的HTTP 服务器上7.可以定制化专属的babel和webpack配置 这里不做过多讲解了,大家可以访问 next.js中文网、github地址了解更多。 重构过程中遇到的问题以及解决方案问题一:网站采用 next.js 的 start 模式服务,还是 export 出静态化文件让 ngxin 做web服务两种方案都可行,但各有优缺点。 考虑到运营并不在乎那点等待时间,相比之下项目稳定性更重要。于是选择方案二:「export 出静态化文件让 ngxin 做web服务」。 ok~ 选定后要做的就是静态化了。 问题二:如何静态化如何做呢? 恩... 最简单的就是 cd 到项目目录下 npm run build && npm run export 下,打包出文件到./out文件夹,然后打个zip包扔服务器上。当然,为了运营数据及时更新,你得24小时不停重复以上步奏,还不能手抖出错。 为了不被同事打死,我设计了一套开发流程,在项目中写一个shell脚本: #!/bin/bashecho node版本:$(node -v)BASEDIR=$(dirname $0)cd ${BASEDIR}/../sudo npm run buildwhile true;do whoami && pwd sudo npm run export >/dev/null 2>&1 || continue sudo chown -R {服务器用户名} ./out || echo 'chown Err' sudo cp -ar ./out/* ./www || echo 'cp Err' sudo chown -R {服务器用户名} ./www || echo 'chown Err' echo '静态化并复制完毕' sleep 15done好了,只要执行这段 shell,你的服务器就会cd到项目目录,先build构建项目,然后每间隔15秒构建一次。并输出当前环境和相关信息。 ...

October 14, 2019 · 5 min · jiezi

为-Nextjs-应用生成-robotstxt-和-sitemapxml

原文发布于 https://www.imlc.me/p/generate-robots-txt-and-sitemap-xml-in-next-js-zh为了优化 SEO,生成 robots.txt 和 sitemap.xml 是必不可少的功能。Next.js 自身并不提供生成 robots.txt 和 sitemap.xml 的特性,所以需要自己实现。 Server Side Render(SSR)sitemap.xml.js在 pages/ 目录下创建 sitemap.xml.js。当浏览器访问 http://<your-domain>/sitemap.xml 路径时, Next.js 会调用 sitemap.xml.js 处理请求并响应。在下面的例子中,我请求后台 API 获取 sitemap 数据,并返回给浏览器。 import React, { Component } from "react";import fetch from 'isomorphic-unfetch';export default class SiteMap extends Component { static async getInitialProps({req, res}) { if(res) { const response = await fetch(`http://${req.headers['host']}/api/sitemap`); const text = await response.text(); res.setHeader("Content-Type", "text/xml"); res.write(text); res.end(); } }}robots.txt同样地,在 pages/ 目录下创建 robots.txt 文件。 ...

October 1, 2019 · 1 min · jiezi

Nextjs-初试

title: next.js入门 tag:next.js, react序章服务端渲染服务端渲染(SSR: Server Side Rendering),html页面由服务器渲染好,客户端请求的是完整的html页面。egg,php,jsp等都是良好的服务端渲染技术。优点seo优化。优化首屏加载速度:相比加载单页应用,只需加载当前页面内容,不用加载大量的js。缺点线上排查bug不能用浏览器控制台查看数据流动。不是前后端分离的最佳实践。SEO搜索引擎优化(SEO:Search Engine Optimization),利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。为网站提供生态式的自我营销解决方案,让其在行业内占据领先地位,获得品牌收益。SEO包含站外SEO和站内SEO两方面。从网站结构、内容建设方案、用户互动传播、页面等角度进行合理规划,从搜索引擎获得更多的免费流量。安装基于react,所以需要同时安装react和react-domyarn next react react-dom --save编写package.json中的script字段{ "scripts": { "dev": "next", "build": "next build", "start": "next start" }}目录结构默认情况下: 每个.js文件是一个路由。./page是服务器的渲染索引./static中的文件映射到/static/路由编写Hello World页面编写一个无状态的页面组件// ./page/index.jsvar num = 1num ++ console.log(num)function click () { console.log(num++)}export default () => ( <div onClick={click}>Hello Next.js</div>)开发yarn dev yarn dev -p 8080 // 指定端口号运行以上hello world页面可以看出,num在服务端终端和浏览器控制台都输出一次,单个js文件中的全局代码是服务端和客户端公用的代码,一次在全局中处理纯服务器逻辑可能会出错,反之亦然。点击div可以打印出num,并且递增,符合react组件逻辑。获取数据和组件生命周期服务端渲染一个常见的业务场景:获取数据库(或其他服务器)数据,数据返回后再将其插入页面中,生成完整页面返回给客户端。前面说过这个逻辑不能写在全局中,因为这里的代码服务器和客户端都会运行,并且这是一个异步过程,肯定要在一个异步函数、或回调函数中运行的逻辑。getInitialProps页面加载时,改方法只会在服务端执行一次。该方法只有在路由切换时,客户端的才会被执行。改方法的返回值已props注入组件,在客户端运行时可以获取数据getInitialProps方法的参数的属性包含:pathname - URL 的 path 部分query - URL 的 query 部分,并被解析成对象asPath - 显示在浏览器中的实际路径(包含查询部分),为String类型req - HTTP 请求对象 (只有服务器端有)res - HTTP 返回对象 (只有服务器端有)jsonPageRes - 获取数据响应对象 (只有客户端有)err - 渲染过程中的任何错误 ...

June 21, 2019 · 1 min · jiezi

connect和next的withRouter共同时候时踩坑

问题重现当同时使用两者时,在代码中切换router并不会重新reRender组件,代码如下: export default connect((state: any) => { return { x: state.common.x, }})(withRouter(Index))问题原因connect本身将组件变为pureComponent,next的withRouter并没有对router做任何处理,而是直接返回。 connect 源码return function connect( mapStateToProps, mapDispatchToProps, mergeProps, { pure = true, areStatesEqual = strictEqual, areOwnPropsEqual = shallowEqual, areStatePropsEqual = shallowEqual, areMergedPropsEqual = shallowEqual, ...extraOptions } = {}) {}withRouter源码render() { return <ComposedComponent router={this.context.router} {...this.props as any} />}解决方案1、将withRouter包在connect外层使用。 export default withRouter( connect((state: any) => { return { x: state.common.x, } })(Index),)2、在使用connect时将组件pure的值默认改为false。

May 29, 2019 · 1 min · jiezi

开发函数计算的正确姿势-移植-nextjs-服务端渲染框架

首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考。Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考。2.0 版本的 Fun,在部署这一块做了很多努力,并提供了比较完善的功能,能够做到将云资源方便、平滑地部署到云端。但该版本,在本地开发上的体验,还有较多的工作要做。于是,我们决定推出 Fun Init 弥补这一处短板。Fun Init: Fun Init 作为 Fun 的一个子命令存在,只要 Fun 的版本大于等于 2.7.0,即可以直接通过 fun init 命令使用。Fun Init 工具可以根据指定的模板快速的创建函数计算应用,快速体验和开发函数计算相关业务。官方会提供常用的模板,用户也可以自定自己的模板。背景next.js 是一种 React 的服务端渲染框架,且 next.js 集成度极高,框架自身集成了 webpack、babel、express 等,使得开发者可以仅依赖 next、react、react-dom 就可以非常方便的构建自己的 SSR React 应用,开发者甚至都不用像以前那样关心路由。 next.js 的高度集成性,使得我们很容易就能实现代码分割、路由跳转、热更新以及服务端渲染和前端渲染。 next.js 可以与 express、koa 等服务端结合使用。为了能让 next.js 在函数计算运行,首先需要让 next.js 在 express 中运行起来,然后再移植 express 到函数计算中运行。express 应用移植相关文章: 开发函数计算的正确姿势——移植 Express移植 express.js 应用到函数计算next.js 运行在 express 中现在,我们提供了一个 fun 模块,通过该模板,三分钟就可以让 next.js 应用在函数计算中运行起来。效果如下: 快速开始1. 安装 node ...

May 24, 2019 · 1 min · jiezi

Nextjs源码简析服务端渲染过程以及documentapppages这三者调用关系

首先分析一下整体加载逻辑在自定义服务端中通过const app = next()创建实例并使用app.render(req, res)方法进行渲染 所以可以从app.render这个渲染入口开始着手 了解框架逻辑唯一的方式就是看源码,由于源码过于细节,下面我会简化涉及到的代码,仅保留主要逻辑,附带具体地址,有兴趣深入的同学可以看看首先是app.render next-server/server/next-server.ts import { renderToHTML } from './render.tsx'// app.render入口函数this.render(req, res){ const html = await this.renderToHTML(req, res) return this.sendHTML(req, res, html)}this.renderToHTML(req, res){ const html = await this.renderToHTMLWithComponents(req, res) return html}this.renderToHTMLWithComponents(req, res) { // render内的renderToHTML return renderToHTML(req, res)}可以看到上面都是简单的调用关系,虽然删除了大部分代码,但我们只需要知道,最终它调用了render.tsx内的renderToHTML 这是一个相当长的函数,也就是本篇文章的主要内容,通过renderToHTML能够了解到大部分内容,和上面相同,删除了大部分逻辑,仅保留核心代码 // next-server/server/render.tsxfunction renderToHTML(req, res) {// 参考下文#补充 loadGetInitialProps,非常简单的函数,就是调用了_app.getInitialProps// _app.getInitialProps函数内部会先调用pages.Component的getInitialProps// 也就是在这里,我们编写的组件内的getInitialProps同样会被调用,获取部分初始数据 let props = await loadGetInitialProps(App, { Component, router, ctx }); // 定义渲染函数,返回html和head const renderPage = () => { // 参考下文#补充 render return render( renderToStaticMarkup, //渲染_app,以及其内部的pages.Component也就是我们编写的代码,详情参考next/pages/_app.tsx <App Component={EnhancedComponent} router={router} {...props} /> ); }; // _document.getInitialProps会调用renderPage,渲染_app也就是我们的正常开发时编写的组件代码,详情参考next/pages/_app.tsx const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage }); // 参考下文#补充 renderDocument let html = renderDocument(Document, { props, docProps, }); return html;}小结req=>render(req, res) renderToHTML(req, res) renderToHTMLWithComponents(req, res) renderToHTML(req,res) _app.initialProps = loadGetInitialProps(App, { Component, router, ctx }) _document.initialProps = loadGetInitialProps(Document, { ...ctx, renderPage }) renderDocument(Document, _app.initialProps, _document.initialProps)<=res对应 ...

May 12, 2019 · 3 min · jiezi

这是一个快速构建nextjs应用的工具

因为公司的业务需求现在开发都用nextjs来实现React的服务端渲染,为了之后开发方便自己写了个脚手架工具。 官方也有一个create-next-app的工具,但是只能简单的安装基础的依赖,或者通过他们提供的某个例子来构建自己的项目。由于目前还在开发阶段 只支持 cssless/sasstypescriptant-designredux上面这些的配置也是平常我用的比较多的配置。后面会逐渐增加其他配置。 判断命令的第一个参数模版地址的时候如果没有对应的模版会从github自动下载模版到对应的路径下。 构建出来的项目结构: 脚手架仓库地址模版仓库地址

April 22, 2019 · 1 min · jiezi

Next.js 入门

欢迎关注我的公众号睿Talk,获取我最新的文章:一、前言当使用 React 开发系统的时候,常常需要配置很多繁琐的参数,如 Webpack 配置、Router 配置和服务器配置等。如果需要做 SEO,要考虑的事情就更多了,怎么让服务端渲染和客户端渲染保持一致是一件很麻烦的事情,需要引入很多第三方库。针对这些问题,Next.js提供了一个很好的解决方案,使开发人员可以将精力放在业务上,从繁琐的配置中解放出来。下面我们一起来看看它的一些特性。二、特性介绍Next.js 具有以下几点特性:默认支持服务端渲染自动根据页面进行代码分割简洁的客户端路由方案(基于页面)基于 Webpack 的开发环境,支持热模块替换可以跟 Express 或者其它 Node.js 服务器完美集成支持 Babel 和 Webpack 的配置项定制三、Hello World执行以下命令,开始 Next.js 之旅:mkdir hello-nextcd hello-nextnpm init -ynpm install –save react react-dom nextmkdir pages在package.json中输入以下内容:{ “scripts”: { “dev”: “next”, “build”: “next build”, “start”: “next start” }}在 pages 文件夹下,新建一个文件 index.js:const Index = () => ( <div> <p>Hello Next.js</p> </div>)export default Index在控制台输入npm run dev,这时候在浏览器输入http://localhost:3000,就能看到效果了。四、路由Next.js 没有路由配置文件,路由的规则跟 PHP 有点像。只要在 pages 文件夹下创建的文件,都会默认生成以文件名命名的路由。我们新增一个文件看效果pages/about.jsexport default function About() { return ( <div> <p>This is the about page</p> </div> )}在浏览器输入http://localhost:3000/about,就能看到相应页面了。如果需要进行页面导航,就要借助next/link组件,将 index.js 改写:import Link from ’next/link’const Index = () => ( <div> <Link href="/about"> <a>About Page</a> </Link> <p>Hello Next.js</p> </div>)export default Index这时候就能通过点击链接进行导航了。如果需要给路由传参数,则使用query string的形式: <Link href="/post?title=hello"> <a>About Page</a> </Link>取参数的时候,需要借助框架提供的withRouter方法,参数封装在 query 对象中:import { withRouter } from ’next/router’const Page = withRouter(props => ( <h1>{props.router.query.title}</h1>))export default Page如果希望浏览器地址栏不显示query string,可以使用as属性:<Link as={/p/${props.id}} href={/post?id=${props.id}} <a>{props.title}</a></Link>这时候浏览器会显示这样的url:localhost:3000/p/12345五、SSRNext.js 对服务端渲染做了封装,只要遵守一些简单的约定,就能实现 SSR 功能,减少了大量配置服务器的时间。以上面这个 url 为例子,直接在浏览器输入localhost:3000/p/12345是会返回404的,我们需要自己实现服务端路由处理的逻辑。下面以express为例子进行讲解。新建一个 server.js 文件:const express = require(’express’)const next = require(’next’)const dev = process.env.NODE_ENV !== ‘production’const app = next({ dev })const handle = app.getRequestHandler()app .prepare() .then(() => { const server = express() // 处理localhost:3000/p/12345路由的代码 server.get(’/p/:id’, (req, res) => { const actualPage = ‘/post’ const queryParams = { title: req.params.id } app.render(req, res, actualPage, queryParams) }) server.get(’*’, (req, res) => { return handle(req, res) }) server.listen(3000, err => { if (err) throw err console.log(’> Ready on http://localhost:3000’) }) }) .catch(ex => { console.error(ex.stack) process.exit(1) })当遇到/p/:id这种路由的时候,会调用app.render方法渲染页面,其它的路由则调用app.getRequestHandler方法。无论是服务端渲染还是客户端渲染,往往都需要发起网络请求获取展示数据。如果要同时考虑 2 种渲染场景,可以用getInitialProps这个方法:import Layout from ‘../components/MyLayout.js’import fetch from ‘isomorphic-unfetch’const Post = props => ( <Layout> <h1>{props.show.name}</h1> <p>{props.show.summary.replace(/<[/]?p>/g, ‘’)}</p> <img src={props.show.image.medium} /> </Layout>)Post.getInitialProps = async function(context) { const { id } = context.query const res = await fetch(https://api.tvmaze.com/shows/${id}) const show = await res.json() console.log(Fetched show: ${show.name}) return { show }}export default Post获取数据后,组件的props就能获取到getInitialProps return 的对象,render 的时候就能直接使用了。getInitialProps是组件的静态方法,无论服务端渲染还是客户端渲染都会调用。如果需要获取 url 带过来的参数,可以从context.query里面取。六、CSS in JS对于页面样式,Next.js 官方推荐使用 CSS in JS 的方式,并且内置了styled-jsx。用法如下:import Layout from ‘../components/MyLayout.js’import Link from ’next/link’function getPosts() { return [ { id: ‘hello-nextjs’, title: ‘Hello Next.js’ }, { id: ’learn-nextjs’, title: ‘Learn Next.js is awesome’ }, { id: ‘deploy-nextjs’, title: ‘Deploy apps with ZEIT’ } ]}export default function Blog() { return ( <Layout> <h1>My Blog</h1> <ul> {getPosts().map(post => ( <li key={post.id}> <Link as={/p/${post.id}} href={/post?title=${post.title}}> <a>{post.title}</a> </Link> </li> ))} </ul> <style jsx>{ h1, a { font-family: 'Arial'; } ul { padding: 0; } li { list-style: none; margin: 5px 0; } a { text-decoration: none; color: blue; } a:hover { opacity: 0.6; } }</style> </Layout> )}注意<style jsx>后面跟的是模板字符串,而不是直接写样式。七、导出为静态页面如果网站都是简单的静态页面,不需要进行网络请求,Next.js 可以将整个网站导出为多个静态页面,不需要进行服务端或客户端动态渲染了。为了实现这个功能,需要在根目录新建一个next.config.js配置文件:module.exports = { exportPathMap: function() { return { ‘/’: { page: ‘/’ }, ‘/about’: { page: ‘/about’ }, ‘/p/hello-nextjs’: { page: ‘/post’, query: { title: ‘Hello Next.js’ } }, ‘/p/learn-nextjs’: { page: ‘/post’, query: { title: ‘Learn Next.js is awesome’ } }, ‘/p/deploy-nextjs’: { page: ‘/post’, query: { title: ‘Deploy apps with Zeit’ } } } }}这个配置文件定义了 5 个需要导出的页面,以及这些页面对应的组件和需要接收的参数。然后在package.json定义下面 2 个命令,然后跑一下:{ “scripts”: { “build”: “next build”, “export”: “next export” }}npm run buildnpm run export跑完后根目录就会多出一个out文件夹,所有静态页面都在里面。八、组件懒加载Next.js 默认按照页面路由来分包加载。如果希望对一些特别大的组件做按需加载时,可以使用框架提供的next/dynamic工具函数。import dynamic from ’next/dynamic’const Highlight = dynamic(import(‘react-highlight’))export default class PostPage extends React.Component { renderMarkdown() { if (this.props.content) { return ( <div> <Highlight innerHTML>{this.props.content}</Highlight> </div> ) } return (<div> no content </div>); } render() { return ( <MyLayout> <h1>{this.props.title}</h1> {this.renderMarkdown()} </MyLayout> ) } }}当 this.props.content 为空的时候,Highlight 组件不会被加载,加速了页面的展现,从而实现按需加载的效果。九、总结本文介绍了 Next.js 的一些特性和使用方法。它最大的特点是践行约定大于配置思想,简化了前端开发中一些常用功能的配置工作,包括页面路由、SSR 和组件懒加载等,大大提升了开发效率。更详细的使用介绍请看官方文档。 ...

April 16, 2019 · 3 min · jiezi

Next框架与主流工具的整合(二)—— 完善与优化

前言:18年12月24日项目成功上线了,在经历了两周的线上bug、UI以及代码优化后,解决了不少问题,于是再完善与优化一下这个项目。布局优化高清配置antd-mobile 自定义配置antd-mobile Toast组件封装布局优化布局优化在这篇文章完成了 → 移动端优雅布局实践,最后我使用的方案是——absolute脱离文档流(好处是设置容器的height: 100%,可以直接继承html窗口高度)。高清配置问题发现开始项目之前没有对dpr(device pixel radio)与缩放做过多的了解,在项目开发的时候就将它们都直接写死为1了。到后来UI验收的时候发现并没有实现UI设计师预期的细线效果。我在解决这个问题的时候才去认真看了一下dpr的介绍。这篇详解dpr的文章写得还不错。从概念来说,dpr就是设备的物理像素与设备独立像素(也就是css逻辑像素,以下就称为css逻辑像素)的比率。比如:iPhone 6的分辨率是7501334,window.screen.width(css逻辑像素)为375,因此dpr = 750 /375 = 2再比如:iPhone X的分辨率是11252436,window.screen.width(css逻辑像素)也是375,因此dpr = 1125 /375 = 3那么dpr有什么用呢?在这之前先提一下我们移动端必备的一个meta标签:<meta name=“viewport” content=“width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=no” />device-width在html中也同样被解读为理想(基准)视口的宽度,即320px,375px,414px,这里的px就是指css像素,通常也被称为逻辑像素;那我们可以认为html中的css像素的显示尺寸应该和NA中的pt、dp的显示尺寸相等。通过这个meta标签,我们可以实现initial-scale=1初始缩放100%,就可以达到1px的css逻辑像素 = 眼睛在设备上看起来的1px,换句话说body { width: 375px; }可以在iPhone 6上充满竖屏的整个宽度。那么问题就来了,如果我们要给一个盒子加上一个1px的细线:border-bottom: 1px solid red;。那么在iPhone 6上真的是1px吗?iPhone 6真机截图(宽度为702px):可以看出高度明显不止1像素。这就是由于dpr造成的,因为iPhone 6的dpr为2,且缩放比例为100%,1px的css渲染出来就是2px物理像素。这就是我们UI粑粑和产品们不满意的地方。那接下来如何去解决这个问题呢?解决方案根据设备的dpr来动态计算缩放比例,以及根节点的font-size。// rem.js(function(doc, win) { var docEl = doc.documentElement, dpr = Math.min(win.devicePixelRatio, 3); dpr = window.top === window.self ? dpr : 1; //被iframe引用时,禁止缩放 var scale = 1 / dpr, resizeEvt = ‘orientationchange’ in window ? ‘orientationchange’ : ‘resize’; docEl.dataset.dpr = dpr; var metaEl = doc.createElement(‘meta’); metaEl.name = ‘viewport’; metaEl.content = ‘initial-scale=’ + scale + ‘,maximum-scale=’ + scale + ‘, minimum-scale=’ + scale + ‘,user-scalable=no,viewport-fit=cover’; docEl.firstElementChild.appendChild(metaEl); var recalc = function() { var width = docEl.clientWidth; // 大于1280按1280来算 if (width / dpr > 1280) { width = 1280 * dpr; } // px : rem = 100 : 1 docEl.style.fontSize = 100 * (width / 375) + ‘px’; }; recalc(); if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false);})(document, window);如果有显示富文本元素,则需要处理富文本元素的样式移动端为了适配不同的机型,使用rem为单位是一个不错的选择,而且我们也一直在用它。 这里除了根据dpr来计算initial-scale,还调整了根节点的font-size,以至于在缩放的时候能够还原到视窗大小(因为要缩放,所以要相应的增加rem的基数)。这样我们上面写的border-bottom: 1px solid red;在这个方案显示出来就是这样的:哇咔咔,可以看出明显变细了,这才是我们UI粑粑们想要的O(∩_∩)O~~但是这样的设置在结合ant-design-mobile的时候,发现ant-design-mobile的组件都被缩小了。原来是,它的元素都是以px为单位,而我们缩放前没有对它的最小单位乘以相应的基数。那么,我们需要给它配置一个基数!antd-mobile自定义配置查文档发现ant-design-mobile提供了主题配置,而且它提供了一个@hd的变量做为长度基本单位,它的默认值是1px。我们只需要把@hd设置为0.01rem就可以解决问题。这个主题配置的文档是以webpack项目来做的例子。那如何在next.js项目中完成自定义配置呢?我在next.js的examples中没有找到我所需要的example,不过找到了两个相关的例子:一个是with-antd-mobile,一个是with-ant-design-less。第二个是ant-design的自定义主题配置,那应该就可以仿照这个example去增加with-antd-mobile的自定义主题配置。这里提一下,这个with-antd-mobile在我写Next框架与主流工具的整合之后更新了next.config.js的配置,这里也改成了最新的配置。安装解析 Less 与 normalize.css 的包npm i @zeit/next-less @zeit/next-css less less-vars-to-js -S修改.babelrc配置{ “presets”: [“next/babel”], “plugins”: [ [ “import”, { “libraryName”: “antd-mobile”, “style”: true } ] ]}修改next.config.js配置/* eslint-disable */const withCSS = require(’@zeit/next-css’);const withSass = require(’@zeit/next-sass’);const withLess = require(’@zeit/next-less’);const lessToJS = require(’less-vars-to-js’);const fs = require(‘fs’);const path = require(‘path’);// Where your antd-custom.less file livesconst themeVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, ‘./antd-custom.less’), ‘utf8’));// fix: prevents error when .less files are required by nodeif (typeof require !== ‘undefined’) { require.extensions[’.less’] = file => {}; require.extensions[’.css’] = file => {};}module.exports = withCSS( withLess( withSass({ lessLoaderOptions: { javascriptEnabled: true, modifyVars: themeVariables } }) ));在项目下新建Less变量文件 antd-custom.less@hd: 0.01rem;重启项目,就大功告成了。antd-mobile Toast组件封装antd-mobile的Toast.info()组件在显示的时候不能点击背景就消失,与原生的Toast有些差异,为了体验,这里再做了一层封装,在点击背景的时候隐藏Toast。// utils/toast.jsstatic info = (content, duration, onClose, mask) => { Toast.info(content, duration, onClose, mask); const toastElement = document.getElementsByClassName(‘am-toast-mask’)[0]; toastElement && toastElement.addEventListener(‘click’, () => { Toast.hide(); onClose && onClose(); }); };antd-mobile的loading图在Android上有些怪异,这里也自定义了Loading:static loading = (content, duration, onClose, mask) => { Toast.info( <div> <svg className=“rotate360-800” width=“0.26rem” height=“0.26rem” viewBox=“0 0 26 26”> <title>加载</title> <desc>Created with Sketch.</desc> <g id=“首页” stroke=“none” strokeWidth=“1” fill=“none” fillRule=“evenodd”> <g transform=“translate(-185.000000, -519.000000)” fill="#FFFFFF" id=“加载”> <g transform=“translate(185.000000, 519.000000)"> <g id=“分组” transform=“translate(0.625011, 0.625011)"> <path d=“M12.3750144,0.0259531552 C5.53983848,0.0259531552 0,5.56600648 0,12.4009676 C0,19.2359286 5.53983848,24.775982 12.3750144,24.775982 C19.2099755,24.775982 24.7500288,19.2359286 24.7500288,12.4009676 C24.7500288,5.56579163 19.2099755,0.0259531552 12.3750144,0.0259531552 Z M12.3750144,22.028385 C7.05736759,22.028385 2.74781179,17.7185714 2.74781179,12.4009676 C2.74781179,7.08332074 7.05741056,2.7735501 12.3750144,2.7735501 C17.6926612,2.7735501 22.0026467,7.08336371 22.0026467,12.4009676 C22.0026467,17.7186144 17.6926182,22.028385 12.3750144,22.028385 Z” id=“形状” fillOpacity=“0.2” fillRule=“nonzero” /> <path d=“M12.3749972,0.0259402646 L12.3750144,2.77353721 C17.6926612,2.77353721 22.0026467,7.08335082 22.0026467,12.4009547 L24.7500116,12.4009547 C24.7500116,5.56577874 19.2099583,0.0259402646 12.3749972,0.0259402646 Z” id=“路径” /> </g> </g> </g> </g> </svg> <div style={{ fontSize: ‘0.12rem’ }}>{content}</div> </div>, duration, onClose, mask ); };写在最后一个项目需要在不断的优化与完善中才能变得更好。搭建项目是对一个项目负责人很大的考验,如果在项目设计的初期有许多的问题没有考虑到,就很有可能导致优化的时候需要耗费很大的精力。总之,不要逃避困难与问题,这些都是成长路上不可或缺的。 ...

January 19, 2019 · 2 min · jiezi

入门hexo ! 搭配next、GiteePages,轻松免费开发高质量个人博客 ( Linux Deepin )

本文重点介绍Linux deepin下开发hexo 搭配next、GiteePages,免费轻松实现高质量高颜值博客。其他系统的方法大同小异,只是环境配置略有不同,只要有git和npm环境便可轻松入门hexo。最终效果: https://tczmh.gitee.io/hexodemo/一、安装先安装git npm依赖sudo apt install gitsudo apt install npm初始化hexo init blogcd blognpm install启动hexo server打开浏览器访问 http://localhost:4000即可看到第一个hexo页面二、主题换主题 ( 位置还是在blog文件夹内 Linux下默认位置是 /usr/lib/blog )git clone https://github.com/iissnan/hexo-theme-next themes/next配置文件vim _config.ymltheme: landscape 改为 theme: next# Extensions## Plugins: https://hexo.io/plugins/## Themes: https://hexo.io/themes/theme: next部署 重启hexo g -dhexo s效果如图三、发文章发表文章hexo new post “初识hexo"编辑文章vim /usr/lib/blog/source/_posts/初识hexo.md修改内容,语法为markdown(语法问题,所有的 被我替换成了 . 使用的时候要替换回来)---title: testdate: 2019-01-17 09:27:29tags: test---## start----**这是加粗的文字***这是倾斜的文字*这是斜体加粗的文字这是加删除线的文字—-—-<a href=“https://www.jianshu.com/u/1f5ac0cf6a8b" target="_blank”>简书</a>—-姓名|技能|排行–|:–:|–:刘备|哭|大哥关羽|打|二哥张飞|骂|三弟—-…javascript function clean(){ alert(“已完成!”); }…—-…flowst=>start: 开始e=>end: 结束op=>operation: 我的操作cond=>condition: 确认?st->op->condcond(yes)->econd(no)->op…—-##end部署 重启hexo g -dhexo s效果如下https://tczmh.gitee.io/hexodemo/2019/01/17/demo/四、部署线上避坑指南:用户名之后会用来作为二级域名例子:若 用户名为qiaofeng那么 就可以获得一个免费的个人线上地址qiaofeng.gitee.io若 新建项目的时候,项目名如果是blog那么 访问地址就是https://qiaofeng.gitee.io/blog/若项目名与用户名相同也叫qiaofeng那么 可以直接访问二级域名访问 https://qiaofeng.gitee.io 而省略项目名先注册码云(https://gitee.com),新建项目(截图省略)打开【服务】 - 【Gitee Pages】勾选【强制使用 HTTPS】点击【启动】看到“已开启 Gitee Pages 服务,网站地址: https://tczmh.gitee.io/hexodemo” 即可回到本地,修改配置文件vim _config.yml中间修改(这里的url是刚才开启Gitee Pages 服务出现的url,root必须是gitee新建的项目名,如果最后出现读不到js css,显示混乱等问题,就是这一步不对)url: https://tczmh.gitee.io/hexodemoroot: /hexodemo结尾修改deploy: type: git repo: https://gitee.com/tczmh/hexodemo.git branch: master其中repo填写gitee上获得的git地址,在【项目详情】 - 【克隆/下载】 - 【复制】安装依赖npm install hexo-deployer-git –save设置全局git (若邮箱和用户名不知道,可以在gitee的个人设置页面查看)git config –global user.email “你的邮箱"git config –global user.name “你的用户名"清理&更新&部署一条龙命令 (可能需要输入账号密码,就输gitee登录的即可)hexo clean && hexo g && hexo d看到以下内容说明成功remote: Powered By Gitee.com To https://gitee.com/tczmh/hexodemo.git + cfcc494…395648d HEAD -> master (forced update)分支 ‘master’ 设置为跟踪来自 ‘https://gitee.com/tczmh/hexodemo.git' 的远程分支 ‘master’。INFO Deploy done: git访问地址:https://tczmh.gitee.io/hexodemo和本地测试的一样大功告成!之后只需要修改本地配置文件来配置博客,发表文章更多功能访问官方文档https://hexo.io/zh-cn/docs/http://theme-next.iissnan.com/getting-started.html补充一下生成二维码方法(因为开启HTTPS 所以直接支持 微信扫一扫 微信长按二维码识别等)https://cli.im/输入【URL】点击【生成】即可主要就是这些,都是一些基本入门的东西,深入研究可以说是其乐无穷。本篇内容也可以查看我的个人博客:https://zzzmh.cn/single?id=54 ...

January 17, 2019 · 1 min · jiezi

移动端优雅布局实践

移动端优雅布局实践前言:移动端有非常多的坑,布局首当其冲。背景移动端应用有各种复杂的页面需求,不仅要解决单屏、多屏、固定头部或底部等多个场景,还要兼容ios和Android内核,在经历了项目实战(手机模式打开)过后,总结出了一些经验,在这里和大家分享一下。这篇文章是基于 →Next轻量级框架与主流工具的整合 最新的代码在这里 → next-mobile-complete-demo心路历程首先,需要实现的首页类似于app应用。第一站:统一flex布局的坑→ flex教程首页如上面的图片所示,然后偷了个懒,直接用了antd-mobile的tab标签栏,它需要指定容器高度。于是,在项目最开始的时候直接通过js将容器设置为浏览器html窗口的高度:// html高度 = body高度 = 主容器高度doc.body.style.height = docEl.clientHeight + ‘px’;这样做也有许多好处:纵向布局十分方便,不管是tab标签栏、tab标签页、头部固定元素或者底部固定元素实现起来都很简单;也能很简单就能实现元素居中对齐、两端对齐、自动分配空间等;同时也避免了Android输入框引起传统布局的问题。不过这里有个唯一的不好的地方就是兼容不了ios的前进返回的操作栏和上下滚动回弹:不能在滚动时隐藏前进返回的操作栏、在上下滚动时容易触发页面的回弹效果,造成滚动卡顿。这里补充一下:在ios上如果以正常流布局,内容超过一定高度时,向下滚动会隐藏底部的前进返回栏,向上滚动的时候再显示出来。当滚动到底部或者顶部时,再继续拉动页面,会有一个回弹的效果。这两个问题极大的降低了ios的用户体验,又恰逢项目间隔期,有大把的时间,于是被推着到了布局优化上面。第二站:寻找良好用户体验的布局案例这里我们在寻找的过程中发现两个具有代表性的移动端应用:bilibili的m站、腾讯新闻它用的是传统式流布局,头部和底部fixed固定,所有的内容全部向下平铺。花瓣网H5它采用的是设置主容器的position属性为absolute来脱离文档流的形式。这两种布局方式在ios上都用户体验极好。但同时也发现他们都存在的一些问题,比如:登录页面明明不足一屏,却依然存在滚动;没有兼容iPhone X的安全域;弹窗滚动穿透等等。如果能将这两种布局和flex进行整合一下,聚合各自的优点,基本上能打造一个用户体验和兼容性都令人满意的移动端应用了。那么,如何基于现有的flex布局去整合这两种布局又成了一个问题。第三站:基于flex调整布局结构在调整之前,我的预期是这样的:去掉外层高度限制,去掉纵向flex布局(除极少数单屏页面),将顶部、底部固定和弹窗设置为fixed。考虑到少数单屏页面需要继承html窗口的高度,于是采用了主容器脱离文档流的方式。调整过后dom结构是这样的:html > body > div#root > div.main-content(position: absolute)只需要给main-content加上height: 100%,就可以满足单屏页面的需求。好事多磨!按照上面的想法进行改造过后又发现了新的问题:脱离文档流过后,切换页面,html会保持最后滚动的位置。第四站:滚动条位置、滚动穿透、兼容iPhone X解决滚动条位置被记录的问题 找了一下发现history有个scrollRestoration的属性,它有两个值,一个是默认值auto还有一个是manual。如果设置为manual就可以手动设置滚动的位置。if (‘scrollRestoration’ in history) { history.scrollRestoration = ‘manual’;}然后在切换路由过后设置滚动的位置为起始位置:Router.events.on(‘routeChangeComplete’, () => {document.scrollingElement.scrollTop = 0;});这样每次切换页面都是从初始位置开始。这里有点鸡肋,前进后退也不会记录滚动位置。如果需要前进后退记录滚动的位置,就不能用这种脱离文档流的形式,需要用body滚动的形式,也就是。解决滚动穿透 这个问题,需要针对有滚动的弹窗和无滚动的弹窗单独处理。针对无滚动的弹窗,在弹窗弹出的时候禁用touchmove事件,隐藏的时候移除事件监听。有滚动的弹窗,需要找到页面的滚动的容器设置overflow:hidden兼容iPhone X 在meta标签后增加viewport-fit=cover<meta name=“viewport” content=“initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover”/>然后留出安全域距离padding-bottom: 0.49rem; // 底部button的高度padding-bottom: calc(0.49rem + constant(safe-area-inset-bottom));padding-bottom: calc(0.49rem + env(safe-area-inset-bottom));这里需要注意些padding-bottom的时候需要写三个,第一个是为了兼容Android。总结总的来说flex布局还是带了十分大的便利,尤其是能根治居中、适配等一些老大难的问题。每种布局的方式都有一定的缺陷,到目前为止还没有一种万能的方案来解决移动端各种复杂的场景。还是需要根据自己的需求还选择使用哪种实现方式。*前面这三种方案各自的缺陷:纵向flex布局(不建议使用)body流式平铺(传统)absolute脱离文档流(激进)ios前进后退的操作栏无法隐藏、回弹效果引起卡顿内部容器无法继承html窗口高度前进后退无法记录滚动条位置

January 16, 2019 · 1 min · jiezi

服务端渲染Next.js下配置SEO文件

服务端渲染Next.js下配置SEO文件使用服务端渲染Next.js提供SEO静态文件(例如sitemap.xml,robots.txt和favicon.ico),只需将这些静态文件放在static文件夹中,然后将以下代码添加到服务器(server.js)配置中即可完成:const robotsOptions = { root: __dirname + ‘/static/’, headers: { ‘Content-Type’: ’text/plain;charset=UTF-8’, }};server.get(’/robots.txt’, (req, res) => ( res.status(200).sendFile(‘robots.txt’, robotsOptions)));const sitemapOptions = { root: __dirname + ‘/static/’, headers: { ‘Content-Type’: ’text/xml;charset=UTF-8’, }};server.get(’/sitemap.xml’, (req, res) => ( res.status(200).sendFile(‘sitemap.xml’, sitemapOptions)));const faviconOptions = { root: __dirname + ‘/static/’};server.get(’/favicon.ico’, (req, res) => ( res.status(200).sendFile(‘favicon.ico’, faviconOptions)));

December 18, 2018 · 1 min · jiezi