完善template:layout、router、store、util
This commit is contained in:
parent
f2e5e0913a
commit
2ca6889ed4
|
@ -5,7 +5,7 @@
|
|||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"serve": "webpack serve --open --config webpack.dev.js",
|
||||
"start": "webpack serve --open --config webpack.dev.js",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<link rel="icon" href="favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import Router from './router'
|
||||
|
||||
const App = () => {
|
||||
return <Router />
|
||||
}
|
||||
|
||||
export default App
|
|
@ -0,0 +1,15 @@
|
|||
const { RouteCode } = require('./routeConstants')
|
||||
|
||||
module.exports = {
|
||||
name: 'app',
|
||||
urls: {
|
||||
loginUrl: '/passport/login',
|
||||
defaultUrl: '/home/index',
|
||||
},
|
||||
redirects: [
|
||||
{
|
||||
from: RouteCode.ROOT,
|
||||
to: RouteCode.PAGE_HOME,
|
||||
},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
export const RoutePath = {
|
||||
ROOT: 'layout',
|
||||
LAYOUT_BASIC: 'layout/basic',
|
||||
PAGE_HOME: 'page/home',
|
||||
}
|
||||
|
||||
export const RouteCode = {
|
||||
ROOT: 'LAYOUT',
|
||||
LAYOUT_BASIC: 'LAYOUT_BASIC',
|
||||
PAGE_HOME: 'PAGE_HOME',
|
||||
}
|
|
@ -3,13 +3,13 @@ import 'regenerator-runtime'
|
|||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import Router from './router'
|
||||
import App from './App'
|
||||
import { Provider } from 'react-redux'
|
||||
import store from './store'
|
||||
|
||||
const element = (
|
||||
<Provider store={store}>
|
||||
<Router />
|
||||
<App />
|
||||
</Provider>
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import { Outlet } from 'react-router-dom'
|
||||
|
||||
const Layout = () => {
|
||||
return <Outlet />
|
||||
}
|
||||
|
||||
export default Layout
|
|
@ -1,15 +1,47 @@
|
|||
import React from 'react'
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom'
|
||||
import BasicLayout from '../layout/basic'
|
||||
import Home from '../page/home'
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'
|
||||
import Redirect from './redirect'
|
||||
import { defaultRoutes } from './routes'
|
||||
import { routerTool } from '../util/router'
|
||||
|
||||
const Router = () => {
|
||||
const appUrls = useSelector((state) => state.app.urls)
|
||||
const redirects = useSelector((state) => state.app.redirects)
|
||||
|
||||
const processRoutes = (params) => {
|
||||
if (!params) return []
|
||||
let allRedirects = routerTool.processRoutes(defaultRoutes, redirects)
|
||||
let routes = params.map((item) => {
|
||||
let Component = lazy(() => import(`src/${item.component}`))
|
||||
let redirect = allRedirects.find((p) => p.from === item.code)
|
||||
let props = {
|
||||
element: (
|
||||
<Suspense fallback={<div>loading</div>}>
|
||||
<Redirect redirect={redirect ? redirect.toUrl : ''}>
|
||||
<Component />
|
||||
</Redirect>
|
||||
</Suspense>
|
||||
),
|
||||
path: item.path,
|
||||
}
|
||||
return (
|
||||
<Route key={item.path} {...props}>
|
||||
{processRoutes(item.children)}
|
||||
</Route>
|
||||
)
|
||||
})
|
||||
return routes
|
||||
}
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path='/' element={<BasicLayout />}>
|
||||
<Route element={<Home />} index />
|
||||
</Route>
|
||||
{processRoutes(defaultRoutes)}
|
||||
<Route
|
||||
path='*'
|
||||
element={<Navigate to={appUrls?.defaultUrl || '/'} />}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* eslint-disable react/prop-types */
|
||||
import React, { useEffect } from 'react'
|
||||
import { generatePath, useMatch, useNavigate } from 'react-router-dom'
|
||||
|
||||
const Redirect = (props) => {
|
||||
const match = useMatch(props.redirect)
|
||||
const navigate = useNavigate()
|
||||
useEffect(() => {
|
||||
if (props.redirect) {
|
||||
if (match) {
|
||||
navigate(generatePath(props.redirect, match.params))
|
||||
} else {
|
||||
navigate(props.redirect)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
return <>{props.children}</>
|
||||
}
|
||||
|
||||
export default Redirect
|
|
@ -0,0 +1,26 @@
|
|||
import { RouteCode, RoutePath } from '../config/routeConstants'
|
||||
|
||||
export const defaultRoutes = [
|
||||
{
|
||||
code: RouteCode.ROOT,
|
||||
title: 'root',
|
||||
path: '/',
|
||||
component: RoutePath.ROOT,
|
||||
children: [
|
||||
{
|
||||
code: RouteCode.LAYOUT_BASIC,
|
||||
title: 'home',
|
||||
path: 'home',
|
||||
component: RoutePath.LAYOUT_BASIC,
|
||||
children: [
|
||||
{
|
||||
code: RouteCode.PAGE_HOME,
|
||||
title: 'index',
|
||||
path: 'index',
|
||||
component: RoutePath.PAGE_HOME,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
|
@ -2,11 +2,11 @@ import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
|
|||
import thunk from 'redux-thunk'
|
||||
import storageEnhancer from './enhancer/storage'
|
||||
import loggerMiddleware from './middleware/logger'
|
||||
import appReducer from './reducer/app'
|
||||
import countReducer from './reducer/count'
|
||||
import todoReducer from './reducer/todo'
|
||||
|
||||
const reducer = combineReducers({
|
||||
todo: todoReducer,
|
||||
app: appReducer,
|
||||
count: countReducer,
|
||||
})
|
||||
const middlewareEnhancer = applyMiddleware(loggerMiddleware, thunk)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import defaultApp from '../../config/defaultApp'
|
||||
import { copyTool } from '../../util/copy'
|
||||
import { storeTool } from '../../util/store'
|
||||
|
||||
const fetch = async (state) => {
|
||||
return state
|
||||
}
|
||||
|
||||
const update = async (state, ...props) => {
|
||||
return copyTool.merger(state, ...props)()
|
||||
}
|
||||
|
||||
const appReducer = storeTool.createReducer(defaultApp, {
|
||||
APP_FETCH: fetch,
|
||||
APP_UPDATE: update,
|
||||
})
|
||||
|
||||
export default appReducer
|
|
@ -1,15 +1,15 @@
|
|||
import { storeTool } from '../../util/store'
|
||||
|
||||
const addCount = (countState) => {
|
||||
return countState + 1
|
||||
const addCount = (state) => {
|
||||
return state + 1
|
||||
}
|
||||
|
||||
const setCount = (countState, param) => {
|
||||
const setCount = (state, param) => {
|
||||
return param
|
||||
}
|
||||
|
||||
const delCount = (countState) => {
|
||||
return countState <= 0 ? 0 : countState - 1
|
||||
const delCount = (state) => {
|
||||
return state <= 0 ? 0 : state - 1
|
||||
}
|
||||
|
||||
const countReducer = storeTool.createReducer(0, {
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { storeTool } from '../../util/store'
|
||||
|
||||
const addTodo = (todoState, param) => {
|
||||
const newTodo = todoState.concat(param)
|
||||
return newTodo
|
||||
}
|
||||
|
||||
const editTodo = (todoState, param) => {
|
||||
const _index = todoState.findIndex((item) => item.id === param.id)
|
||||
if (_index < 0) return newTodo
|
||||
const newTodo = storeTool.updateItemInArray(todoState, _index, (item) => {
|
||||
return storeTool.updateObject(item, param)
|
||||
})
|
||||
return newTodo
|
||||
}
|
||||
|
||||
const delTodo = (todoState, param) => {
|
||||
const _index = todoState.findIndex((item) => item.id === param.id)
|
||||
if (_index < 0) return newTodo
|
||||
const newTodo = todoState.splice(_index, 1)
|
||||
return newTodo
|
||||
}
|
||||
|
||||
const todoReducer = storeTool.createReducer([{ id: 1, name: 'hello' }], {
|
||||
ADD_TODO: addTodo,
|
||||
EDIT_TODO: editTodo,
|
||||
DEL_TODO: delTodo,
|
||||
})
|
||||
|
||||
export default todoReducer
|
|
@ -0,0 +1,74 @@
|
|||
const defineType = (param) => {
|
||||
let type = Object.prototype.toString.call(param)
|
||||
return type.split(' ')[1].split(']')[0]
|
||||
}
|
||||
|
||||
const mergeObject = (target = {}, source, isJoin, isReplace, isFilter) => {
|
||||
for (const key in source) {
|
||||
if (Object.hasOwnProperty.call(target, key)) {
|
||||
if (isReplace) {
|
||||
target[key] = source[key]
|
||||
} else {
|
||||
target[key] = merger(target[key], source[key])(
|
||||
isJoin,
|
||||
isReplace,
|
||||
isFilter
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (isJoin) {
|
||||
target[key] = merger(target[key], source[key])(
|
||||
isJoin,
|
||||
isReplace,
|
||||
isFilter
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
const mergeArray = (target = [], source, isJoin, isReplace, isFilter) => {
|
||||
if (isJoin) {
|
||||
target = [...target, ...source]
|
||||
} else {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (isReplace) {
|
||||
target[i] = source[i]
|
||||
} else {
|
||||
target[i] = merger((target && target[i]) || undefined, source[i])(
|
||||
isJoin,
|
||||
isReplace,
|
||||
isFilter
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isFilter) {
|
||||
target = [...new Set(target)]
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
const merger = (...props) => {
|
||||
let res
|
||||
const merge = (isJoin = true, isReplace = false, isFilter = true) => {
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
switch (defineType(props[i])) {
|
||||
case 'Array':
|
||||
res = mergeArray(res, props[i], isJoin, isReplace, isFilter)
|
||||
break
|
||||
case 'Object':
|
||||
res = mergeObject(res, props[i], isJoin, isReplace, isFilter)
|
||||
break
|
||||
default:
|
||||
res = props[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
return merge
|
||||
}
|
||||
|
||||
export const copyTool = { merger }
|
|
@ -0,0 +1,33 @@
|
|||
const findPath = (params, code) => {
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
if (params[i].code === code) {
|
||||
return [params[i].path]
|
||||
} else {
|
||||
if (params[i].children) {
|
||||
let childPath = findPath(params[i].children, code)
|
||||
return childPath ? [params[i].path, ...childPath] : []
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const processRoutes = (routes, redirects) => {
|
||||
return redirects.map((item) => {
|
||||
let fromUrl = findPath(routes, item.from)
|
||||
if (fromUrl.length > 0) {
|
||||
fromUrl = fromUrl.join('/').replace('//', '/')
|
||||
}
|
||||
let toUrl = findPath(routes, item.to)
|
||||
if (toUrl.length > 0) {
|
||||
toUrl = toUrl.join('/').replace('//', '/')
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
fromUrl,
|
||||
toUrl,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const routerTool = { processRoutes }
|
|
@ -1,20 +1,3 @@
|
|||
const updateObject = (oldVal, newVal) => {
|
||||
return Object.assign({}, oldVal, newVal)
|
||||
}
|
||||
|
||||
const updateItemInArray = (array, index, updateCallback) => {
|
||||
const updatedArray = array.map((_item, _index) => {
|
||||
if (_index !== index) {
|
||||
return _item
|
||||
}
|
||||
|
||||
const updatedItem = updateCallback(_item)
|
||||
return updatedItem
|
||||
})
|
||||
|
||||
return updatedArray
|
||||
}
|
||||
|
||||
const createReducer = (initialState, handlers) => {
|
||||
return function reducer(state = initialState, action) {
|
||||
if (Object.prototype.hasOwnProperty.call(handlers, action.type)) {
|
||||
|
@ -25,4 +8,4 @@ const createReducer = (initialState, handlers) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const storeTool = { createReducer, updateObject, updateItemInArray }
|
||||
export const storeTool = { createReducer }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const path = require('path')
|
||||
const CaseSensitivePathsWebpackPlugin = require('case-sensitive-paths-webpack-plugin')
|
||||
const { merge } = require('webpack-merge')
|
||||
const common = require('./webpack.common')
|
||||
|
|
Reference in New Issue