国际化实现 (react-intl)
import {
addLocaleData,
IntlProvider
} from 'react-intl'
import zh_CN from '../locale/zh_CN';//个人配置
import en_US from '../locale/en_US';//个人配置
import zh from 'react-intl/locale-data/zh'; //react-intl语言包
import en from 'react-intl/locale-data/en'; //react-intl语言包
addLocaleData([...en, ...zh]);//需要放入本地数据库
// 判断cookie中设置的语言是否存在,不存在则默认取浏览器的语言, 如果是中文默认为中文,如果不是中文默认为英文
if (!lang) {
if (typeof window !== 'undefined') {
language = (navigator.language || navigator.userLanguage).substr(0, 2)
language = language == 'zh' ? 'zh' : 'en'
Cookie.set('hpbLanguage', language)
}
}
return {
<IntlProvider locale={lang ? lang : language} messages={messages[lang ? lang : language]}>
<Component {...pageProps} />
</IntlProvider>
}
// IntlProvider 有三个配置参数:
// locale, <string>, 语言标记,例如 'zh-CN' 'en-US'
// messages, <object>, 国际化所需的 key-value 对象
// formats, <object>, 自定义 format,比如日期格式、货币等
在页面中如何使用
<FormattedMessage
tagName="p"
id="example"
values={{
name: 'React'
}}
defaultMessage="{name} 默认信息。"
description="{name} 描述?"
/>
- id 指代的是这个字符串在配置文件中的属性名
- description 指的是对于这个位置替代的字符串的描述,便于维护代码,不写的话也不会影响输出的结果
- defaultMessage 当在 locale 配置文件中没有找到这个 id 的时候,输出的默认值
- tagName 实际生成的标签,默认是 span
- values 动态参数. 格式为对象
默认语言的设置
由于一般不会设置很多种语言资源库,不能完全和浏览器的默认语言相匹配,如果出现语言库不存在的情况,回导致页面中显示出语言对应的 key,也就是
FormattedMessage
组件中对应的 id,导致页面显示问题,所以设置默认语言
switch (navigator.language.split('-')[0]) {
case 'en':
return en_US
break
case 'zh':
return zh_CN
break
default:
return en_US
break
}
解决国际化多语言在服务端渲染时的问题( cookie-parser )
解决页面手动刷新时,由于默认语言的原因导致的页面闪烁,解决方法:在服务端也储存 cookie,解决刷新的问题
// serve.js
const cookie = require('cookie-parser')
app
.prepare()
.then(() => {
const server = express()
server.use(cookie()) // use cookie
....
}).catch(ex => {
console.error(ex.stack)
process.exit(1)
})
在客户端只需要按照正常的存 cookie 的方法即可
import Cookie from 'js-cookie'
Cookie.set(key, value) // cookie-parser可以保持客户端和服务端cookie统一
在对应的页面设置
static async getInitialProps({ req }) {
// 获取cookie中设置的语言,渲染不同语言的页面
const lang = req
? req.cookies.hpbLanguage || ''
: Cookie.get('hpbLanguage') || ''
return { lang }
}
路由跳转
需求:期望详情页的路由是
blog/id
而不是 `/blog?query=id
routerLink = id => {
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual' // 跳转的时候页面回到顶部
}
// console.log(window.location)
if (typeof window !== 'undefined') {
// 后来的需求是要在新页面打开,当时考虑是使用a标签打开还是window.open,最终选择了window.open
window.open(`${window.location.origin}/post-${id}`, '_blank')
} else {
Router.push(
{
pathname: '/post',
query: {
id
}
},
`/post-${id}` // 伪造路由,实际的路由还是通过 `query` 去传参的,障眼法而已
)
}
}
通过 express
做服务端的数据请求和重定向
devProxy 代理设置
const devProxy = {
'/api': {
target: 'ip:3000/',
// pathRewrite: { '^/api': '/' },
changeOrigin: true
}
}
自定义服务端的路由和重定向
app
.prepare()
.then(() => {
const server = express()
server.use(cookie())
const proxyMiddleware = require('http-proxy-middleware') // 接口地址代理的中间件
Object.keys(devProxy).forEach(function(context) {
server.use(proxyMiddleware(context, devProxy[context]))
})
server.get('/post-:id', (req, res) => {
// 配合伪造路由,解析路由参数,确保接口的请求参数是正确的
const actualPage = '/post'
const queryParams = { id: req.params.id }
app.render(req, res, actualPage, queryParams)
})
server.get('/post/:id', (req, res) => {
// 301重定向 /post/:id => /post-:id
res.redirect(301, `/post-${req.params.id}`)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3001, err => {
if (err) throw err
console.log(`> Ready on port ${port} [${env}]`)
})
})
.catch(ex => {
console.error(ex.stack)
process.exit(1)
})
antd 默认样式修改
因为
antd
的样式是全局的,所以在局部作用域内修改会无法生效,可以使用 less 中的全局的方法来修改
<div className="title">
<Row gutter={24}>
<Col xl={6} md={6} xs={6}>
111111
</Col>
<Col xl={12} md={12} xs={12}>
22222
</Col>
<Col xl={6} md={6} xs={6} className="right">
333333
</Col>
</Row>
</div>
.title {
max-width: 1200px;
line-height: 60px;
height: 62px;
margin: 60px auto 0;
background: #3d4864;
font-size: 14px;
text-align: center;
color: #fff;
.right {
line-height: 20px;
padding-top: 20px;
}
:global(.ant-row) {
<!--全局的样式-->margin: 0 !important;
}
}
全局图片路径
大坑: 当时做全局部署的时候,需要改图片路径。
export const imgHost = {
// "local_page": 'https://dapp-prod-fileserver01.oss-cn-hongkong.aliyuncs.com/hpbsite3.0',
local_page: '../static',
// "local_component": 'https://dapp-prod-fileserver01.oss-cn-hongkong.aliyuncs.com/hpbsite3.0',
local_component: '../static'
// "local_component": '../../../',
//https://dapp-prod-fileserver01.oss-cn-hongkong.aliyuncs.com/hpbsite3.0/images/sc_github.png
}
// 组件内使用
import { imgHost } from '../../common/config/imgHost'
;<img src={`${imgHost.local_component}/images/team/${name}.jpg`} />
css 样式的预加载
出现的问题: ssr 部署到服务器上之后,第一次加载会出现没有样式的页面
期望: 在 css 和 js 都加载完成后才显示页面
解决方案:使用 css 预加载
Twitter 和 Telegram 分享链接加载的是卡片效果
官方文档 官方提供 4 种类型,Summary card、Summary with large image、Player card、App card。
import React, { Component } from 'react'
import Head from 'next/head'
class Header extends Component {
constructor(props) {
super(props)
this.state = {
visible: false
}
}
render() {
let {
description = '',
title = '',
descTitle = '',
// url = 'url',
// img = 'https://dapp-prod-fileserver01.oss-cn-hongkong.aliyuncs.com/hpbsite3.0/images/logo/indexIcon2.png'
img = '',
keywords = ''
} = this.props.data || {}
return (
<Head>
<meta name="description" content={description} />
<meta name="keywords" content={keywords} />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=no"
className="next-head"
></meta>
<meta property="og:type" content="article" />
<meta property="og:title" content={descTitle} />
{/* <meta property="og:url" content={url} /> */}
<meta property="og:description" content={description} />
{/* <meta property="og:site_name" content="" /> */}
<meta property="og:image" content={img} />
<meta property="og:image:width" content="770" />
<meta property="og:image:height" content="433" />
{/* <meta property="og:locale" content="en_US" /> */}
{/* <meta name="twitter:creator" content="" />
<meta name="twitter:site" content="" /> */}
<meta name="twitter:text:title" content={descTitle} />
<meta name="twitter:image" content={img} />
<meta name="twitter:card" content="summary_large_image" />
{/* <meta property="article:publisher" content="hwq" /> */}
{/* <meta name="twitter:app:id:iphone" content="586939626" /> */}
{/* <meta property="article:author" content="hwq" /> */}
<title>{title}</title>
</Head>
)
}
}
export default Header