# multilingual_shop **Repository Path**: iiiboy/multilingual_shop ## Basic Information - **Project Name**: multilingual_shop - **Description**: 多语言电商平台前端部分,使用react+react-bootstrap进行设计开发,使用axios进行数据请求,使用redux,redux-saga进行公共数据管理,react-router进行路由管理. - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-09-10 - **Last Updated**: 2021-03-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 多语言电商项目(毕业设计)react实现 ## 1. 使用到的技术栈 react,node,koa ## 2. 创建项目,搭建环境 1. 使用`npx create-react-app project`创建react项目 2. 使用react-bootstrap作为ui框架,并且在上下载bootstrap主题,然后使用`yarn add react-bootstrap`安装依赖 3. 因为react项目默认为sass,但是我更习惯用less,所以需要配置less环境:`yarn add less less-loader react-app-rewired customize-cra -D` 安装对应依赖,然后再src目录下创建config-overrides.js进行配置,注意: 如果配置完成还是报错,可能是less-loader版本出现问题,可以删除当前版本的less-loader,然后`yarn add less-loader@5.0.0 -D` 4. 因为react-i18next使用比较复杂,没有相应中文文档,而且教程较少 下面换到react-intl-universal这个库由阿里开发,主要参考 ```jsx import React, { Component } from 'react' import Routes from './routes/Routes' // ! 这里将intl的初始化放到App组件里面来进行 经过实测这样还是会遇到intl.get()为空的情况 import intl from 'react-intl-universal' import resource from './locales/resource' import './plugins/font-awesome' import './plugins/axios' // 可以借助intl.determineLocale获取当前浏览器的语言环境设置初始化的语言环境 // 这个函数会返回字符串 就是当前获取到的环境 const lng = intl.determineLocale({ // 但是这里建议不要使用localStorage来更改当前页面语言环境 // 因为当你修改localStorage的lang字段之后没有刷新页面 是不会更改语言的 所以使用 url 或者cookie // localStorageLocaleKey:'lang', // 这个用于从localStorage中确定语言环境,寻找 lang 这个键名 // *注意 当这里声明了但是匹配不上时 会默认为当前浏览器的语言环境 也就是 navigator.language urlLocaleKey: 'lang', localStorageLocaleKey: 'lang', fallbackLocale: 'zh-CN' // 当所有的匹配不上时就使用这个备用的 }) class App extends Component { // 这里很重要 在没有constructor时 将state写在最前面就相当于 在constructor里面写state // isDone用于判断intl是否初始化完成 state = { isDone: false } componentDidMount () { // 组件挂载完成后进行初始化intl this.loadLocales() } // 这里是intl用于初始化的函数 loadLocales = () => { intl.init({ currentLocale: lng, fallbackLocale: 'zh_CN', locales: resource }).then(() => { // 这里时初始化完成后触发 this.setState({ isDone: true }) }) } render () { return ( // !第一次挂载时 因为isDone为false 所以并没有挂载渲染Routes 当初始化完成时才进行渲染 // !这样其实很重要,保证了一下所有的组件所处的环境都是intl渲染完成后的 不然的话 会遇到 intl.get()获取到空的情况 // !!!经过实测 这样还是会遇到intl.get()为空的情况 目前没有好的方法 // !只能在componentDidMount()进行定义 或者在 render() 中进行定义 // !好像还有一种方法 但是对于我目前的情况 不是很适用 https://blog.csdn.net/chenqk_123/article/details/102858073 this.state.isDone && ) } } export default App ``` ## 3. 需要先移除之前的库 然后进行配置 ## 4. 在项目中使用font-awesome 参考这个网址: 官方文档: 1. 使用 `yarn add @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome @fortawesome/free-brands-svg-icons @fortawesome/free-regular-svg-icons` 安装这么多依赖 2. 这样进行使用 ```jsx import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faQuestionCircle } from '@fortawesome/free-regular-svg-icons'; ``` 3. 像上面那样每个组件太麻烦了 我们可以将一些使用比较多的icon注册到全局 3.1 src下创建plugins文件夹 3.2 在plugins文件夹下创建font-awesome.js文件,并且进行配置 ```js import { library } from '@fortawesome/fontawesome-svg-core' import { fab } from '@fortawesome/free-brands-svg-icons' import { faCheckSquare, faCoffee } from '@fortawesome/free-solid-svg-icons' // 这个library 就相当于是全局 add就是添加到全局 // 接下来我们就可以之直接 这样使用 注意使用这种方式要去掉'fa' library.add(fab, faCheckSquare, faCoffee) ``` 3.3 在app.js下进行导入 `import './plugins/font-awesome'` ## 5. react-bootstrap进行表单验证 1. react-bootstrap 可以使用constraint validation API 进行表单验证 这个api相当于是H5的新特性,可以直接通过html5,js进行一些 简单的表单验证 参考网址: 参考网址: 主要的验证规则: 1.1 pattern 正则匹配 1.2 min 最小值 1.3 max 最大值 1.4 required 是否必需 1.5 step 暂时没有看懂 后面可以理解一下 1.6 maxlength最大长度 1.7 minlength最小长度 ```jsx // 因为是原生的api所以可以直接使用 具体的可以看react-bootstrap官网 import React from 'react' class Example extends React.Component { constructor (props) { super(props) this.state = {} } onSubmit = (event) => { const form = event.currentTarget if (form.checkValidity() === false) { event.preventDefault() } this.setState({}, () => { console.log(this.state) }) } render () { return (
) } } ``` 2. 如果使用validation API无法满足需求的话 还可以使用react-formal,formik配合yup进行验证,react-bootstrap中有formik进行验证 ```jsx // 注意引入formik的方式 import { Formik } from 'formik' // 引入yup的方式 import * as yup from 'yup' import React, { Component } from 'react' const schema = yup.object().shape({ email: yup.string().required('请输入邮箱!'), password: yup.string().required('请输入密码!') }) class Login extends Component { render () { return ( <> {/* * 注意这里的使用方法 Formik 组件只是 formik依赖的一个组件 还有其他的可以去官方文档看 * Formik 有很多属性可以看源码 */} { ({ handleSubmit, handleChange, handleBlur, // 这里就相当于是上面Formik的initialValues values, // 默认的字段信息 用于做提示 touched, // 是否全部通过验证 isValid, // 没有通过验证 errors }) => { return (
{errors.email} {errors.password} {touched.password}
) } }
) } } ``` ## 6. 创建store存储用户信息 1. 获取用户信息的话需要进行网络请求,这里使用的是axios进行网络请求的,在plugins/axios.js对axios进行了一些默认的配置, 然后又在services里对get,post,put,delete请求方法进行了封装,就可以直接引入services/http.js里的方法进行网络请求了, 而且后面还可以在http.js文件中进行集中的错误处理 2. 网络请求这方面完成后,还需要创建store用于存储用户信息 其他的没什么好说的,主要是redux处理异步的情况,我选择使用redux-saga 看之前的笔记就在lesson_05_saga redux-saga 官方网址: 3. 使用saga的步骤 同时还有启动redux-devtools ```js import { createStore, combineReducers, applyMiddleware } from 'redux' // 这个用于启动redux-devtools 便于浏览器redux工具的配合 // 参考网址 https://www.npmjs.com/package/redux-devtools-extension import { composeWithDevTools } from 'redux-devtools-extension' // 1. 导入创建saga中间件的函数 import createSagaMiddleware from 'redux-saga' // 2. 导入对应的generator函数 import { userSaga } from '../sagas/userSaga' import { user } from './reducers/user' // 注意使用saga的步骤 // 3. 创建saga中间件 const sagaMiddleware = createSagaMiddleware() const store = createStore( combineReducers({ user }), // 4. 使用saga中间件 注意redux-devtools同时还需要监听中间件 所以这里使用这个函数包裹中间件 composeWithDevTools(applyMiddleware(sagaMiddleware)) ) // 5. 使用generator函数 sagaMiddleware.run(userSaga) export default store ``` 4. 开始正确使用redux-saga 4.1 saga是用于处理redux的,所以需要先创建store,reducer,actions等一系列操作,创建完成后,在页面中使用connect连接组件,注入dispatch 4.2 在页面中就可以使用dispatch来触发saga 下面是saga的基础写法 ```js import { takeEvery,// 用于监听 call,// 用于异步请求 put,// 相当于原生dispatch用于分发 select// 用于获取当前state } from 'redux-saga/effects' import { LOGIN_USER, UPDATE_USER } from '../constants/user' // 注意这里的loginUser是这样的 export const loginUser = () => httpGet({ url: '/user/current' }) 所以下面call时不用传入参数 import { loginUser } from '../actions/userActions' // 创建并导出generator函数 export function * userSaga () { console.log('redux-saga创建成功') // !注意这里哦 !!! 这里监听的type 前往不要与分发的type一样 如果一样了 就会一直dispatch 然后一直监听触发 // !陷入死循环 yield takeEvery(LOGIN_USER, function * (...aru) { // 这里的loginUser这个函数不用传入参数 如果需要传参的话 就直接在后面添加参数就是了 与改变this指向的call一样的传参方式 const [res] = yield call(loginUser) if (res) { // !这里分发的type 前往不要和分发的type一样 yield put({ type: UPDATE_USER, payload: res.data.data }) } // * 注意 这里的返回值好像是下一个yield的参数, 但是这里使用的是一个函数 应该不一样 return '登陆成功' }) } ``` # 7. 使用redux-persist让redux持久化 redux-persist的npm网址: 这个网上一找一大推的教程 ## 8. 去掉input为number时的上下箭头 ```css input[type=number] { -moz-appearance: textfield; } input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } ``` ## 9. react ref的所有注册方式 ## 10. react遍历生成ref