摘要:前言以前一直是用進(jìn)行的開發(fā)于是決定年后弄一弄所以年后這段時(shí)間也就一直瞎弄可算是看到成果了本來(lái)是想寫一個(gè)類似仿今日頭條那樣的項(xiàng)目來(lái)入手后來(lái)又尋思還不如寫個(gè)后臺(tái)管理呢。于是乎自己便著手簡(jiǎn)單的搭建了一個(gè)集中設(shè)置的版本。
前言
以前一直是用vue進(jìn)行的開發(fā), 于是決定年后弄一弄react, 所以年后這段時(shí)間也就一直瞎弄react, 可算是看到成果了
本來(lái)是想寫一個(gè) 類似 Vue仿今日頭條 那樣的項(xiàng)目來(lái)入手, 后來(lái)又尋思還不如寫個(gè)后臺(tái)管理呢。
于是乎便開始搗鼓起來(lái)了。
react
react-dom
react-router-dom: react-router4以后 好像都是用這個(gè)東西了
react-transition-group: 用來(lái)做動(dòng)畫的
redux: 用來(lái)管理全局狀態(tài)
react-redux: 用來(lái)管理全局狀態(tài)
redux-actions: 用來(lái)創(chuàng)建action的,而且生成相關(guān)reducers的時(shí)候也不要寫 switch/case 或 if/else 了,主要是方便。
redux-thunk: redux的中間件, 用來(lái)處理我們異步action
antd: 隨便找的一個(gè)比較常用的react-UI庫(kù)
跟react相關(guān)的主要就是這個(gè)幾個(gè)了
至于webpack 配置,基本跟以前配置vue的基本沒(méi)多大區(qū)別。
build: 用來(lái)放置關(guān)于webpack的配置
config: 項(xiàng)目配置
src: 源碼
static: 靜態(tài)資源
.babelrc: babel配置
postcss.config.js: css配置
別的目錄就不說(shuō)了,主要介紹一個(gè)src下的目錄結(jié)構(gòu)actions: 放redux中action相關(guān)的地方
reducers: 放redux中reducer相關(guān)的地方
assets: 項(xiàng)目靜態(tài)資源
components: 常用的公共組件
router: 路由相關(guān)的配置
store: redux的配置
styles: 公共樣式文件
utils: 工具類的封裝
view: 所有頁(yè)面的主體結(jié)構(gòu)
main.js: 項(xiàng)目入口文件
config.js: 公共屬性配置
1. react 的 幾種書寫方式React.createClass
import React from "react" const MyComponent = React.createClass({ render () { return (我是React.createClass生成的組件
) } })
React.createClass會(huì)自綁定函數(shù)方法(不像React.Component只綁定需要關(guān)心的函數(shù))導(dǎo)致不必要的性能開銷,增加代碼過(guò)時(shí)的可能性
React.createClass的mixins不夠自然、直觀;
React.Component
import React from "react" class MyComponent from React.Component { render () { return (我是React.Component生成的組件
) } }
需要手動(dòng)綁定this指向
React.Component形式非常適合高階組件(Higher Order Components--HOC),它以更直觀的形式展示了比mixins更強(qiáng)大的功能,并且HOC是純凈的JavaScript,不用擔(dān)心他們會(huì)被廢棄
無(wú)狀態(tài)函數(shù)式組件
import React from "react" const MyComponent = (props) => (我是無(wú)狀態(tài)函數(shù)式組件
) ReactDOM.render(, mountNode)
無(wú)狀態(tài)組件的創(chuàng)建形式使代碼的可讀性更好,并且減少了大量冗余的代碼,精簡(jiǎn)至只有一個(gè)render方法,大大的增強(qiáng)了編寫一個(gè)組件的便利
組件不會(huì)被實(shí)例化,整體渲染性能得到提升
組件不能訪問(wèn)this對(duì)象
組件無(wú)法訪問(wèn)生命周期的方法
無(wú)狀態(tài)組件只能訪問(wèn)輸入的props,同樣的props會(huì)得到同樣的渲染結(jié)果,不會(huì)有副作用
2. 路由攔截路由攔截這塊費(fèi)了挺長(zhǎng)時(shí)間,本來(lái)是想找個(gè)類似vue的beforeRouter這個(gè)種鉤子函數(shù),發(fā)現(xiàn)沒(méi)有。
然后后面找到history模塊,發(fā)現(xiàn)有個(gè)這東西有個(gè)監(jiān)聽路由的方法,最開始就用這它,但是我突然切成hash模式進(jìn)行開發(fā)的時(shí)候,發(fā)現(xiàn)通過(guò)history.push(path, [state])設(shè)置state屬性的時(shí)候出了問(wèn)題,這東西好像只能給history模式設(shè)置state屬性,但是我有部分東西是通過(guò)設(shè)置state屬性來(lái)進(jìn)來(lái)的,于是便放棄了這個(gè)方法尋找新的方法。
后面發(fā)現(xiàn)可以通過(guò)監(jiān)聽根路徑的 componentWillReceiveProps 鉤子函數(shù) 便可以達(dá)到監(jiān)聽的效果。
這鉤子函數(shù)只要props改變便會(huì)觸發(fā),因?yàn)槊看吻袚Q路由 location 的pathname總是不同的,所有只要切換路徑便會(huì)觸發(fā)這個(gè)這個(gè)鉤子函數(shù)。這東西容易觸發(fā)死循環(huán),所以記得做好判斷。
class MainComponents extends React.Component { componentWillMount () { // 第一次進(jìn)來(lái)觸發(fā) this.dataInit(this.props) } componentWillReceiveProps(nextProps){ // 以后每次變化props都會(huì)觸發(fā) // 如果死循環(huán)了 可能是某個(gè)屬性設(shè)置會(huì)更新props上屬性,所以導(dǎo)致一直循環(huán),這個(gè)時(shí)候記得做好判斷 this.dataInit(nextProps) } render () { // 404 if (!isExistPath(allRoutes, pathname)) return3. 路由集中設(shè)置//當(dāng)前路徑路由信息 let currRoute = getRoute(allRoutes, pathname) // 非白名單驗(yàn)證 if (!whiteList.some(path => path === pathname)) { // 登錄驗(yàn)證 if (!Cookie.get("Auth_Token")) { return } // 獲取用戶信息 if (!user) { this.getUserInfo(() => { this.setRoutesByRole(this.props.user.roles) }) } } // 401 if (user && currRoute) { if (!isAuth(currRoute.role, user)) return } // 網(wǎng)頁(yè)title document.title = currRoute.name } }
用過(guò)vue的都知道我們一般都是通過(guò)new Router({routes}) 來(lái)集中管理路由表。但是react-router好像不能這么設(shè)置。最新的版本好像連嵌套都不行。
于是乎自己便著手簡(jiǎn)單的搭建了一個(gè)集中設(shè)置的版本 。不過(guò)后面我看到個(gè)插件好像是可以管理的 react-router-config,不過(guò)我也還沒(méi)試過(guò),也不知道可不可行。
// 路由表 const allRoutes = [ { path: "/auth", login: true, layout: true, icon: "user", name: "權(quán)限管理", role: ["admin"], component: _import_views("Auth") }, { path: "/error", login: true, layout: true, icon: "user", name: "ErrorPage", redirect: "/error/404", children: [ { path: "/error/404", component: _import_views("Error/NotFound"), name: "404"}, { path: "/error/401", component: _import_views("Error/NotAuth"), name: "401"} ] } ... ] // 根目錄4. 根據(jù)用戶權(quán)限動(dòng)態(tài)生成路由// MainComponents class MainComponents extends React.Component { render () { return ( {renderRouteComponent(allRoutes.filter(route => !route.layout))} //不需要側(cè)邊欄等公共部分的路由頁(yè)面 ) } } // ComponentByLayout const ComponentByLayout = ({history}) => () // 路由渲染 const RouteComponent = route => {renderRouteComponent(allRoutes.filter(route => route.layout))} const renderRouteComponent = routes => routes.map((route, index) => { return route.children ? route.children.map(route => RouteComponent(route)) : RouteComponent(route) })
我想根據(jù)用戶不同的權(quán)限生成不同的側(cè)邊欄。
{ path: "/auth", login: true, layout: true, icon: "user", name: "權(quán)限管理", role: ["admin"], component: _import_views("Auth") }
根據(jù)這個(gè)路由role信息 跟用戶的role信息匹配進(jìn)行顯示跟隱藏
這樣來(lái)篩選出符合這個(gè)用戶的路由表以及側(cè)邊欄(側(cè)邊欄根據(jù)路由表生成)
但是有個(gè)問(wèn)題,因?yàn)槲覀兪切枰卿洸拍艿弥脩舻臋?quán)限信息,所以我們得那個(gè)時(shí)候才能確定路由是哪些。
但是那個(gè)時(shí)候路由已經(jīng)設(shè)置完畢了。vue里面的提供了 router.addRoutes這個(gè)方法來(lái)供我們動(dòng)態(tài)設(shè)置路由,react里面我也沒(méi)找到關(guān)于這個(gè)api的,于是我便采取所有的路由都注冊(cè)一遍,但是這樣便產(chǎn)生一個(gè)問(wèn)題。
以 /auth 為例,我本身是沒(méi)有訪問(wèn)/auth的權(quán)限,所以我側(cè)邊欄不會(huì)生成 /auth這個(gè)列表選項(xiàng)。但是我們?cè)诘刂窓诶锩?訪問(wèn) /auth 是能進(jìn)入這個(gè)頁(yè)面的的 (最好的辦法就是壓根就不生成這個(gè)路由)。所以這個(gè)設(shè)置其實(shí)是有問(wèn)題,目前我也沒(méi)知道怎么動(dòng)態(tài)生成路由的辦法,暫時(shí)也只是在根目錄 做了權(quán)限處理
5. 按需加載按需加載的方法也不少,目前只嘗試了第一種,因?yàn)槲覍慥ue也是用import實(shí)現(xiàn)按需加載的,所以也就沒(méi)去折騰了。
1. import方法//asyncComponent.js import React from "react" export default loadComponent => ( class AsyncComponent extends React.Component { state = { Component: null, } async componentDidMount() { if (this.state.Component !== null) return try { const {default: Component} = await loadComponent() this.setState({ Component }) }catch (err) { console.error("Cannot load component in"); throw err } } render() { const { Component } = this.state return (Component) ? : null } } ) // index.js import asyncComponent from "./asyncComponent.js" const _import_ = file => asyncComponent(() => import(file)) _import_("components/Home/index.js")
原理很簡(jiǎn)單:
import()接受相應(yīng)的模塊然后返回Promise對(duì)象
asyncComponent 接收一個(gè)函數(shù),且這個(gè)函數(shù)返回promise對(duì)象
在componentDidMount鉤子函數(shù)通過(guò) async/await 執(zhí)行接受進(jìn)來(lái)的loadComponent方法,得到import返回的結(jié)果,賦值給state.Component,
因?yàn)槲覀僫mport的是一個(gè)React組件,所以我們得到的也是React組件,到時(shí)候只需要把該組件 render出去就行了
2. Bundle組件 + import(跟第一種感覺差不多) 3. react-loadable 4. bundle-loader 6. request我這里用到的是axios, 用axios做了個(gè)簡(jiǎn)單的攔截器
import axios from "axios" import qs from "qs" axios.defaults.withCredentials = true // 發(fā)送時(shí) axios.interceptors.request.use(config => { // 發(fā)起請(qǐng)求,可以進(jìn)行動(dòng)畫啥的 return config }, err => { return Promise.reject(err) }) // 響應(yīng)時(shí) axios.interceptors.response.use(response => response, err => Promise.resolve(err.response)) // 檢查狀態(tài)碼 function checkStatus(res) { // 得到返回結(jié)果,結(jié)束動(dòng)畫啥的 if (res.status === 200 || res.status === 304) { return res.data } return { code: 0, msg: res.data.msg || res.statusText, data: res.statusText } return res } // 檢查CODE值 function checkCode(res) { if (res.code === 0) { throw new Error(res.msg) } return res } export default { get(url, params) { if (!url) return return axios({ method: "get", url: url, params, timeout: 30000 }).then(checkStatus).then(checkCode) }, post(url, data) { if (!url) return return axios({ method: "post", url: url, data: qs.stringify(data), timeout: 30000 }).then(checkStatus).then(checkCode) } }7. redux
這里主要用了 redux-actions 來(lái)創(chuàng)建action的 ,
原生寫法
// action const addTodo = text => ({ type: "ADD_TODO", payload: { text, completed: false } }) // reducer const todos = (state = [], action) => { switch(action.type) { case "ADD_TODO": return [...state, action.payload] ... default: return state } }
用了 redux-actions的寫法
import { createAction, handleActions } from "redux-actions" // action const addTodo = createAction("ADD_TODO") // reducer const todos = handleActions({ ADD_TODO: (state, action) => { return [...state, action.payload] } ... }, [])
// 用redux-actions簡(jiǎn)單明了
8. connect用了redux,這東西基本就不能少了, connect主要是用來(lái) 連接 組件 跟 redux store的, 就是讓組件能獲取redux store里面的 值 和 方法
connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])
一般只用到前兩個(gè)參數(shù)
mapStateToProps(state, ownProps): 獲取store里面state指定數(shù)據(jù),然后傳遞到指定組件, ownProps 組件本身的 props
mapDispatchToProps: 這個(gè)是獲取store里面的action方法, 然后傳入指定組件
用法
import toggleTodo from "actions/todo" const mapStateToProps = state => ({ active: state.active }) const mapDispatchToProps = { onTodoClick: toggleTodo } connect(mapStateToProps, mapDispatchToProps)(Component) // 在Component組件中, 便能在 props 里面獲取到 active 數(shù)據(jù), 跟 onTodoClick 這個(gè)方法了
connect很多地方基本都要用到
所以也進(jìn)行了封裝
// connect.js import actions from "src/actions" // 所有action import {connect} from "react-redux" import {bindActionCreators} from "redux" export default connect( state => ({state}), // 偷懶了, 每次把state里面所有的數(shù)據(jù)都返回了 dispatch => bindActionCreators(actions, dispatch) //合并所有action,并且傳入dispatch, 那樣我們?cè)诮M件里面調(diào)用action,就不在需要dispatch了 )
bindActionCreators
然后我們把 connect.js 文件通過(guò) webpack 的alias屬性來(lái)進(jìn)行配置
//配置別名映射 alias: { "src": resolve("src"), "connect": resolve("src/utils/connect") }
然后我們就可以在文件中如下引用
import React from "react" import connect from "connect" @connect // 通過(guò)裝飾器調(diào)用 class Component extends React.Component { componentWillMount () { const {state, onTodoClick} = this.props console.log(state, onTodoClick) } }
為了省事,我把store里面所有的數(shù)據(jù) 和 action都返回了。
9. cssModules在 vue 中 我們一般都是通過(guò)設(shè)置 style標(biāo)簽的 scoped 屬性來(lái)做到css模塊化
但是在 react 中,我采用的 cssModules 來(lái)做css模塊化
通過(guò)webpack設(shè)置 css-loader 的modules來(lái)開啟css的模塊化
{ loader: "css-loader", options: { modules: true, //是否開啟 localIdentName: "[name]__[local]___[hash:base64:5]" // 轉(zhuǎn)化出來(lái)的class名字結(jié)構(gòu) } },
引入css, 并通過(guò)對(duì)象的賦值方式添加className
import styles from "./styles.css" export default () => ( ) //styles.css .a { color: #ff4747; }
或者可以通過(guò) react-css-modules 來(lái)更方便的控制class類名
import styles from "./styles.css" import CSSModules from "react-css-modules" class Component extends React.Component { render () { return ( ) } } export default CSSModules(Component, styles, { allowMultiple: true //允許多個(gè)class一起使用 }) //styles.css .a { color: #ff4747; } .b { background: #f00; }
這樣我們就可以通過(guò)字符串的方式傳入 class類名. 注意: 我們添加時(shí) 不再使用 className 了, 而是使用 styleName了
10. 雙向綁定的實(shí)現(xiàn)class Bingding extends React.Component { state = { value: "" } handleInput = value => { this.setState({ value }) } render () { return ( {this.handleInput(e.target.value)}}/>{this.state.value}) } }
就是通過(guò) onChange 事件 來(lái)觸發(fā) this.setState 重新渲染 render 方法
還有一些知識(shí)點(diǎn)
包括 動(dòng)畫,生命周期 等等
就不過(guò)多介紹了。這些項(xiàng)目中基本多多少少都參和了一點(diǎn)。
開發(fā)中遇到的問(wèn)題挺多的,最主要是react-router配置的問(wèn)題,怎么配置都感覺不太好。
也同時(shí)希望有人推薦幾個(gè)全面的尤其是最新版本的react開源項(xiàng)目。
項(xiàng)目啟動(dòng)步驟
npm/yarn run dll (DllPlugin打包,只需打包一次就夠了)
npm/yarn run dev (開發(fā)模式)
npm/yarn run build (生產(chǎn)模式)
小結(jié)國(guó)內(nèi)比較火的兩個(gè)框架,也勉強(qiáng)算是都接觸了下,vue我是一直在用的,react算是年后剛接觸的。
從我目前來(lái)看,vue比react開發(fā)起來(lái)確實(shí)要方便很多(可能用的比較多吧)。
因?yàn)?b>vue很多常用的都是內(nèi)置的。而react基本都要自己去尋找對(duì)應(yīng)的模塊。本身就只提供UI, 其他基本得自力更生。
主要是你經(jīng)常一找能找著多個(gè)模塊,你就不知道用哪個(gè),還得一個(gè)個(gè)試水。當(dāng)然,react的社區(qū)強(qiáng)大,這么都不是什么大問(wèn)題。
在線觀看地址
博客地址
github
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/93427.html
摘要:語(yǔ)法更近似于移動(dòng)端。當(dāng)參數(shù)為兩個(gè)時(shí),等同于,繪制光滑二次貝塞爾曲線。有些精通的同學(xué)這時(shí)候可能就要問(wèn)我了,不對(duì)啊,二次貝塞爾曲線和光滑三次貝塞爾曲線的參數(shù)都是個(gè),你這里沒(méi)有光滑三次啊因?yàn)殚_發(fā)的同學(xué)留坑沒(méi)寫了呀微笑。和則是用于指定旋轉(zhuǎn)的原點(diǎn)。 技術(shù)背景 在移動(dòng)應(yīng)用的開發(fā)過(guò)程中,繪制基本的二維圖形或動(dòng)畫是必不可少的。然而,考慮到Android和iOS均有一套各自的API方案,因此采用一種更普...
摘要:今天給大家?guī)?lái)了好程序員實(shí)戰(zhàn)項(xiàng)目商城管理后臺(tái)。配合項(xiàng)目學(xué)習(xí)會(huì)讓你更快掌握它的使用方法下面就來(lái)看看好程序員這套實(shí)戰(zhàn)項(xiàng)目課程介紹好程序員項(xiàng)目本項(xiàng)目是一個(gè)使用開發(fā)的商城系統(tǒng)的管理后臺(tái),里面登錄判斷,接口調(diào)用,數(shù)據(jù)展示和編輯,文件上傳等后臺(tái)功能。 眾所周知,項(xiàng)目經(jīng)驗(yàn)對(duì)于一個(gè)程序員變得越來(lái)越重要。在面...
摘要:在此我們選用用友的公共靜態(tài)資源庫(kù)。因此打算建立遠(yuǎn)程的其實(shí)還有個(gè)關(guān)鍵是我使用用友配的電腦開發(fā),在本地部署的話電腦配置。。。不過(guò)此步驟我們也可以省略了,用友的大前端技術(shù)團(tuán)隊(duì)提供了平臺(tái)。 數(shù)據(jù)分析平臺(tái)-實(shí)踐系列一 項(xiàng)目創(chuàng)建于2018年1月底,到現(xiàn)在已經(jīng)接近半年,在此寫下半年來(lái)項(xiàng)目的實(shí)踐過(guò)程以及自己對(duì)前端的學(xué)習(xí)與體悟。 技術(shù)選型 框架: React 路由: React-Router 4 狀態(tài)管...
閱讀 726·2021-11-23 09:51
閱讀 3618·2021-10-11 10:58
閱讀 15972·2021-09-29 09:47
閱讀 3702·2021-09-01 11:42
閱讀 1370·2019-08-29 16:43
閱讀 1890·2019-08-29 15:37
閱讀 2184·2019-08-29 12:56
閱讀 1790·2019-08-28 18:21