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