eastercat / easter_webpack Goto Github PK
View Code? Open in Web Editor NEWreact+webpack
react+webpack
npm i
extract-text-webpack-plugin
copy-webpack-plugin
clean-webpack-plugin
webpack-merge
html-webpack-plugin
postcss-smart-import
postcss-loader
precss
--save-dev
const path = require('path');
const ROOTPATH = path.resolve(__dirname, '.');
module.exports = {
context: path.resolve(ROOTPATH, 'app'),
resolve: {
extensions: ['.js', '.jsx'], //后缀名自动补全,可以使用jsx的文件后缀
modules: [path.resolve(ROOTPATH, "node_modules")],
alias: {
COMPONENTS_PATH: './components',
}
},
entry: {
app: ['babel-polyfill', './app.js']
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
}
}
},
{
test: /.*\.(gif|png|jpe?g|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]'
}
}, {
loader: 'image-webpack-loader'
}]
},
{
test: /\.html$/,
use: [{
loader: 'html-loader',
options: {
minimize: false
}
}],
},
{
test: /\.(woff|svg|eot|ttf)\??.*$/,
use: [{
loader: 'url-loader',
options: {
limit: 50000,
}
}]
}
]
},
devServer: {
contentBase: path.resolve(ROOTPATH, './app'),//为一个目录下的文件提供本地服务器,在这里设置其所在目录
historyApiFallback: true,//跳转将指向index.html
inline: true,//开启自动刷新页面
port: 1234,//设置默认监听端口,如果省略,默认为"8080"
hot: true,//开启热替换
},
plugins: [],
};
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const path = require('path');
const ROOTPATH = path.resolve(__dirname, '.');
module.exports = merge(common, {
output: {
path: path.resolve(ROOTPATH, 'dist'), //打包的文件夹
filename: '[name].js',
publicPath: ''
},
module: {
rules: [
{
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}],
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
outputStyle: 'expanded',
sourceMapContents: true
}
}]
},
{
test: /\.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'less-loader',
options: {
sourceMap: true,
outputStyle: 'expanded',
sourceMapContents: true,
}
}]
},
{
test: /index\.html/,
use: [{
loader: 'file-loader',
options: {
name: 'index.[ext]'
}
}]
}
]
},
plugins: [],
});
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ROOTPATH = path.resolve(__dirname, '.');
module.exports = merge(common, {
output: {
path: path.resolve(ROOTPATH, 'dist'), //打包的文件夹
filename: '[name].[hash].bundle.js',
publicPath: ''
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({fallback: 'style-loader', use: ['css-loader']}),
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: [{
loader: 'css-loader'
}, {
loader: 'sass-loader'
}]
})
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader", options: {importLoaders: 1}
}, {
loader: "postcss-loader"
}, {
loader: 'less-loader'
}]
})
},
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new ExtractTextPlugin({
filename: '[name].[contenthash].css',
allChunks: true, // don't contain embedded styles
}),
//加入js压缩的实例
new UglifyJsPlugin({
mangle: {
mangle: false
},
compress: {
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: false,
if_return: true,
join_vars: true,
drop_console: false,
warnings: false
},
}),
new HtmlWebpackPlugin({
title: '中建八局',
filename: path.resolve(ROOTPATH, 'dist/template.html'), // the path to create html
template: path.resolve(ROOTPATH, 'app/public/template.html'), //the path of template html,
minify: false,
// favicon: path.resolve(__dirname, 'app/images/cscec_favicon-2.ico')
}),
new CleanWebpackPlugin(['dist', 'dist.zip', 'dist.rar'], {exclude: ['lib']}),
new CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, './node_modules')
) === 0
)
}
}),
],
});
"scripts": {
"build": "set NODE_ENV=production&&webpack -p --config webpack.pro.js",
"start": "webpack-dev-server --devtool eval --progress --colors --config webpack.dev.js "
},
module.exports = {
plugins: [
require('postcss-smart-import')({ /* ...options */ }),
require('precss')({ /* ...options */ }),
require('autoprefixer')({ /* ...options */ })
]
};
生成的代码已经进过了优化,压缩,分离CSS和JS,添加了版本号,能够利用缓存提升加载速度
redux-freeze运行时报错机制
redux-thunkredux的异步中间件
redux-logger日志中间件
redux-immutable在不可变数据类型中合并reducer
redux-create-reducer使用action和reducer的关联变的简单
npm i --save redux-immutable redux-freeze redux-thunk redux-logger immutable redux-create-reducer
import {createStore, applyMiddleware, compose} from 'redux';
import {combineReducers} from 'redux-immutable';
import freeze from "redux-freeze"
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import {Map} from 'immutable';
import reducers from './reducers';
let middlewares = [];
middlewares.push(thunk);
middlewares.push(logger);
middlewares.push(freeze);
//添加中间件
let middleware = applyMiddleware(...middlewares);
//添加redux dev tools,可以在谷歌商城里直接安装工具,搜索名字
middleware = compose(middleware, window.devToolsExtension());
const reducer = combineReducers(reducers);
const store = createStore(
reducer,
Map({}),
middleware
);
export default store;
import user from '../components/content01.reducer';
export default {
user
}
import {createReducer} from 'redux-create-reducer';
import {fromJS} from 'immutable';
import {
ADD_ONE_USER
} from './content01.actions';
const initState = fromJS({
data: [{
name: 'doudou',
age: 32,
phone: 123456789,
email: '[email protected]',
key: 1,
}]
});
const handlers = {
[ADD_ONE_USER]: (user, action) => {
return user.set('data', user.get('data').push(fromJS(action.payload)));
}
};
export default createReducer(initState, handlers);
export const ADD_ONE_USER = 'ADD_ONE_USER';
export function addOneUser(value) {
return dispatch => {
return dispatch({
type: 'ADD_ONE_USER',
payload: value
})
}
}
const mapStateToProps = (state) => {
return {
data: state.get('user').get('data'),
}
};
const mapActionCreators = {
addOneUser
};
export default connect(mapStateToProps, mapActionCreators)(Content01);
//生成package.json
npm init
npm install react react-dom --save
npm install [email protected] [email protected] --save-dev
<!--webpack和webpack-dev-server同时全局安装一下-->
npm install [email protected] [email protected] -g
[email protected]是最后兼容ie9的版本,升级之后会导致打包的文件在ie9下运行报错
npm install
babel-core 核心功能
babel-loader
babel-polyfill 转换低版本代码
babel-preset-env 解析Es6
babel-preset-react 解析JSX
--save-dev
npm install
css-loader
style-loader
file-loader
url-loader
image-webpack-loader
postcss-loader
html-loader
--save-dev
dependencies是运行时依赖,是我们发布后还需要依赖的模块
devDependencies是开发时的依赖,在发布后用不到它,而只是在我们开发才用到它
当npm install时,会下载dependencies和devDependencies中的模块,当使用npm install –production或者注明NODE_ENV变量值为production时,只会下载dependencies中的模块
const path = require('path');
const ROOTPATH = path.resolve(__dirname, '.');
module.exports = {
context: path.resolve(ROOTPATH, './app'),
entry: './app.js',
output: {
path: path.resolve(ROOTPATH, './dist'),
filename: 'app.js',
},
resolve: {
extensions: ['.js', '.jsx'], //后缀名自动补全,可以使用jsx的文件后缀
modules: [
path.resolve(__dirname, 'node_modules')
]
},
module: {
rules: [{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
}
}
}, {
test: /index\.html/,
use: [{
loader: 'file-loader',
options: {
name: 'index.[ext]'
}
}]
}]
}
};
import './index.html';
import React from 'react';
import ReactDom from 'react-dom';
import App from './App.jsx';
ReactDom.render(<App/>, document.querySelector('#root'));
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<meta charset="UTF-8">
<title>中建八局</title>
</head>
<body>
<div id="root"></div>
<script src="./app.js"></script>
</body>
</html>
import React from 'react';
import Header from './Header';
import Content from './Content';
import Sidebar from './Sidebar';
export default function App() {
return (
<div className="app">
<Header/>
<Sidebar/>
<Content/>
</div>
)
}
import React from 'react';
function Header() {
return (
<div className="header">
<div className="header-con">
<div className="user">
欢迎您!
</div>
</div>
</div>
)
}
export default Header;
import React from 'react';
export default function Sidebar() {
return (
<div className="sidebar">
<div className="title">
easterCat
</div>
</div>
)
}
import React from 'react';
export default function Content() {
return (
<div className="content">
this is content
</div>
)
}
<!--控制台执行webpack会在/dist中生成一个app.js和index.html-->
webpack
//webpack-dev-server配置
devServer: {
contentBase: './dist',
historyApiFallback: true,
inline: true,//源文件改变,会自动刷新页面
port: 1234,//设置默认监听端口,如果省略,默认为"8080"
},
"scripts": {
"start": "webpack-dev-server"
},
npm start
...
import './app.css'
module: {
rules: [
{
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}],
},
]
},
webpack
此时的css打包到js中,动态添加到index的style标签里面
npm install react-router-dom --save
import './index.html';
import './styles/app.less';
import React from 'react';
import ReactDom from 'react-dom';
import App from './components/App.jsx';
import {BrowserRouter, Route} from 'react-router-dom';
ReactDom.render(
<BrowserRouter>
<Route path="/" component={App}/>
</BrowserRouter>
,
document.getElementById('root')
);
import React from 'react';
import Home from './Home';
import Login from './Login';
import {Route} from 'react-router-dom';
class App extends React.Component {
componentDidMount() {
const {
location,
history
} = this.props;
if (location.pathname === '/home' || location.pathname === '/') {
history.replace('/home')
} else if (location.pathname === '/login') {
history.replace('/login')
}
}
render() {
return (
<div className="app">
<Route path="/home" component={Home}/>
<Route path="/login" component={Login}/>
</div>
)
}
}
export default App;
import React from 'react';
import {matchPath} from 'react-router-dom';
import Header from './Header';
import Content from './Content';
import Sidebar from './Sidebar';
import {Layout} from 'antd';
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
collapsed: false
};
this.ress = ['content01', 'content02', 'content03'];
this.res = null;
const match = matchPath(this.props.history.location.pathname, {
path: '/home/:res'
});
if (match) {
this.res = match.params.res;
}
this.toggle = () => {
this.setState({
collapsed: !this.state.collapsed
})
};
}
componentWillMount() {
if (!this.res || !this.res.length || this.ress.indexOf(this.res) === -1) {
this.props.history.replace(`/home/content01`)
}
}
render() {
return (
<Layout className="layout-app">
<Layout.Sider
trigger={null}
collapsible
collapsed={this.state.collapsed}
>
<Sidebar res= {this.res}/>
</Layout.Sider>
<Layout>
<Layout.Header style={{background: '#fff', padding: 0}}>
<Header collapsed={this.state.collapsed}
toggle={this.toggle}
/>
</Layout.Header>
<Layout.Content style={{margin: '24px 16px', padding: 24, background: '#fff', minHeight: 280}}>
<Content/>
</Layout.Content>
</Layout>
</Layout>
)
}
}
import React from 'react';
import {Form, Icon, Input, Button, Checkbox} from 'antd';
const FormItem = Form.Item;
class Logining extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = (e) => {
const {
history
} = this.props;
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
if (values.userName === 'admin' && values.password === '123456') {
history.replace('/home')
}
console.log('Received values of form: ', values);
}
});
}
}
render() {
const {
getFieldDecorator
} = this.props.form;
return (
<div className="login">
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{required: true, message: 'Please input your username!'}],
})(
<Input prefix={<Icon type="user" style={{fontSize: 13}}/>} placeholder="Username"/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{required: true, message: 'Please input your Password!'}],
})(
<Input prefix={<Icon type="lock" style={{fontSize: 13}}/>} type="password"
placeholder="Password"/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<a className="login-form-forgot" href="">Forgot password</a>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
Or <a href="">register now!</a>
</FormItem>
</Form>
</div>
);
}
}
const Login = Form.create()(Logining);
export default Login;
import React from 'react';
import {Menu, Icon} from 'antd';
import {NavLink} from 'react-router-dom';
export default class Sidebar extends React.Component {
render() {
const {
res
} = this.props;
return (
<div className="layout-sidebar">
<div className="logo"/>
<Menu theme="dark"
mode="inline"
defaultSelectedKeys={[res]}
>
<Menu.Item key="content01">
<NavLink to="/home/content01">
<Icon type="user"/>
<span>nav 1</span>
</NavLink>
</Menu.Item>
<Menu.Item key="content02">
<NavLink to="/home/content02">
<Icon type="video-camera"/>
<span>nav 2</span>
</NavLink>
</Menu.Item>
<Menu.Item key="content03">
<NavLink to="/home/content03">
<Icon type="upload"/>
<span>nav 3</span>
</NavLink>
</Menu.Item>
</Menu>
</div>
)
}
}
import React from 'react';
import {Route} from 'react-router-dom';
import Content01 from './content01';
import Content02 from './content02';
import Content03 from './content03';
export default class Content extends React.Component {
render() {
return (
<div>
<Route path="/home/Content01" component={Content01}/>
<Route path="/home/Content02" component={Content02}/>
<Route path="/home/Content03" component={Content03}/>
</div>
)
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<meta charset="UTF-8">
<title>hello world</title>
</head>
<body>
<div id="root"></div>
<script src="./app.js"></script>
</body>
</html>
npm i redux react-redux --save
import {createStore} from 'redux';
import user from '../components/content01.reducer';
const store = createStore(user);
export default store;
import {Provider} from 'react-redux';
import store from './store/store';
ReactDom.render(
<Provider store={store}>
<BrowserRouter>
<Route path="/" component={App}/>
</BrowserRouter>
</Provider>
,
document.getElementById('root')
);
let initState = {
data: [{
name: 'doudou',
age: 32,
phone: 123456789,
email: '[email protected]',
key: 1,
}]
};
function user(state = initState, action) {
const data = state.data;
switch (action.type) {
case 'ADD_ONE_USER':
data[data.length] = action.payload;
return {data: data};
default:
return state;
}
}
export default user;
export function addOneUser(value) {
return {
type: 'ADD_ONE_USER',
payload: value
}
}
import React from 'react';
import {Table, Icon, Button} from 'antd';
import {connect} from 'react-redux';
import {addOneUser} from './content01.action';
import FromContent from './FromContent';
class Content01 extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
date: null
};
this.showModal = () => {
this.setState({
visible: true,
data: new Date()
});
};
this.closeModal = () => {
this.setState({
visible: false,
});
};
this.submit = (values) => {
values.key = Date.parse(new Date());
this.props.addOneUser(values);
this.closeModal();
}
}
render() {
const columns = [{
title: '姓名',
dataIndex: 'name',
key: 'name',
}, {
title: '年龄',
dataIndex: 'age',
key: 'age',
}, {
title: '电话号码',
dataIndex: 'phone',
key: 'phone',
}, {
title: '邮箱',
dataIndex: 'email',
key: 'email',
}];
const data = this.props.data;
return (
<div>
<Button type="primary" onClick={this.showModal}>
<Icon type="user-add"/>添加
</Button>
<Table columns={columns} dataSource={data}/>
{
this.state.visible ? <FromContent date={this.state.date}
submit={this.submit}
showModal={this.showModal}
closeModal={this.closeModal}
/> : null
}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
data: state.data
}
};
const mapDispatchToProps = (dispatch) => {
return {
addOneUser: (value) => dispatch(addOneUser(value))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(Content01);
import React from 'react';
import {Modal, Button, Form, Input} from 'antd';
const FormItem = Form.Item;
import {increaseAction} from './content01.action';
class FromContent01 extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
this.props.submit(values);
}
});
}
}
render() {
const {getFieldDecorator} = this.props.form;
const {closeModal, date} = this.props;
return (
<Modal
title="添加一个成员"
key={date}
visible={true}
onCancel={closeModal}
footer={null}
>
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem label="姓名">
{getFieldDecorator('name', {
rules: [{required: true, message: 'Please input your name!'}],
})(
<Input placeholder="姓名"/>
)}
</FormItem>
<FormItem label="年龄">
{getFieldDecorator('age', {
rules: [{required: true, message: 'Please input your age!'}],
})(
<Input placeholder="年龄"/>
)}
</FormItem>
<FormItem label="电话号码">
{getFieldDecorator('phone', {
rules: [{
required: true, message: 'Please input your phone!',
}],
})(
<Input type="电话号码"/>
)}
</FormItem>
<FormItem label="邮箱">
{getFieldDecorator('email', {
rules: [{
required: true, message: 'Please input your email!',
}],
})(
<Input type="邮箱"/>
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
</FormItem>
</Form>
</Modal>
)
}
}
const FromContent = Form.create()(FromContent01);
export default FromContent;
import React from 'react';
import Avatar from '../images/avatar.jpg';
class Header extends React.Component {
render() {
return (
<div className="header">
<div className="header-con">
<div className="user">
<span className="text">欢迎您!</span>
<span className="avatar">
<img src={Avatar} alt="" />
</span>
</div>
</div>
</div>
)
}
}
export default Header;
module: {
rules: [
{
test: /.*\.(gif|png|jpe?g|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]'
}
}, {
loader: 'image-webpack-loader'
}]
},
]
},
<!--less和sass都用,此处用sass-->
npm install sass-loader node-sass --save-dev
module: {
rules:[{
test: /\.scss$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
outputStyle: 'expanded',
sourceMapContents: true
}
}]
},]
},
@import 'body';
@import 'header';
@import 'sidebar';
@import 'content';
<!--例:header.scss-->
.header {
position: fixed;
top: 0;
left: 150px;
right: 0;
padding: 0 30px;
height: 61px;
background: #ebebeb;
.user {
position: absolute;
right: 0;
top: 15px;
height: 30px;
line-height: 30px;
color: gray;
}
.header-con {
position: relative;
width: 100%;
height: 60px;
}
.text {
float: left;
height: 30px;
}
.avatar {
float: right;
width: 30px;
height: 30px;
img {
width: 100%;
height: 100%;
border-radius: 90%;
}
}
}
import '../style/app.css';
<!--修改为-->
import '../style/app.scss';
webpack
npm install less less-loader --save-dev
module: {
rules: [
{
test: /\.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'less-loader',
options: {
sourceMap: true,
outputStyle: 'expanded',
sourceMapContents: true,
}
}]
},
]
},
此时把文件后缀改成less再次编译运行
npm install antd --save
<!--babel-plugin-import必须要装-->
npm install babel-plugin-import --save-dev
<!--在App.js中引入-->
import 'antd/dist/antd.css' 或 import 'antd/dist/antd.less'
<!--在app.scss中引入-->
@import "~antd/dist/antd.css";
import React from 'react';
import Table from 'antd/lib/Table';
class Content extends React.Component {
render() {
const columns = [{
title: '姓名',
dataIndex: 'name',
key: 'name',
}, {
title: '年龄',
dataIndex: 'age',
key: 'age',
}, {
title: '电话号码',
dataIndex: 'number',
key: 'number',
}, {
title: '邮箱',
dataIndex: 'email',
key: 'email',
}];
const data = [];
for (let i = 1; i < 15; i++) {
let obj = {
name: 'doudou',
age: 32,
number: 123456789,
email: '[email protected]',
};
obj.key = i;
data.push(obj);
}
return (
<div className="content">
<Table columns={columns} dataSource={data}/>
</div>
)
}
}
export default Content;
从 antd 引入模块即可,无需引入样式,babel-plugin-import 会加载 JS 和 CSS
//.babelrc
{
"plugins": [
[
"import",
{
"libraryName": "antd",
"style": true //引入less,如果使用css文件就改为'css'
}
]
]
}
import {Table} from 'antd';
此时app.scss和App.js中引入的antd.css可以去掉了
如果在编译antd的样式文件报错,更换一个less,当前是@2.7.2
import React from 'react';
import Header from './layout/Header';
import Content from './layout/Content';
import Sidebar from './layout/Sidebar';
import '../style/app.scss';
import {Layout} from 'antd';
class App extends React.Component {
constructor() {
super();
this.state = {
collapsed: false
};
this.toggle = () => {
this.setState({
collapsed: !this.state.collapsed
})
};
}
render() {
return (
<Layout className="layout-app">
<Layout.Sider
trigger={null}
collapsible
collapsed={this.state.collapsed}
>
<Sidebar/>
</Layout.Sider>
<Layout>
<Layout.Header style={{background: '#fff', padding: 0}}>
<Header collapsed={this.state.collapsed}
toggle={this.toggle}
/>
</Layout.Header>
<Layout.Content style={{margin: '24px 16px', padding: 24, background: '#fff', minHeight: 280}}>
<Content/>
</Layout.Content>
</Layout>
</Layout>
)
}
}
export default App;
import React from 'react';
import avatar_img from '../../images/avatar.jpg';
import {Icon, Avatar} from 'antd';
class Header extends React.Component {
constructor(props) {
super(props);
}
render() {
const {
collapsed,
toggle
} = this.props;
return (
<div className="layout-header">
<Icon
className="trigger"
type={collapsed ? 'menu-unfold' : 'menu-fold'}
onClick={toggle}
/>
<Avatar className="avatar"
src={avatar_img}/>
</div>
)
}
}
export default Header;
import React from 'react';
import {Menu, Icon} from 'antd';
class Sidebar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="layout-sidebar">
<div className="logo"/>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
<Menu.Item key="1">
<Icon type="user"/>
<span>nav 1</span>
</Menu.Item>
<Menu.Item key="2">
<Icon type="video-camera"/>
<span>nav 2</span>
</Menu.Item>
<Menu.Item key="3">
<Icon type="upload"/>
<span>nav 3</span>
</Menu.Item>
</Menu>
</div>
)
}
}
export default Sidebar;
import React from 'react';
import {Table} from 'antd';
class Content extends React.Component {
render() {
const columns = [{
title: '姓名',
dataIndex: 'name',
key: 'name',
}, {
title: '年龄',
dataIndex: 'age',
key: 'age',
}, {
title: '电话号码',
dataIndex: 'number',
key: 'number',
}, {
title: '邮箱',
dataIndex: 'email',
key: 'email',
}];
const data = [];
for (let i = 1; i < 15; i++) {
let obj = {
name: 'doudou',
age: 32,
number: 123456789,
email: '[email protected]',
};
obj.key = i;
data.push(obj);
}
return (
<Table columns={columns} dataSource={data}/>
)
}
}
export default Content;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.