├── README.md
├── package.json
├── server.js
├── shot
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
└── 6.png
├── src
├── action
│ └── index.jsx
├── app.jsx
├── component
│ ├── About.jsx
│ ├── ArticleId.jsx
│ ├── Index.jsx
│ ├── Login.jsx
│ ├── Menu.jsx
│ ├── MsgList.jsx
│ ├── Register.jsx
│ ├── User.jsx
│ └── common
│ │ └── index.jsx
├── config
│ ├── config.jsx
│ ├── route.jsx
│ └── store.jsx
├── css
│ ├── images
│ │ └── user-bg.jpg
│ ├── resets.less
│ └── style.less
├── erweima.png
├── iconfont
│ ├── demo.css
│ ├── demo.html
│ ├── iconfont.css
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ └── iconfont.woff
├── lib
│ ├── GetNext
│ │ └── GetNext.js
│ └── Tool
│ │ └── Tool.jsx
└── reducer
│ └── index.jsx
├── start.bat
├── static
└── build
│ ├── app.css
│ ├── app.js
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── user-bg.jpg
├── webapp.html
└── webpack.config.js
/README.md:
--------------------------------------------------------------------------------
1 | # react-kelink
2 | ```
3 | 为柯林CMS建站系统定制的文章模块webapp
4 | 官网:http://kelink.com/
5 | ```
6 | ### 广告
7 | ```
8 | NodeJS前端分享群 133240225
9 | 深圳html5开发者社群 170761660
10 | ```
11 | ```
12 | 技术栈:
13 | 1.webpack
14 | 2.react
15 | 3.react-router
16 | 4.ES6
17 | 5.less
18 | 7.flex-css-layou
19 | 8.redux
20 | ```
21 | ### 编译流程
22 | ```
23 | 1.安装nodejs环境:https://nodejs.org/en/
24 | 2.打开cmd命令,移动到项目目录
25 | 3.执行cmd命令安装依赖模块: npm install
26 | 4.运行服务器:npm start
27 | 5.发布应用:webpack -p (注:首次使用webpack请先执行:npm install -g webpack)
28 | 6.修改代码自动编译:npm -w
29 | 7.浏览器访问:http://localhost:3000/
30 | ```
31 |
32 | 演示地址:http://meirongwu.cn/webapp.html
33 |
34 | ### 截图
35 | 
36 |
37 | 
38 |
39 | 
40 |
41 | 
42 |
43 | 
44 |
45 | 
46 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-kelink",
3 | "version": "1.0.3",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "node server",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/1340641314/react-kelink.git"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/1340641314/react-kelink/issues"
18 | },
19 | "homepage": "https://github.com/1340641314/react-kelink#readme",
20 | "dependencies": {
21 | "flex-css-layout": "^1.2.8",
22 | "react": "^15.0.1",
23 | "react-dom": "^15.0.1",
24 | "react-redux": "^4.4.5",
25 | "react-router": "^2.3.0",
26 | "redux": "^3.5.2",
27 | "redux-thunk": "^2.1.0"
28 | },
29 | "devDependencies": {
30 | "extract-text-webpack-plugin": "^1.0.1",
31 | "autoprefixer-loader": "^3.2.0",
32 | "babel-loader": "^6.2.4",
33 | "babel-preset-es2015": "^6.6.0",
34 | "babel-preset-react": "^6.5.0",
35 | "body-parser": "^1.15.1",
36 | "css-loader": "^0.23.1",
37 | "file-loader": "^0.8.5",
38 | "jsx-loader": "^0.13.2",
39 | "less": "^2.6.1",
40 | "less-loader": "^2.2.3",
41 | "request": "^2.72.0",
42 | "style-loader": "^0.13.1",
43 | "url-loader": "^0.5.7",
44 | "webpack": "^1.13.0",
45 | "webpack-dev-server": "^1.14.1"
46 | }
47 | }
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var bodyParser = require('body-parser');
3 | var request = require('request');
4 | var app = express();
5 |
6 |
7 | //设置静态文件目录
8 | app.use(express.static(__dirname + '/static'))
9 | app.use(bodyParser.json());
10 | app.use(bodyParser.urlencoded({
11 | extended: false
12 | }));
13 |
14 | //获取所有的栏目
15 | app.get('/wapindex.aspx', function (req, res) {
16 | request.get({
17 | url: 'http://xk-web.kelink.com/wapindex.aspx', qs: req.query
18 | }, function (err, httpResponse, body) {
19 | res.send(body);
20 | });
21 | });
22 |
23 | //获取文章列表
24 | app.get('/article/list.aspx', function (req, res) {
25 | request.get({
26 | url: 'http://xk-web.kelink.com/article/list.aspx', qs: req.query
27 | }, function (err, httpResponse, body) {
28 | res.send(body);
29 | });
30 | });
31 |
32 | //获取文章内容
33 | app.get('/article/view.aspx', function (req, res) {
34 |
35 | request.get({
36 | url: 'http://xk-web.kelink.com/article/view.aspx', qs: req.query
37 | }, function (err, httpResponse, body) {
38 | res.send(body);
39 | });
40 | });
41 |
42 | //登录
43 |
44 | app.post('/waplogin.aspx', function (req, res) {
45 | request.post({ url: 'http://xk-web.kelink.com/JsonAPI/waplogin.aspx', form: req.body }, function (err, httpResponse, body) {
46 | res.send(body);
47 | });
48 |
49 | });
50 |
51 | //设置任意路由都返回html
52 | app.get('*', function (req, res) {
53 | res.sendFile(__dirname + '/webapp.html')
54 | });
55 |
56 | //创建服务器
57 | app.listen(3000, function () {
58 | console.log('请在浏览器中打开:http://localhost:3000/')
59 | });
--------------------------------------------------------------------------------
/shot/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/1.png
--------------------------------------------------------------------------------
/shot/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/2.png
--------------------------------------------------------------------------------
/shot/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/3.png
--------------------------------------------------------------------------------
/shot/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/4.png
--------------------------------------------------------------------------------
/shot/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/5.png
--------------------------------------------------------------------------------
/shot/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/shot/6.png
--------------------------------------------------------------------------------
/src/action/index.jsx:
--------------------------------------------------------------------------------
1 | export default (_ID) => {
2 | const action = {};
3 |
4 | /*
5 | 开始加载数据
6 | */
7 | action.GET_DATA_START = (state) => {
8 | return { _ID, state, type: 'GET_DATA_START' };
9 | }
10 | /*
11 | 获取最新数据成功
12 | */
13 | action.GET_DATA_SUCCESS = (state) => {
14 | return { _ID, state, type: 'GET_DATA_SUCCESS' };
15 | }
16 |
17 | /*
18 | 获取最新数据失败
19 | */
20 | action.GET_DATA_ERROR = (state) => {
21 | return { _ID, state, type: 'GET_DATA_ERROR' };
22 | }
23 |
24 | /*
25 | 设置滚动条
26 | */
27 | action.SETSCROLL = (state) => {
28 | return { _ID, state, type: 'SETSCROLL' };
29 | }
30 |
31 | /*
32 | 更新classid
33 | */
34 | action.CLASSID_UPDATE = (state) => {
35 | return { _ID, state, type: 'CLASSID_UPDATE' };
36 | }
37 |
38 | return action;
39 | }
--------------------------------------------------------------------------------
/src/app.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { Provider } from 'react-redux'
4 | import route from './config/route';
5 | import store from './config/store';
6 | import './css/resets.less'; //重置浏览器默认样式
7 | // import './css/data-flex.min.css'; //css布局文件
8 | import 'flex-css-layout';
9 | import './css/style.less'; //css文件
10 | import './iconfont/iconfont.css'; //字体图标文件
11 |
12 | store.subscribe(function () {
13 | // console.log(store.getState());
14 | });
15 | ReactDOM.render(
16 |
17 | {route}
18 | ,
19 | document.body.appendChild(document.createElement('div'))
20 | );
--------------------------------------------------------------------------------
/src/component/About.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 | import erweima from '../erweima.png';
14 |
15 |
16 | class About extends Component {
17 | render() {
18 | return (
19 |
20 |
21 |
22 |
25 |
{config.indexTitle} {config.version}
26 |
27 |
28 |
29 | );
30 | }
31 | };
32 |
33 |
34 | export default About;
--------------------------------------------------------------------------------
/src/component/ArticleId.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Loading} from './common/index';
13 |
14 | class ArticleId extends Component {
15 | constructor(props) {
16 | super(props);
17 |
18 |
19 | this.state = {
20 | loadMsg: '正在加载中...',
21 | loadState: 0, //0 正在加载中, 1加载失败,2加载成功
22 | data: null
23 | };
24 |
25 |
26 | }
27 | render() {
28 | let main = null;
29 | let {loadState, loadMsg, title, data} = this.state;
30 | switch (loadState) {
31 | case 0:
32 | main = ();
33 | break;
34 | case 1:
35 | main = (加载失败
);
36 | case 2:
37 | main = ();
38 | break;
39 | }
40 |
41 | return (
42 |
43 |
44 | {main}
45 |
46 | );
47 | }
48 | componentDidMount() {
49 | this.ajax = Tool.get('/article/view.aspx', {
50 | output: 'json',
51 | siteid: config.siteid,
52 | id: this.props.params.id
53 | }, (data) => {
54 | this.setState({
55 | loadMsg: '加载完成',
56 | loadState: 2,
57 | data: data
58 | });
59 | }, () => {
60 | this.setState({
61 | loadMsg: '加载失败',
62 | loadState: 1
63 | });
64 | });
65 | }
66 | componentWillUnmount() {
67 | if (this.ajax) this.ajax.end();
68 | }
69 | };
70 |
71 | class View extends Component {
72 | render() {
73 | let {book_title, book_content, book_click} = this.props;
74 | return (
75 |
76 |
{book_title}
77 |
阅读:{book_click}
78 |
{}
79 |
80 | );
81 | }
82 | }
83 |
84 | export default ArticleId;
--------------------------------------------------------------------------------
/src/component/Index.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | react 相关
3 | */
4 | import React, {Component} from 'react';
5 | import {Link} from 'react-router';
6 |
7 | /*
8 | redux 相关
9 | */
10 | import { connect } from 'react-redux';
11 | import action from '../action/index';
12 |
13 | /*
14 | 公共react组件
15 | */
16 | import {Header, Footer, Loading} from './common/index';
17 |
18 | /*
19 | 相关的模块调用
20 | */
21 | import Tool from '../lib/Tool/Tool';
22 | import GetNext from '../lib/GetNext/GetNext';
23 | import config from '../config/config';
24 | /*
25 | 组件入口文件
26 | */
27 | class Index extends Component {
28 | constructor(props) {
29 | super(props);
30 | this.state = this.props.state;
31 | /*
32 | 初始化
33 | */
34 | this.initApp = (props, state) => {
35 | let {location} = props;
36 | this.classid = /^\d+$/.test(location.query.classid) ? location.query.classid : config.indexClassId; //如果没有栏目id传过来,默认为0
37 | location.query.classid = this.classid;
38 | if (!state.classid[this.classid]) {
39 | state.classid[this.classid] = Tool.merged(state.def); //没有指定栏目的数据库,将默认的复制过来给指定栏目id
40 | }
41 | }
42 |
43 | /*
44 | DOM更新完成
45 | */
46 | this.DOMLoad = (props, state) => {
47 | let {GET_DATA_START, GET_DATA_SUCCESS, GET_DATA_ERROR} = props;
48 | let classid = state.classid[this.classid];
49 | let data = {
50 | siteid: config.siteid,
51 | classid: this.classid,
52 | action: 'new',
53 | page: classid.page,
54 | output: 'json'
55 | };
56 | window.scrollTo(classid.scrollX, classid.scrollY); //设置滚动条位置
57 | if (!classid.getNextBtn) return false; //已经全部加载完成分页了,无需重新加载
58 | this.newGetNext = new GetNext(this.refs.dataload, {
59 | url: '/article/list.aspx',
60 | data: data,
61 | start: (el) => { //开始加载
62 | classid.loadState = 0;
63 | GET_DATA_START(state);
64 | },
65 | load: (data) => { //加载成功
66 | classid.page++;
67 | if (classid.data && data && classid.data[classid.data.length - 1].id == data[data.length - 1].id || !data) {
68 | classid.loadState = 2;
69 | classid.loadMsg = '没有了';
70 | classid.getNextBtn = false;
71 | this.newGetNext.end(); //结束分页插件
72 |
73 | if (!data) {
74 | classid.title = '';
75 | classid.loadMsg = '暂无记录';
76 | }
77 |
78 | return GET_DATA_SUCCESS(state);
79 |
80 | } else if (Tool.isArray(classid.data)) {
81 | Array.prototype.push.apply(classid.data, data);
82 | } else {
83 | classid.data = data;
84 | }
85 | classid.loadMsg = '上拉加载更多';
86 | classid.loadState = 2;
87 | if (this.classid === config.indexClassId) {
88 | classid.title = config.indexTitle;
89 | } else {
90 | classid.title = data[0].classname;
91 | }
92 |
93 | GET_DATA_SUCCESS(state);
94 | },
95 | error: () => { //加载失败
96 | classid.loadState = 1;
97 | classid.loadMsg = '加载失败';
98 | GET_DATA_ERROR(state);
99 | }
100 | });
101 | }
102 | /*
103 | 卸载前
104 | */
105 | this.unmount = (props, state) => {
106 | let { SETSCROLL} = props;
107 | let classid = state.classid[this.classid];
108 | classid.scrollX = window.scrollX;
109 | classid.scrollY = window.scrollY;
110 | SETSCROLL(state); //记录滚动条位置
111 |
112 | if (this.newGetNext) this.newGetNext.end(); //结束分页插件
113 | }
114 |
115 | this.initApp(this.props, this.state);
116 |
117 | }
118 | render() {
119 | let {loadState, title, data, loadMsg} = this.state.classid[this.classid];
120 | let main = null;
121 | if (Tool.isArray(data)) {
122 | main = ();
123 | }
124 | let index = 0;
125 | let leftTo = null;
126 | let leftIcon = null;
127 | if (this.classid !== config.indexClassId) {
128 | index = 1;
129 | leftTo = '/Menu';
130 | leftIcon = 'fanhui';
131 | }
132 |
133 | return (
134 |
135 |
136 | {main}
137 |
138 |
140 | );
141 | }
142 | componentDidMount() {
143 | this.DOMLoad(this.props, this.state);
144 | }
145 | shouldComponentUpdate(nextProps, nextState) {
146 | if (nextProps.location.query.classid !== this.classid) {
147 | this.unmount(this.props, this.state); //卸载前一个栏目相关信息
148 |
149 | this.initApp(nextProps, nextState);
150 | this.props.CLASSID_UPDATE(this.state);
151 | this.classidBtn = true;
152 | return false;
153 | }
154 |
155 | return true;
156 | }
157 | componentDidUpdate() {
158 | if (this.classidBtn) {
159 | this.DOMLoad(this.props);
160 | this.classidBtn = false;
161 | }
162 | }
163 | componentWillUnmount() {
164 | this.unmount(this.props, this.state);
165 | }
166 | };
167 |
168 | /*
169 | 文章列表
170 | */
171 | export class ArticleList extends Component {
172 | render() {
173 | return (
174 |
175 | {
176 | this.props.list.map((item, index) => {
177 | let {id, book_title, book_content, book_click, classname, book_classid, book_img} = item;
178 | book_content = book_content.substring(0, 50) + '...';
179 | let images = null;
180 | if (/^http/.test(book_img)) {
181 | images = (
182 |
183 | );
184 | }
185 |
186 | return (
187 | -
188 |
189 | {images}
190 |
{book_title}
191 | {book_content}
192 |
193 |
194 |
阅读:{book_click}
195 |
196 | {classname}
197 |
198 |
199 |
200 | )
201 | })
202 | }
203 |
204 | );
205 | }
206 | }
207 |
208 | export default connect((state) => { return { state: state.classNewList }; }, action('classNewList'))(Index); //连接redux
--------------------------------------------------------------------------------
/src/component/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 |
14 |
15 | export default class Login extends Component {
16 | constructor(props) {
17 | super(props);
18 |
19 | this.state = {
20 | logname: '',
21 | logpass: '',
22 | action: 'login',
23 | classid: config.indexClassId,
24 | siteid: config.siteid
25 | };
26 |
27 | this.submit = () => {
28 | Tool.post('/JsonAPI/waplogin.aspx', this.state, (text) => {
29 | alert(text);
30 | console.log(text);
31 | }, () => {
32 | console.log('登录失败');
33 | });
34 | }
35 |
36 | }
37 | render() {
38 | let {logname, logpass} = this.state;
39 | return (
40 |
41 |
42 |
43 |
44 |
45 |
用
46 |
户
47 |
名
48 |
49 |
50 | { this.state.logname = e.target.value; } } />
51 |
52 |
53 |
54 |
58 |
59 | { this.state.logpass = e.target.value; } } />
60 |
61 |
62 |
登录
63 |
64 |
65 | );
66 | }
67 | componentDidMount() {
68 | window.scrollTo(0, 0);
69 | }
70 | };
--------------------------------------------------------------------------------
/src/component/Menu.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 |
14 | class Menu extends Component {
15 | constructor(props) {
16 | super(props);
17 | /*
18 | DOM 更新完成后执行方法
19 | */
20 | this.DOMLoad = (props) => {
21 | let {state, GET_DATA_SUCCESS, GET_DATA_ERROR} = this.props;
22 | window.scrollTo(state.scrollX, state.scrollY); //设置滚动条位置
23 | if (state.loadState !== 2) {
24 | this.ajax = Tool.get('/wapindex.aspx', { output: 'json', siteid: config.siteid, classid: config.indexClassId }, GET_DATA_SUCCESS, GET_DATA_ERROR);
25 | }
26 | }
27 |
28 | this.unmount = (props, state) => {
29 |
30 | if (this.ajax) this.ajax.end(); //解除ajax相关
31 | this.props.SETSCROLL();
32 | }
33 |
34 | }
35 | render() {
36 | let main = null;
37 | let {loadState, loadMsg, data} = this.props.state;
38 | switch (loadState) {
39 | case 0:
40 | main = ();
41 | break;
42 | case 1:
43 | main = (加载失败
);
44 | case 2:
45 | main = ();
46 | break;
47 | }
48 | return (
49 |
50 |
51 | {main}
52 |
53 |
54 | );
55 | }
56 | componentDidMount() {
57 | this.DOMLoad(this.props);
58 | }
59 | componentWillUnmount() {
60 | this.unmount(this.props);
61 | }
62 | };
63 |
64 | class MenuList extends Component {
65 | render() {
66 | return (
67 |
82 | );
83 | }
84 | }
85 |
86 | export default connect((state) => { return { state: state.classMenuList }; }, action('classMenuList'))(Menu); //连接redux
--------------------------------------------------------------------------------
/src/component/MsgList.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 |
14 | /**
15 | * (上拉加载box)
16 | *
17 | * @class DrawLoad
18 | * @extends {Component}
19 | */
20 | class DrawLoad extends Component {
21 | constructor(props) {
22 | super(props);
23 | console.log(this.props);
24 | }
25 | render() {
26 | return (
27 |
28 | {this.props.children[0]}
29 | {this.props.children[1]}
30 | {this.props.children[3]}
31 |
32 | );
33 | }
34 | }
35 |
36 | /**
37 | * (上拉加载没有数据时,显示组件)
38 | *
39 | * @class DrawLoadDataNo
40 | * @extends {Component}
41 | */
42 | class DrawLoadDataNo extends Component {
43 | constructor(props) {
44 | super(props);
45 | console.log(this.props);
46 | }
47 | render() {
48 | return this.props.children;
49 | }
50 | }
51 | /**
52 | * (上拉加载有数据时显示组件)
53 | *
54 | * @class DrawLoadDataYes
55 | * @extends {Component}
56 | */
57 | class DrawLoadDataYes extends Component {
58 | constructor(props) {
59 | super(props);
60 | console.log(this.props);
61 | }
62 | render() {
63 | return this.props.children;
64 | }
65 | }
66 |
67 | /**
68 | * (触发加载机制的box)
69 | *
70 | * @class DrawLoadState
71 | * @extends {Component}
72 | */
73 | class DrawLoadState extends Component {
74 | constructor(props) {
75 | super(props);
76 | console.log(this.props);
77 | }
78 | render() {
79 | return this.props.children;
80 | }
81 | }
82 |
83 | export default class MsgList extends Component {
84 | constructor(props) {
85 | super(props);
86 | this.start = () => {
87 | console.log('开始加载');
88 | }
89 | this.success = () => {
90 | console.log('加载成功');
91 | }
92 | this.error = () => {
93 | console.log('开始加载');
94 | }
95 | }
96 | render() {
97 | return (
98 |
99 |
107 | 循环列表
108 | 没有数据
109 | 上拉加载更多
110 |
111 |
112 | );
113 | }
114 | }
--------------------------------------------------------------------------------
/src/component/Register.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 |
14 |
15 | export default class Register extends Component {
16 | constructor(props) {
17 | super(props);
18 |
19 | this.state = {
20 | output: 'json',
21 | tousername: '', //手机号码
22 | tonickname: '', // 昵称
23 | topassword: '', //密码
24 | toemail: '', //邮箱
25 | tosex: '0', //性别,0女,1男
26 | codecheck: '4000', //验证码
27 | classid: config.indexClassId,
28 | siteid: config.siteid,
29 | sid: '-2-0-0-0-0',
30 | backurl: '' //来源地址
31 | };
32 |
33 | this.submit = () => {
34 | Tool.post('/waplogin.aspx', this.state, (text) => {
35 | alert(text);
36 | console.log(text);
37 | }, () => {
38 | console.log('登录失败');
39 | });
40 | }
41 |
42 | }
43 | render() {
44 | let {logname, logpass} = this.state;
45 | return (
46 |
47 |
48 |
49 |
50 |
54 |
55 | { this.state.logname = e.target.value; } } />
56 |
57 |
58 |
59 |
63 |
64 | { this.state.logname = e.target.value; } } />
65 |
66 |
67 |
68 |
72 |
73 | { this.state.logname = e.target.value; } } />
74 |
75 |
76 |
77 |
81 |
82 | { this.state.logpass = e.target.value; } } />
83 |
84 |
85 |
86 |
87 |
验
88 |
证
89 |
码
90 |
91 |
92 | { this.state.logpass = e.target.value; } } />
93 |
94 |
95 |
111 |
注册
112 |
113 |
114 | );
115 | }
116 | componentDidMount() {
117 | window.scrollTo(0, 0);
118 | }
119 | };
--------------------------------------------------------------------------------
/src/component/User.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | redux 相关
6 | */
7 | import { connect } from 'react-redux';
8 | import action from '../action/index';
9 |
10 | import Tool from '../lib/Tool/Tool';
11 | import config from '../config/config';
12 | import {Header, Footer, Loading} from './common/index';
13 | import erweima from '../erweima.png';
14 |
15 |
16 | class User extends Component {
17 | render() {
18 | return (
19 |
20 |
21 |
22 |
28 |
29 |
30 | 登录
31 |
32 |
33 | 注册
34 |
35 |
36 |
37 | -
38 |
39 |
40 |
41 |
42 | 我的文章
43 |
44 |
45 |
46 |
47 |
48 | -
49 |
50 |
51 |
52 |
53 | 我的消息
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | 设置
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | 联系我们
80 |
81 |
82 |
83 |
84 |
85 | -
86 |
87 |
88 |
89 |
90 | 关于
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | );
101 | }
102 | };
103 | export default User;
--------------------------------------------------------------------------------
/src/component/common/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Link} from 'react-router';
3 |
4 | /*
5 | 全局公共头部
6 | */
7 | export class Header extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 | render() {
12 | let {title, leftTo, leftIcon, rightTo, rightIcon } = this.props;
13 | let left = null;
14 |
15 | if (leftTo && leftIcon) {
16 | left = (
17 |
18 |
19 |
20 | );
21 | } else if (leftIcon === 'fanhui') { //返回上一页
22 | left = (
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | let right = null;
30 |
31 | if (rightTo && rightIcon) {
32 | right = (
33 |
34 |
35 |
36 | );
37 | }
38 |
39 | return (
40 |
41 |
42 | {left}
43 |
44 | {title}
45 |
46 | {right}
47 |
48 |
49 | )
50 | }
51 | }
52 | Header.contextTypes = {
53 | router: React.PropTypes.object.isRequired
54 | }
55 | /*
56 | loading 加载动画
57 | */
58 | export class Loading extends Component {
59 | render() {
60 | return (
61 |
62 |
{this.props.loadMsg}
63 |
64 | );
65 | }
66 | }
67 |
68 | export class Footer extends Component {
69 | render() {
70 | let arr = [];
71 | arr[this.props.index] = 'on';
72 | return (
73 |
93 | );
94 | }
95 | }
--------------------------------------------------------------------------------
/src/config/config.jsx:
--------------------------------------------------------------------------------
1 | const config = {};
2 |
3 | config.version = '1.0.4'
4 |
5 | config.indexTitle = '柯林 Article APP'; //首页标题
6 |
7 | config.siteid = '1000'; //默认网站id
8 |
9 | config.indexClassId = '0'; //程序默认的栏目id
10 |
11 |
12 | export default config;
--------------------------------------------------------------------------------
/src/config/route.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component } from 'react';
2 | import { Router, Route, IndexRoute, browserHistory, hashHistory } from 'react-router';
3 | import Index from '../component/Index';
4 | import ArticleId from '../component/ArticleId';
5 | import Menu from '../component/Menu';
6 | import About from '../component/About';
7 | import User from '../component/User';
8 | import Login from '../component/Login';
9 | import Register from '../component/Register';
10 | import MsgList from '../component/MsgList';
11 |
12 |
13 | class Main extends Component {
14 | render() {
15 | return (
16 | {this.props.children}
17 | );
18 | }
19 | };
20 | const route = (
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 |
35 | export default route;
--------------------------------------------------------------------------------
/src/config/store.jsx:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware} from 'redux';
2 | import reducer from '../reducer/';
3 | import thunk from 'redux-thunk';
4 |
5 | //创建一个 Redux store 来以存放应用中所有的 state,应用中应有且仅有一个 store。
6 | var store = createStore(
7 | combineReducers(reducer),
8 | applyMiddleware(thunk)
9 | );
10 |
11 | export default store;
--------------------------------------------------------------------------------
/src/css/images/user-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/src/css/images/user-bg.jpg
--------------------------------------------------------------------------------
/src/css/resets.less:
--------------------------------------------------------------------------------
1 | //out:null
2 |
3 |
4 | html,
5 | body,
6 | div,
7 | ul,
8 | li,
9 | p,
10 | footer,
11 | header,
12 | article,
13 | a,
14 | b,
15 | em,
16 | nav,
17 | form,
18 | input,
19 | textarea,
20 | select,
21 | button,
22 | i,
23 | h1,
24 | h2,
25 | h3,
26 | h4,
27 | h5,
28 | h6 {
29 | padding: 0;
30 | margin: 0;
31 | border: none;
32 | list-style: none;
33 | text-decoration: none;
34 | box-sizing: border-box;
35 | }
36 |
37 | input,
38 | textarea,
39 | button {
40 | &:focus {
41 | outline: none;
42 | }
43 | }
44 |
45 | body {
46 | font: 14px/1.5 "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;
47 | color: #040404;
48 | background: #eee;
49 | }
50 |
51 | html,
52 | body {
53 | width: 100%;
54 | height: 100%;
55 | -webkit-text-size-adjust: 100%;
56 | }
57 |
58 | header,
59 | nav,
60 | footer,
61 | article {
62 | display: block;
63 | }
64 |
65 | a {
66 | background-color: transparent;
67 | -webkit-text-decoration-skip: objects;
68 | }
69 |
70 | a:active,
71 | a:hover {
72 | outline-width: 0;
73 | }
74 |
75 | ::-webkit-input-placeholder {
76 | color: inherit;
77 | opacity: 0.54;
78 | }
79 |
80 | ::-webkit-file-upload-button {
81 | -webkit-appearance: button;
82 | font: inherit;
83 | }
84 |
85 | .scrolling {
86 | overflow-y: scroll!important;
87 | -webkit-overflow-scrolling: touch!important;
88 | }
89 |
90 | .red {
91 | color: red;
92 | }
93 |
94 | img {
95 | border: none;
96 | max-width: 100%;
97 | }
98 |
--------------------------------------------------------------------------------
/src/css/style.less:
--------------------------------------------------------------------------------
1 | //out: null
2 | @main-color: red;
3 |
4 | /*
5 | 公共头部
6 | */
7 |
8 | .common-header {
9 | height: 50px;
10 | z-index: 999;
11 | position: relative;
12 | background: @main-color;
13 | animation: move-down 0.3s ease-out;
14 | .icon {
15 | width: 50px;
16 | height: 50px;
17 | a {
18 | display: block;
19 | color: #fff;
20 | }
21 | }
22 | .iconfont {
23 | font-size: 24px;
24 | }
25 | .title {
26 | line-height: 50px;
27 | text-align: center;
28 | color: #fff;
29 | font-size: 16px;
30 | }
31 | }
32 |
33 | @keyframes move-down {
34 | 0% {
35 | transform: translate(0, -10px);
36 | }
37 | 100% {
38 | transform: translate(0, 0);
39 | }
40 | }
41 |
42 |
43 | /*
44 | 文章列表
45 | */
46 |
47 | .article-list {
48 | li {
49 | padding: 10px;
50 | margin-bottom: 10px;
51 | box-shadow: 1px 1px 3px #ccc;
52 | background: #fff;
53 | &+li {
54 | border-top: 1px solid #eee;
55 | }
56 | }
57 | h3 {
58 | color: #222;
59 | }
60 | .content {
61 | font-size: 13px;
62 | color: #999;
63 | }
64 | .bottom {
65 | padding-top: 5px;
66 | .click {
67 | font-size: 12px;
68 | color: #ccc;
69 | }
70 | .to {
71 | a {
72 | font-size: 12px;
73 | color: #1a43a8;
74 | }
75 | }
76 | }
77 | .pictrue {
78 | // height: 160px;
79 | margin-bottom: 10px;
80 | background-size: cover;
81 | background-position: center center;
82 | }
83 | }
84 |
85 |
86 | /*
87 | 数据正在加载中
88 | */
89 |
90 | .data-load-0 {
91 | margin: 20px auto 20px auto;
92 | position: relative;
93 | animation: rotate-forever 1s infinite linear;
94 | height: 30px;
95 | width: 30px;
96 | border: 4px solid @main-color;
97 | border-right-color: transparent;
98 | border-radius: 50%;
99 | .msg {
100 | display: none;
101 | }
102 | }
103 |
104 | .data-load {
105 | .msg {
106 | line-height: 70px;
107 | text-align: center;
108 | font-size: 14px;
109 | }
110 | }
111 |
112 | @keyframes rotate-forever {
113 | 0% {
114 | transform: rotate(0deg)
115 | }
116 | 100% {
117 | transform: rotate(360deg)
118 | }
119 | }
120 |
121 |
122 | /*
123 | 分类
124 | */
125 |
126 | .class {
127 | overflow: hidden;
128 | background: #fff;
129 | ul {
130 | overflow: hidden;
131 | padding: 10px 10px 0 10px;
132 | }
133 | li {
134 | float: left;
135 | width: 25%;
136 | margin-bottom: 10px;
137 | a {
138 | display: block;
139 | text-align: center;
140 | font-size: 14px;
141 | font-weight: bolder;
142 | color: #222;
143 | }
144 | }
145 | }
146 |
147 |
148 | /*
149 | 文章详情
150 | */
151 |
152 | .article-view {
153 | padding: 10px;
154 | h2 {
155 | font-weight: bolder;
156 | font-size: 16px;
157 | color: #222;
158 | }
159 | .yue {
160 | text-align: right;
161 | font-size: 12px;
162 | color: #999;
163 | }
164 | article {
165 | padding: 10px 0;
166 | font-size: 14px;
167 | color: #666;
168 | }
169 | }
170 |
171 |
172 | /*
173 | 关于我们
174 | */
175 |
176 | .about {
177 | padding: 40px;
178 | text-align: center;
179 | font-size: 14px;
180 | color: #666;
181 | .pictrue {
182 | overflow: hidden;
183 | width: 200px;
184 | height: 200px;
185 | margin: 0 auto;
186 | img {
187 | width: inherit;
188 | height: inherit;
189 | border: none;
190 | }
191 | }
192 | .info {
193 | padding-top: 20px;
194 | }
195 | a {
196 | color: #3290e6;
197 | }
198 | }
199 |
200 |
201 | /*
202 | 底部菜单栏
203 | */
204 |
205 | .common-footer {
206 | .zhanwei {
207 | height: 50px;
208 | }
209 | .menu {
210 | position: fixed;
211 | right: 0;
212 | bottom: 0;
213 | left: 0;
214 | height: 50px;
215 | z-index: 999;
216 | background: @main-color;
217 | a {
218 | padding: 5px 0;
219 | font-size: 14px;
220 | display: block;
221 | line-height: 20px;
222 | text-align: center;
223 | color: #fff;
224 | opacity: 0.8;
225 | text-align: center;
226 | }
227 | .on {
228 | a {
229 | opacity: 1;
230 | color: #ebff00;
231 | }
232 | }
233 | .iconfont {
234 | display: block;
235 | }
236 | }
237 | }
238 |
239 |
240 | /*
241 | 登录注册
242 | */
243 |
244 | .login {
245 | padding: 100px 0;
246 | .line {
247 | padding: 10px 10%;
248 | .key {
249 | width: 50px;
250 | padding-right: 10px;
251 | line-height: 34px;
252 | font-size: 14px;
253 | }
254 | .value {
255 | font-size: 14px;
256 | overflow: hidden;
257 | padding: 5px 10px;
258 | border-radius: 5px;
259 | background: #fff;
260 | input {
261 | width: 100%;
262 | line-height: 24px;
263 | background: transparent;
264 | }
265 | }
266 | .select {
267 | line-height: 34px;
268 | .iconfont {
269 | display: inline-block;
270 | width: 26px;
271 | font-size: 24px;
272 | }
273 | .icon-xuanzhong {
274 | color: @main-color;
275 | }
276 | }
277 | }
278 | .btn {
279 | margin: 50px 10%;
280 | font-size: 16px;
281 | font-weight: bolder;
282 | line-height: 38px;
283 | border-radius: 8px;
284 | text-align: center;
285 | color: #fff;
286 | background: @main-color;
287 | }
288 | }
289 |
290 |
291 | /*
292 | 个人中心
293 | */
294 |
295 | .user {
296 | .head {
297 | margin: -50px 0 0 0;
298 | .headimg {
299 | height: 250px;
300 | padding-top: 50px;
301 | background-image: url(images/user-bg.jpg);
302 | background-size: cover;
303 | background-position: center center;
304 | .pictrue {
305 | overflow: hidden;
306 | width: 80px;
307 | height: 80px;
308 | border-radius: 50%;
309 | box-shadow: 0 0 10px #fff, 0 0 20px #000;
310 | background-size: cover;
311 | background-position: center center;
312 | }
313 | .name {
314 | padding-top: 10px;
315 | font-size: 16px;
316 | font-weight: bolder;
317 | color: rgba(255, 255, 255, 0.9);
318 | }
319 | }
320 | }
321 | .logins {
322 | margin-top: 20px;
323 | height: 38px;
324 | .item {
325 | padding: 0 20px;
326 | a {
327 | display: block;
328 | line-height: 38px;
329 | font-size: 14px;
330 | font-weight: bolder;
331 | text-align: center;
332 | border-radius: 8px;
333 | color: #fff;
334 | background: @main-color;
335 | }
336 | }
337 | }
338 | .nav {
339 | overflow: hidden;
340 | margin: 20px 0;
341 | background: #fff;
342 | li {
343 | padding: 5px 10px;
344 | &+li {
345 | border-top: 1px solid #eee;
346 | }
347 | a {
348 | height: 38px;
349 | line-height: 38px;
350 | font-size: 14px;
351 | color: #666;
352 | .font {
353 | width: 40px;
354 | .iconfont {
355 | font-size: 24px;
356 | }
357 | }
358 | .arrow {
359 | color: #ddd;
360 | }
361 | }
362 | }
363 | }
364 | }
--------------------------------------------------------------------------------
/src/erweima.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/src/erweima.png
--------------------------------------------------------------------------------
/src/iconfont/demo.css:
--------------------------------------------------------------------------------
1 | *{margin: 0;padding: 0;list-style: none;}
2 | /*
3 | KISSY CSS Reset
4 | 理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
5 | 2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
6 | 3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
7 | 特色:1. 适应中文;2. 基于最新主流浏览器。
8 | 维护:玉伯, 正淳
9 | */
10 |
11 | /** 清除内外边距 **/
12 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
13 | dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
14 | pre, /* text formatting elements 文本格式元素 */
15 | form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
16 | th, td /* table elements 表格元素 */ {
17 | margin: 0;
18 | padding: 0;
19 | }
20 |
21 | /** 设置默认字体 **/
22 | body,
23 | button, input, select, textarea /* for ie */ {
24 | font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
25 | }
26 | h1, h2, h3, h4, h5, h6 { font-size: 100%; }
27 | address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
28 | code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
29 | small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
30 |
31 | /** 重置列表元素 **/
32 | ul, ol { list-style: none; }
33 |
34 | /** 重置文本格式元素 **/
35 | a { text-decoration: none; }
36 | a:hover { text-decoration: underline; }
37 |
38 |
39 | /** 重置表单元素 **/
40 | legend { color: #000; } /* for ie6 */
41 | fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
42 | button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
43 | /* 注:optgroup 无法扶正 */
44 |
45 | /** 重置表格元素 **/
46 | table { border-collapse: collapse; border-spacing: 0; }
47 |
48 | /* 清除浮动 */
49 | .ks-clear:after, .clear:after {
50 | content: '\20';
51 | display: block;
52 | height: 0;
53 | clear: both;
54 | }
55 | .ks-clear, .clear {
56 | *zoom: 1;
57 | }
58 |
59 | .main {padding: 30px 100px;}
60 | .main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
61 |
62 | .helps{margin-top:40px;}
63 | .helps pre{
64 | padding:20px;
65 | margin:10px 0;
66 | border:solid 1px #e7e1cd;
67 | background-color: #fffdef;
68 | overflow: auto;
69 | }
70 |
71 | .icon_lists li{
72 | float:left;
73 | width: 100px;
74 | height:180px;
75 | text-align: center;
76 | }
77 | .icon_lists .icon{
78 | font-size: 42px;
79 | line-height: 100px;
80 | margin: 10px 0;
81 | color:#333;
82 | -webkit-transition: font-size 0.25s ease-out 0s;
83 | -moz-transition: font-size 0.25s ease-out 0s;
84 | transition: font-size 0.25s ease-out 0s;
85 |
86 | }
87 | .icon_lists .icon:hover{
88 | font-size: 100px;
89 | }
90 |
--------------------------------------------------------------------------------
/src/iconfont/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | IconFont
7 |
8 |
9 |
10 |
11 |
12 |
IconFont 图标
13 |
14 |
15 | -
16 |
17 |
主页
18 | 
19 | .zhuye
20 |
21 |
22 | -
23 |
24 |
菜单
25 | 
26 | .caidan
27 |
28 |
29 | -
30 |
31 |
个人中心
32 | 
33 | .gerenzhongxin
34 |
35 |
36 | -
37 |
38 |
关于
39 | 
40 | .guanyu
41 |
42 |
43 | -
44 |
45 |
未选中
46 | 
47 | .weixuanzhong
48 |
49 |
50 | -
51 |
52 |
消息
53 | 
54 | .xiaoxi
55 |
56 |
57 | -
58 |
59 |
设置
60 | 
61 | .shezhi
62 |
63 |
64 | -
65 |
66 |
返回
67 | 
68 | .fanhui
69 |
70 |
71 | -
72 |
73 |
文章
74 | 
75 | .wenzhang
76 |
77 |
78 | -
79 |
80 |
箭头
81 | 
82 | .arrow-right
83 |
84 |
85 | -
86 |
87 |
联系2big
88 | 
89 | .lianxi
90 |
91 |
92 | -
93 |
94 |
选中
95 | 
96 | .xuanzhong
97 |
98 |
99 |
100 |
101 |
102 |
103 | 第一步:使用font-face声明字体
104 |
105 | @font-face {font-family: 'iconfont';
106 | src: url('iconfont.eot'); /* IE9*/
107 | src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
108 | url('iconfont.woff') format('woff'), /* chrome、firefox */
109 | url('iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
110 | url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
111 | }
112 |
113 | 第二步:定义使用iconfont的样式
114 |
115 | .iconfont{
116 | font-family:"iconfont" !important;
117 | font-size:16px;font-style:normal;
118 | -webkit-font-smoothing: antialiased;
119 | -webkit-text-stroke-width: 0.2px;
120 | -moz-osx-font-smoothing: grayscale;}
121 |
122 | 第三步:挑选相应图标并获取字体编码,应用于页面
123 |
124 | <i class="iconfont">3</i>
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/src/iconfont/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "iconfont";
3 | src: url('iconfont.eot?t=1465547032'); /* IE9*/
4 | src: url('iconfont.eot?t=1465547032#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('iconfont.woff?t=1465547032') format('woff'), /* chrome, firefox */
6 | url('iconfont.ttf?t=1465547032') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1465547032#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family:"iconfont" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -webkit-text-stroke-width: 0.2px;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 | .icon-zhuye:before { content: "\e601"; }
19 | .icon-caidan:before { content: "\e600"; }
20 | .icon-gerenzhongxin:before { content: "\e604"; }
21 | .icon-guanyu:before { content: "\e603"; }
22 | .icon-weixuanzhong:before { content: "\e60a"; }
23 | .icon-xiaoxi:before { content: "\e608"; }
24 | .icon-shezhi:before { content: "\e606"; }
25 | .icon-fanhui:before { content: "\e602"; }
26 | .icon-wenzhang:before { content: "\e609"; }
27 | .icon-arrow-right:before { content: "\e605"; }
28 | .icon-lianxi:before { content: "\e607"; }
29 | .icon-xuanzhong:before { content: "\e60c"; }
30 |
--------------------------------------------------------------------------------
/src/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/src/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/src/iconfont/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
75 |
--------------------------------------------------------------------------------
/src/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/src/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/src/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/src/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/src/lib/GetNext/GetNext.js:
--------------------------------------------------------------------------------
1 | !(function(GetNext) {
2 | if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
3 |
4 | define(GetNext);
5 | } else if (typeof module !== 'undefined' && module.exports) {
6 | module.exports = GetNext();
7 | } else {
8 | window.GetNext = GetNext();
9 | }
10 | })(function() {
11 | function GetNext(select, set) {
12 | this.el = getEl(select); //选择元素触发加载分页的元素
13 | /*
14 | 元素在可视区位置,符合其中一个条件就会触发加载机制
15 | */
16 | this.top = set.top || 0; //元素在顶部伸出的距离才加载
17 | this.right = set.right || 0; //元素在右边伸出的距离才加载
18 | this.bottom = set.bottom || 0; //元素在底部伸出的距离才加载
19 | this.left = set.left || 0; //元素在左边伸出的距离才加载
20 | this.dataType = 'json';
21 | /*
22 | 发送到服务器的相关数据
23 | */
24 | this.url = set.url || location.pathname; //发送到服务器的地址
25 | this.data = set.data || {}; //发送到服务器的数据
26 | this.pageName = set.pageName || 'page'; //分页的参数名称,用来加载完成后+1
27 | /*
28 | 回调方法
29 | */
30 | this.startCall = set.start || function() {}; //开始加载时调用方法
31 | this.loadCall = set.load || function() {}; //加载成功时调用方法
32 | this.errorCall = set.error || function() {}; //开始加载时调用方法
33 | this.endCall = set.end || function() {}; //加载完成时调用方法
34 |
35 | //监听的事件列表
36 | this.monitorEvent = ['DOMContentLoaded', 'load', 'click', 'touchstart', 'touchend', 'haschange', 'online', 'pageshow', 'popstate', 'resize', 'storage', 'mousewheel', 'scroll'];
37 | /*
38 | 存储http请求对象
39 | */
40 | this.xhr = null;
41 | /*
42 | 页面初始化
43 | */
44 | this.init();
45 | };
46 |
47 | /**
48 | * 初始化插件
49 | */
50 | GetNext.prototype.init = function() {
51 | this.eachDOM = this.eachDOM.bind(this);
52 | this.readystatechange = this.readystatechange.bind(this);
53 | this.start();
54 | };
55 |
56 | GetNext.prototype.start = function() {
57 | //事件绑定
58 | var eventList = this.monitorEvent;
59 | for (let i = 0; i < eventList.length; i++) {
60 | window.addEventListener(eventList[i], this.eachDOM, false);
61 | }
62 | this.eachDOM();
63 | };
64 | /**
65 | * 卸载插件
66 | */
67 | GetNext.prototype.end = function() {
68 | var eventList = this.monitorEvent;
69 | for (let i = 0; i < eventList.length; i++) {
70 | window.removeEventListener(eventList[i], this.eachDOM, false);
71 | }
72 |
73 | if (this.xhr) this.xhr.removeEventListener('readystatechange', this.readystatechange, false);
74 | };
75 |
76 | /**
77 | * 遍历DOM查询是否符合加载条件
78 | */
79 | GetNext.prototype.eachDOM = function() {
80 |
81 | if (this.testXhrStart()) return;
82 | let length = this.el.length;
83 | for (let i = 0; i < length; i++) {
84 | if (this.testMeet(this.el[i]) === true) {
85 | this.getNextData(this.el[i]);
86 | return;
87 | }
88 |
89 | }
90 | };
91 | /**
92 | * 获取下一页数据
93 | * @param {object} el 触发事件的元素
94 | */
95 | GetNext.prototype.getNextData = function(el) {
96 | if (this.testXhrStart()) return;
97 | this.startCall(el);
98 | let url = this.getUrl();
99 | this.xhr = new XMLHttpRequest(); //创建http请求对象
100 | this.xhr.open('GET', url, true); //异步请求
101 | this.xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
102 | this.xhr.addEventListener('readystatechange', this.readystatechange, false);
103 | this.xhr.send(); //发送请求
104 |
105 | };
106 |
107 | /**
108 | * http请求
109 | */
110 | GetNext.prototype.readystatechange = function() {
111 | let xhr = this.xhr;
112 |
113 | if (xhr.readyState === 4) {
114 | var head = xhr.getAllResponseHeaders();
115 | var response = xhr.responseText;
116 | //将服务器返回的数据,转换成json
117 | if (/application\/json/.test(head) || this.dataType === 'json' && /^(\{|\[)([\s\S])*?(\]|\})$/.test(response)) {
118 | response = JSON.parse(response);
119 | }
120 |
121 | if (xhr.status === 200) {
122 | this.loadCall(response, xhr);
123 | if (this.data[this.pageName]) this.data[this.pageName]++;
124 | } else {
125 | this.errorCall(response, xhr.status, xhr);
126 | }
127 | this.endCall(response, xhr.status, xhr);
128 | }
129 |
130 | };
131 | /**
132 | * 获取发送请求的url,含参数
133 | * @returns {string} 返回拼接成的url地址
134 | */
135 | GetNext.prototype.getUrl = function() {
136 | let data = this.data;
137 | let aData = [];
138 | let url = '';
139 | for (let attr in data) {
140 | aData.push(attr + '=' + data[attr]);
141 | }
142 | url = this.url + '?' + aData.join('&') + '&' + new Date().getTime();
143 | return url;
144 | };
145 | /**
146 | * 检测元素是否在可视区
147 | * @param {object} el 检测的元素
148 | */
149 | GetNext.prototype.testMeet = function(el) {
150 | let bcr = el.getBoundingClientRect(); //取得元素在可视区的位置
151 | let mw = el.offsetWidth; //元素自身宽度
152 | let mh = el.offsetHeight; //元素自身的高度
153 | let w = window.innerWidth; //视窗的宽度
154 | let h = window.innerHeight; //视窗的高度
155 | let boolX = (!((bcr.right - this.left) <= 0 && ((bcr.left + mw) - this.left) <= 0) && !((bcr.left + this.right) >= w && (bcr.right + this.right) >= (mw + w))); //上下符合条件
156 | let boolY = (!((bcr.bottom - this.top) <= 0 && ((bcr.top + mh) - this.top) <= 0) && !((bcr.top + this.bottom) >= h && (bcr.bottom + this.bottom) >= (mh + h))); //上下符合条件
157 | if (el.width != 0 && el.height != 0 && boolX && boolY) {
158 | return true;
159 | } else {
160 | return false;
161 | }
162 | };
163 | /**
164 | * 判断请求状态
165 | * @returns {boolean} true 禁止请求 false允许请求
166 | */
167 | GetNext.prototype.testXhrStart = function() {
168 | return Boolean((this.xhr !== null) && (this.xhr && this.xhr.readyState !== 4));
169 | };
170 | /**
171 | * 获取元素
172 | * @param {string} select 选择器
173 | * @returns {Array} 返回选择的元素
174 | */
175 | function getEl(select) {
176 | switch (typeof select) {
177 | case 'string':
178 | return document.querySelectorAll(select);
179 | case 'object':
180 | if (Object.prototype.toString.call(select) === '[object Array]') {
181 | return select;
182 | } else {
183 | return [select];
184 | }
185 | }
186 | }
187 | return GetNext;
188 | });
--------------------------------------------------------------------------------
/src/lib/Tool/Tool.jsx:
--------------------------------------------------------------------------------
1 | const Tool = {};
2 | /**
3 | * 发送ajax请求和服务器交互
4 | * @param {object} mySetting 配置ajax的配置
5 | */
6 | Tool.ajax = function (mySetting) {
7 |
8 | var setting = {
9 | url: window.location.pathname, //默认ajax请求地址
10 | async: true, //true。默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false
11 | type: 'GET', //请求的方式
12 | data: {}, //发给服务器的数据
13 | dataType: 'json',
14 | success: function (text) {}, //请求成功执行方法
15 | error: function () {} //请求失败执行方法
16 | };
17 |
18 |
19 | var aData = []; //存储数据
20 | var sData = ''; //拼接数据
21 | //属性覆盖
22 | for (var attr in mySetting) {
23 | setting[attr] = mySetting[attr];
24 | }
25 | for (var attr in setting.data) {
26 | aData.push(attr + '=' + filter(setting.data[attr]));
27 | }
28 | sData = aData.join('&');
29 | setting.type = setting.type.toUpperCase();
30 |
31 |
32 | var xhr = new XMLHttpRequest();
33 | try {
34 | if (setting.type == 'GET') { //get方式请求
35 | sData = setting.url + '?' + sData;
36 | xhr.open(setting.type, sData + '&' + new Date().getTime(), setting.async);
37 | xhr.send();
38 | } else { //post方式请求
39 | xhr.open(setting.type, setting.url, setting.async);
40 | xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
41 | xhr.send(sData);
42 | }
43 | } catch (e) {
44 | return httpEnd();
45 | }
46 |
47 | if (setting.async) {
48 | xhr.addEventListener('readystatechange', httpEnd, false);
49 | } else {
50 | httpEnd();
51 | }
52 |
53 | function httpEnd() {
54 | if (xhr.readyState == 4) {
55 | var head = xhr.getAllResponseHeaders();
56 | var response = xhr.responseText;
57 | //将服务器返回的数据,转换成json
58 |
59 | if (/application\/json/.test(head) || setting.dataType === 'json' && /^(\{|\[)([\s\S])*?(\]|\})$/.test(response)) {
60 | response = JSON.parse(response);
61 | }
62 |
63 | if (xhr.status == 200) {
64 | setting.success(response, setting, xhr);
65 | } else {
66 | setting.error(setting, xhr);
67 | }
68 | }
69 | }
70 | xhr.end = function () {
71 | xhr.removeEventListener('readystatechange', httpEnd, false);
72 | }
73 |
74 | function filter(str) { //特殊字符转义
75 | str += ''; //隐式转换
76 | str = str.replace(/%/g, '%25');
77 | str = str.replace(/\+/g, '%2B');
78 | str = str.replace(/ /g, '%20');
79 | str = str.replace(/\//g, '%2F');
80 | str = str.replace(/\?/g, '%3F');
81 | str = str.replace(/&/g, '%26');
82 | str = str.replace(/\=/g, '&3D');
83 | str = str.replace(/#/g, '%23');
84 | return str;
85 | }
86 | return xhr;
87 | };
88 | /**
89 | * 封装ajax post请求
90 | * @param {string} pathname 服务器请求地址
91 | * @param {object} data 发送给服务器的数据
92 | * @param {function} success 请求成功执行方法
93 | * @param {function} error 请求失败执行方法
94 | */
95 | Tool.post = function (pathname, data, success, error) {
96 | var setting = {
97 | url: pathname, //默认ajax请求地址
98 | type: 'POST', //请求的方式
99 | data: data, //发给服务器的数据
100 | success: success || function () {}, //请求成功执行方法
101 | error: error || function () {} //请求失败执行方法
102 | };
103 | return Tool.ajax(setting);
104 | };
105 | /**
106 | * 封装ajax get请求
107 | * @param {string} pathname 服务器请求地址
108 | * @param {object} data 发送给服务器的数据
109 | * @param {function} success 请求成功执行方法
110 | * @param {function} error 请求失败执行方法
111 | */
112 | Tool.get = function (pathname, data, success, error) {
113 | var setting = {
114 | url: pathname, //默认ajax请求地址
115 | type: 'GET', //请求的方式
116 | data: data, //发给服务器的数据
117 | success: success || function () {}, //请求成功执行方法
118 | error: error || function () {} //请求失败执行方法
119 | };
120 | return Tool.ajax(setting);
121 | };
122 |
123 | /*
124 | 合并对象属性
125 | */
126 | Tool.merged = (...arg) => {
127 | var obj = {};
128 | for (let i=0;i {
152 | return typeof(obj) == 'object' && Object.prototype.toString.call(obj).toLowerCase() === '[object object]' && !obj.length; //true 是 false不是
153 | }
154 |
155 | /*
156 | 判断对象是不是数组
157 | */
158 | Tool.isArray = (arr) => {
159 | return Object.prototype.toString.call(arr).toLowerCase() === '[object array]'; //true 是 false不是
160 | }
161 |
162 | export default Tool;
--------------------------------------------------------------------------------
/src/reducer/index.jsx:
--------------------------------------------------------------------------------
1 | import Tool from '../lib/Tool/Tool';
2 |
3 | const start = {
4 | loadMsg: '正在加载中...',
5 | loadState: 0, //0 正在加载中, 1加载失败,2加载成功
6 | title: '正在加载中...',
7 | data: null,
8 | scrollX: window.scrollX,
9 | scrollY: window.scrollY
10 | };
11 |
12 | /*
13 | 分类最新列表数据
14 | */
15 | const classNewList = (state = {def: start, classid: {}}, action) => {
16 | /*
17 | {
18 | def: {
19 | getNextBtn: true, //判断所有数据是否已经全部加载完成
20 | state: 0, //0 正在加载中, 1加载失败,2加载成功
21 | page: 1, //加载到第几页
22 | title: '正在加载中',
23 | data: null,
24 | scrollX: window.scrollX,
25 | scrollY: window.scrollY
26 | },
27 | classid: {
28 | 0: {
29 | getNextBtn: true, //判断所有数据是否已经全部加载完成
30 | state: 0, //0 正在加载中, 1加载失败,2加载成功
31 | page: 1, //加载到第几页
32 | title: '正在加载中',
33 | data: null,
34 | scrollX: window.scrollX,
35 | scrollY: window.scrollY
36 | },
37 | 1: {
38 | getNextBtn: true, //判断所有数据是否已经全部加载完成
39 | state: 0, //0 正在加载中, 1加载失败,2加载成功
40 | page: 1, //加载到第几页
41 | title: '正在加载中',
42 | data: null,
43 | scrollX: window.scrollX,
44 | scrollY: window.scrollY
45 | }
46 | }
47 | }
48 | */
49 | if (state._ID && state._ID !== action._ID) return state;
50 | switch (action.type) {
51 | case 'GET_DATA_START': //开始加载
52 | return Tool.merged(state, action.state);
53 | case 'GET_DATA_SUCCESS': //加载成功
54 | return Tool.merged(state, action.state);
55 | case 'GET_DATA_ERROR': //加载失败
56 | return Tool.merged(state, action.state);
57 | case 'SETSCROLL': //记录滚动条
58 | return Tool.merged(state, action.state);
59 | case 'CLASSID_UPDATE': //栏目id更新
60 | return Tool.merged(state, action.state);
61 | default:
62 | return Tool.merged(state, {
63 | _ID: 'classNewList',
64 | def: {
65 | page: 1,
66 | getNextBtn: true
67 | }
68 | });
69 | }
70 | }
71 | /*
72 | 分类导航
73 | */
74 | const classMenuList = (state = start, action) => {
75 | /*
76 | {
77 | loadMsg: '正在加载中',
78 | loadState: 0, //0 正在加载中, 1加载失败,2加载成功
79 | title: '正在加载中',
80 | data: null,
81 | scrollX: window.scrollX,
82 | scrollY: window.scrollY
83 | }
84 | */
85 | if (state._ID && state._ID !== action._ID) return state;
86 | switch (action.type) {
87 | case 'GET_DATA_SUCCESS': //加载成功
88 | return Tool.merged(state, {loadMsg: '加载完成了', data: action.state, loadState: 2});
89 | case 'GET_DATA_ERROR': //加载失败
90 | return Tool.merged(state, {loadMsg: '加载失败', title: '加载失败', loadState: 1});
91 | case 'SETSCROLL': //记录滚动条
92 | return Tool.merged(state, {scrollX: window.scrollX, scrollY: window.scrollY});
93 | default:
94 | return Tool.merged(state, {_ID: 'classMenuList'});
95 | }
96 |
97 | }
98 |
99 | //导出方法
100 | export default {classNewList, classMenuList};
101 |
--------------------------------------------------------------------------------
/start.bat:
--------------------------------------------------------------------------------
1 | echo 启动服务器
2 | cd E:\react-kelink
3 | start npm start
4 | echo 编译前端代码
5 | cd E:\react-kelink
6 | start webpack -w
--------------------------------------------------------------------------------
/static/build/app.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | div,
4 | ul,
5 | li,
6 | p,
7 | footer,
8 | header,
9 | article,
10 | a,
11 | b,
12 | em,
13 | nav,
14 | form,
15 | input,
16 | textarea,
17 | select,
18 | button,
19 | i,
20 | h1,
21 | h2,
22 | h3,
23 | h4,
24 | h5,
25 | h6 {
26 | padding: 0;
27 | margin: 0;
28 | border: none;
29 | list-style: none;
30 | text-decoration: none;
31 | box-sizing: border-box;
32 | }
33 | input:focus,
34 | textarea:focus,
35 | button:focus {
36 | outline: none;
37 | }
38 | body {
39 | font: 14px/1.5 "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;
40 | color: #040404;
41 | background: #eee;
42 | }
43 | html,
44 | body {
45 | width: 100%;
46 | height: 100%;
47 | -webkit-text-size-adjust: 100%;
48 | }
49 | header,
50 | nav,
51 | footer,
52 | article {
53 | display: block;
54 | }
55 | a {
56 | background-color: transparent;
57 | -webkit-text-decoration-skip: objects;
58 | }
59 | a:active,
60 | a:hover {
61 | outline-width: 0;
62 | }
63 | ::-webkit-input-placeholder {
64 | color: inherit;
65 | opacity: 0.54;
66 | }
67 | ::-webkit-file-upload-button {
68 | -webkit-appearance: button;
69 | font: inherit;
70 | }
71 | .scrolling {
72 | overflow-y: scroll!important;
73 | -webkit-overflow-scrolling: touch!important;
74 | }
75 | .red {
76 | color: red;
77 | }
78 | img {
79 | border: none;
80 | max-width: 100%;
81 | }
82 | /*! flex-css-layout v1.2.8 | 狼族小狈 https://github.com/1340641314/flex-css-layout */[flex],[flex]>*,[flex]>[flex]{overflow:hidden}[flex]{display:-webkit-box;display:-ms-flexbox;display:flex}[flex]>*{display:block}[flex]>[flex]{display:-webkit-box;display:-ms-flexbox;display:flex}[flex~="dir:left"]{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}[flex~="dir:right"]{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}[flex~="dir:top"]{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}[flex~="dir:bottom"]{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}[flex~="main:left"]{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}[flex~="main:right"]{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}[flex~="main:justify"]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}[flex~="main:center"]{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}[flex~="cross:top"]{-webkit-box-align:start;-ms-flex-align:start;-ms-grid-row-align:flex-start;align-items:flex-start}[flex~="cross:bottom"]{-webkit-box-align:end;-ms-flex-align:end;-ms-grid-row-align:flex-end;align-items:flex-end}[flex~="cross:center"]{-webkit-box-align:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center}[flex~="cross:baseline"]{-webkit-box-align:baseline;-ms-flex-align:baseline;-ms-grid-row-align:baseline;align-items:baseline}[flex~="cross:stretch"]{-webkit-box-align:stretch;-ms-flex-align:stretch;-ms-grid-row-align:stretch;align-items:stretch}[flex~="box:mean"]>*,[flex~="box:first"]>*,[flex~="box:last"]>*,[flex~="box:justify"]>*{width:0;height:auto;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[flex~="box:first"]>:first-child,[flex~="box:last"]>:last-child,[flex~="box:justify"]>:first-child,[flex~="box:justify"]>:last-child{width:auto;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[flex~="dir:top"][flex~="box:mean"]>*,[flex~="dir:top"][flex~="box:first"]>*,[flex~="dir:top"][flex~="box:last"]>*,[flex~="dir:top"][flex~="box:justify"]>*,[flex~="dir:bottom"][flex~="box:mean"]>*,[flex~="dir:bottom"][flex~="box:first"]>*,[flex~="dir:bottom"][flex~="box:last"]>*,[flex~="dir:bottom"][flex~="box:justify"]>*{width:auto;height:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[flex~="dir:top"][flex~="box:first"]>:first-child,[flex~="dir:top"][flex~="box:last"]>:last-child,[flex~="dir:top"][flex~="box:justify"]>:first-child,[flex~="dir:top"][flex~="box:justify"]>:last-child,[flex~="dir:bottom"][flex~="box:first"]>:first-child,[flex~="dir:bottom"][flex~="box:last"]>:last-child,[flex~="dir:bottom"][flex~="box:justify"]>:first-child [flex~="dir:bottom"][flex~="box:justify"]>:last-child{height:auto;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[flex-box="0"]{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[flex-box="1"]{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[flex-box="2"]{-webkit-box-flex:2;-ms-flex-positive:2;flex-grow:2;-ms-flex-negative:2;flex-shrink:2}[flex-box="3"]{-webkit-box-flex:3;-ms-flex-positive:3;flex-grow:3;-ms-flex-negative:3;flex-shrink:3}[flex-box="4"]{-webkit-box-flex:4;-ms-flex-positive:4;flex-grow:4;-ms-flex-negative:4;flex-shrink:4}[flex-box="5"]{-webkit-box-flex:5;-ms-flex-positive:5;flex-grow:5;-ms-flex-negative:5;flex-shrink:5}[flex-box="6"]{-webkit-box-flex:6;-ms-flex-positive:6;flex-grow:6;-ms-flex-negative:6;flex-shrink:6}[flex-box="7"]{-webkit-box-flex:7;-ms-flex-positive:7;flex-grow:7;-ms-flex-negative:7;flex-shrink:7}[flex-box="8"]{-webkit-box-flex:8;-ms-flex-positive:8;flex-grow:8;-ms-flex-negative:8;flex-shrink:8}[flex-box="9"]{-webkit-box-flex:9;-ms-flex-positive:9;flex-grow:9;-ms-flex-negative:9;flex-shrink:9}[flex-box="10"]{-webkit-box-flex:10;-ms-flex-positive:10;flex-grow:10;-ms-flex-negative:10;flex-shrink:10}/*! flex-css-layout v1.2.8 | 狼族小狈 https://github.com/1340641314/flex-css-layout */[data-flex]{overflow:hidden;display:-webkit-box;display:-ms-flexbox;display:flex}[data-flex]>*{display:block;overflow:hidden}[data-flex]>[data-flex]{overflow:hidden;display:-webkit-box;display:-ms-flexbox;display:flex}[data-flex~="dir:left"]{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}[data-flex~="dir:right"]{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}[data-flex~="dir:top"]{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}[data-flex~="dir:bottom"]{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}[data-flex~="main:left"]{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}[data-flex~="main:right"]{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}[data-flex~="main:justify"]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}[data-flex~="main:center"]{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}[data-flex~="cross:top"]{-webkit-box-align:start;-ms-flex-align:start;-ms-grid-row-align:flex-start;align-items:flex-start}[data-flex~="cross:bottom"]{-webkit-box-align:end;-ms-flex-align:end;-ms-grid-row-align:flex-end;align-items:flex-end}[data-flex~="cross:center"]{-webkit-box-align:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center}[data-flex~="cross:baseline"]{-webkit-box-align:baseline;-ms-flex-align:baseline;-ms-grid-row-align:baseline;align-items:baseline}[data-flex~="cross:stretch"]{-webkit-box-align:stretch;-ms-flex-align:stretch;-ms-grid-row-align:stretch;align-items:stretch}[data-flex~="box:mean"]>*,[data-flex~="box:first"]>*,[data-flex~="box:last"]>*,[data-flex~="box:justify"]>*{width:0;height:auto;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[data-flex~="box:first"]>:first-child,[data-flex~="box:last"]>:last-child,[data-flex~="box:justify"]>:first-child,[data-flex~="box:justify"]>:last-child{width:auto;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[data-flex~="dir:top"][data-flex~="box:mean"]>*,[data-flex~="dir:top"][data-flex~="box:first"]>*,[data-flex~="dir:top"][data-flex~="box:last"]>*,[data-flex~="dir:top"][data-flex~="box:justify"]>*,[data-flex~="dir:bottom"][data-flex~="box:mean"]>*,[data-flex~="dir:bottom"][data-flex~="box:first"]>*,[data-flex~="dir:bottom"][data-flex~="box:last"]>*,[data-flex~="dir:bottom"][data-flex~="box:justify"]>*{width:auto;height:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[data-flex~="dir:top"][data-flex~="box:first"]>:first-child,[data-flex~="dir:top"][data-flex~="box:last"]>:last-child,[data-flex~="dir:top"][data-flex~="box:justify"]>:first-child,[data-flex~="dir:top"][data-flex~="box:justify"]>:last-child,[data-flex~="dir:bottom"][data-flex~="box:first"]>:first-child,[data-flex~="dir:bottom"][data-flex~="box:last"]>:last-child,[data-flex~="dir:bottom"][data-flex~="box:justify"]>:first-child [data-flex~="dir:bottom"][data-flex~="box:justify"]>:last-child{height:auto;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[data-flex-box="0"]{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}[data-flex-box="1"]{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1}[data-flex-box="2"]{-webkit-box-flex:2;-ms-flex-positive:2;flex-grow:2;-ms-flex-negative:2;flex-shrink:2}[data-flex-box="3"]{-webkit-box-flex:3;-ms-flex-positive:3;flex-grow:3;-ms-flex-negative:3;flex-shrink:3}[data-flex-box="4"]{-webkit-box-flex:4;-ms-flex-positive:4;flex-grow:4;-ms-flex-negative:4;flex-shrink:4}[data-flex-box="5"]{-webkit-box-flex:5;-ms-flex-positive:5;flex-grow:5;-ms-flex-negative:5;flex-shrink:5}[data-flex-box="6"]{-webkit-box-flex:6;-ms-flex-positive:6;flex-grow:6;-ms-flex-negative:6;flex-shrink:6}[data-flex-box="7"]{-webkit-box-flex:7;-ms-flex-positive:7;flex-grow:7;-ms-flex-negative:7;flex-shrink:7}[data-flex-box="8"]{-webkit-box-flex:8;-ms-flex-positive:8;flex-grow:8;-ms-flex-negative:8;flex-shrink:8}[data-flex-box="9"]{-webkit-box-flex:9;-ms-flex-positive:9;flex-grow:9;-ms-flex-negative:9;flex-shrink:9}[data-flex-box="10"]{-webkit-box-flex:10;-ms-flex-positive:10;flex-grow:10;-ms-flex-negative:10;flex-shrink:10}/*
83 | 公共头部
84 | */
85 | .common-header {
86 | height: 50px;
87 | z-index: 999;
88 | position: relative;
89 | background: red;
90 | -webkit-animation: move-down 0.3s ease-out;
91 | animation: move-down 0.3s ease-out;
92 | }
93 | .common-header .icon {
94 | width: 50px;
95 | height: 50px;
96 | }
97 | .common-header .icon a {
98 | display: block;
99 | color: #fff;
100 | }
101 | .common-header .iconfont {
102 | font-size: 24px;
103 | }
104 | .common-header .title {
105 | line-height: 50px;
106 | text-align: center;
107 | color: #fff;
108 | font-size: 16px;
109 | }
110 | @-webkit-keyframes move-down {
111 | 0% {
112 | -webkit-transform: translate(0, -10px);
113 | transform: translate(0, -10px);
114 | }
115 | 100% {
116 | -webkit-transform: translate(0, 0);
117 | transform: translate(0, 0);
118 | }
119 | }
120 | @keyframes move-down {
121 | 0% {
122 | -webkit-transform: translate(0, -10px);
123 | transform: translate(0, -10px);
124 | }
125 | 100% {
126 | -webkit-transform: translate(0, 0);
127 | transform: translate(0, 0);
128 | }
129 | }
130 | /*
131 | 文章列表
132 | */
133 | .article-list li {
134 | padding: 10px;
135 | margin-bottom: 10px;
136 | box-shadow: 1px 1px 3px #ccc;
137 | background: #fff;
138 | }
139 | .article-list li + li {
140 | border-top: 1px solid #eee;
141 | }
142 | .article-list h3 {
143 | color: #222;
144 | }
145 | .article-list .content {
146 | font-size: 13px;
147 | color: #999;
148 | }
149 | .article-list .bottom {
150 | padding-top: 5px;
151 | }
152 | .article-list .bottom .click {
153 | font-size: 12px;
154 | color: #ccc;
155 | }
156 | .article-list .bottom .to a {
157 | font-size: 12px;
158 | color: #1a43a8;
159 | }
160 | .article-list .pictrue {
161 | margin-bottom: 10px;
162 | background-size: cover;
163 | background-position: center center;
164 | }
165 | /*
166 | 数据正在加载中
167 | */
168 | .data-load-0 {
169 | margin: 20px auto 20px auto;
170 | position: relative;
171 | -webkit-animation: rotate-forever 1s infinite linear;
172 | animation: rotate-forever 1s infinite linear;
173 | height: 30px;
174 | width: 30px;
175 | border: 4px solid red;
176 | border-right-color: transparent;
177 | border-radius: 50%;
178 | }
179 | .data-load-0 .msg {
180 | display: none;
181 | }
182 | .data-load .msg {
183 | line-height: 70px;
184 | text-align: center;
185 | font-size: 14px;
186 | }
187 | @-webkit-keyframes rotate-forever {
188 | 0% {
189 | -webkit-transform: rotate(0deg);
190 | transform: rotate(0deg);
191 | }
192 | 100% {
193 | -webkit-transform: rotate(360deg);
194 | transform: rotate(360deg);
195 | }
196 | }
197 | @keyframes rotate-forever {
198 | 0% {
199 | -webkit-transform: rotate(0deg);
200 | transform: rotate(0deg);
201 | }
202 | 100% {
203 | -webkit-transform: rotate(360deg);
204 | transform: rotate(360deg);
205 | }
206 | }
207 | /*
208 | 分类
209 | */
210 | .class {
211 | overflow: hidden;
212 | background: #fff;
213 | }
214 | .class ul {
215 | overflow: hidden;
216 | padding: 10px 10px 0 10px;
217 | }
218 | .class li {
219 | float: left;
220 | width: 25%;
221 | margin-bottom: 10px;
222 | }
223 | .class li a {
224 | display: block;
225 | text-align: center;
226 | font-size: 14px;
227 | font-weight: bolder;
228 | color: #222;
229 | }
230 | /*
231 | 文章详情
232 | */
233 | .article-view {
234 | padding: 10px;
235 | }
236 | .article-view h2 {
237 | font-weight: bolder;
238 | font-size: 16px;
239 | color: #222;
240 | }
241 | .article-view .yue {
242 | text-align: right;
243 | font-size: 12px;
244 | color: #999;
245 | }
246 | .article-view article {
247 | padding: 10px 0;
248 | font-size: 14px;
249 | color: #666;
250 | }
251 | /*
252 | 关于我们
253 | */
254 | .about {
255 | padding: 40px;
256 | text-align: center;
257 | font-size: 14px;
258 | color: #666;
259 | }
260 | .about .pictrue {
261 | overflow: hidden;
262 | width: 200px;
263 | height: 200px;
264 | margin: 0 auto;
265 | }
266 | .about .pictrue img {
267 | width: inherit;
268 | height: inherit;
269 | border: none;
270 | }
271 | .about .info {
272 | padding-top: 20px;
273 | }
274 | .about a {
275 | color: #3290e6;
276 | }
277 | /*
278 | 底部菜单栏
279 | */
280 | .common-footer .zhanwei {
281 | height: 50px;
282 | }
283 | .common-footer .menu {
284 | position: fixed;
285 | right: 0;
286 | bottom: 0;
287 | left: 0;
288 | height: 50px;
289 | z-index: 999;
290 | background: red;
291 | }
292 | .common-footer .menu a {
293 | padding: 5px 0;
294 | font-size: 14px;
295 | display: block;
296 | line-height: 20px;
297 | color: #fff;
298 | opacity: 0.8;
299 | text-align: center;
300 | }
301 | .common-footer .menu .on a {
302 | opacity: 1;
303 | color: #ebff00;
304 | }
305 | .common-footer .menu .iconfont {
306 | display: block;
307 | }
308 | /*
309 | 登录注册
310 | */
311 | .login {
312 | padding: 100px 0;
313 | }
314 | .login .line {
315 | padding: 10px 10%;
316 | }
317 | .login .line .key {
318 | width: 50px;
319 | padding-right: 10px;
320 | line-height: 34px;
321 | font-size: 14px;
322 | }
323 | .login .line .value {
324 | font-size: 14px;
325 | overflow: hidden;
326 | padding: 5px 10px;
327 | border-radius: 5px;
328 | background: #fff;
329 | }
330 | .login .line .value input {
331 | width: 100%;
332 | line-height: 24px;
333 | background: transparent;
334 | }
335 | .login .line .select {
336 | line-height: 34px;
337 | }
338 | .login .line .select .iconfont {
339 | display: inline-block;
340 | width: 26px;
341 | font-size: 24px;
342 | }
343 | .login .line .select .icon-xuanzhong {
344 | color: red;
345 | }
346 | .login .btn {
347 | margin: 50px 10%;
348 | font-size: 16px;
349 | font-weight: bolder;
350 | line-height: 38px;
351 | border-radius: 8px;
352 | text-align: center;
353 | color: #fff;
354 | background: red;
355 | }
356 | /*
357 | 个人中心
358 | */
359 | .user .head {
360 | margin: -50px 0 0 0;
361 | }
362 | .user .head .headimg {
363 | height: 250px;
364 | padding-top: 50px;
365 | background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAZABkAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wgARCADwAWkDASIAAhEBAxEB/8QAHAAAAgMBAQEBAAAAAAAAAAAAAgMBBAUABgcI/8QAGgEAAgMBAQAAAAAAAAAAAAAAAQIAAwQFBv/aAAwDAQACEAMQAAAB+PHza9aoaIIEfRkTMtSopY9YMNsRBPIFcuJTVTcXGp3k269I0ma4ODNsrstKLwQUBspjBMzJ0NkxEPARUHEUeLoB4okHigiO7oO7uksvTZq3pgwkKYINX7ueiDGXpYxMxbBoYsZ0SCIFEa3Q0KNWmNnK0lOb1irbSQmUFRV5Rat1jpK8OAwIMSB6YijM9BEFBAwURR6SKxJAGs2q1urcgGLkI1sDVunnzjJG1KyZJAsAgXSolMkvQrt6lYUti+hTpuYnoPO13WDB7VLW1BkQsHUxFxil36lipjoVZ6Og9Wyv7bk9P5vl/T/B6Kcjujoc1qumS7ar2M/SQBgRxiclcwa9BsaTZ0w+StBNmrHOVmHZv4m9l1Zr7j6LcKvt1rVrPTrhsu1Yv57MbP8AT5brgr0UbctW8t4La+ihXxBtIvzrcv6bWvjPQ/cvi3L1N8hXoamRBR0ObEFBGi+vZzdOpEw6GXCrosV7Nma/xScwMNrVZNDUzBeLRsrdo2b1Hn79N7rPP1ZNLbzLVzdKrYuqs3zu8/ZmZ3o8wr5upr0erhrsY1goLikszaWlQ15kfTfmWgKv1J4mv5rkH5iqwruBQmL0RBCV0LdW7m6Wb3FZWcGtXRZq27MumTGHKLzvFMOj7ZnH7/iLnsa1b0I17WW+rZYOW2nnb/WDztzZ4Cjex9gEM3UqKcfG9Fh9TLWcLr6CVfCi/DztfK6OOuYToz3CpvrtFLUOoAYPn4Zhq7ellX8+6oS2OJjhDJv0br5drhE5Nq9l6NNj2wfmfVSSRguFl30jjCukuFQtiOjJtMtsMc7Bp5GkEbzlT0PnupkQ+tF9GvNNuTXSxtjH6GOnMRsyHZq6FdwUdnKEQMxfkiCEo+2p9Oyo1LjDBqFsTeo2LMusupEzbOr5vTps9dn3MLgejtP0zWeP9l5X1FiZNej6KxI8r7jxRl7eyMxgXq/DX7B6BdZmLWrH183fizKzc3o8+87HMWaVCUmKjotzlcosD6ebKAejosz9HQU02KPP0KjVk6PrPrhgIYszGIka7d/M0qz7C2w/L+kzk7JOvm9DYIDBH0MpMadeAfNN9DLjx1z0FO04jXouMrg9OXzeRsZvT49OHIsVvLkW9HQUmYMQR2EqubBc4s1L1eSyQHTurkBOhKYuQY4Wo5qDKWL2VyP9SL53PI630cvnNhD9BPwrqz7SPJ8lnqgpfUEq+bq+qU3r+aK9R5qaRny2roSyOX7e/P6f1luNPG+N/Jf0l+bbGGRnQ/czRgy/a+N+rVZ/SeM954rLg+d0Lk7umFX7PjUL8+NTH6VYhl62LYAZYEL546OZCiOE4wZJZs1rIF7QzbdYfTZSq0WfS+NsUaPtqvk+tz7PZ/P+wNDZRJ7r8/T+g/LtqofqPvApFFf4T7fx9z1u7mPptytabN5Tbw8qu36v4LE5a49p4r1DH9GUfDfMsFeWambOtXIZatkdAdUSNmaO7ivd0ycUSGc2pwl+7htE2a9M0stvpMpvunUOuyxSbXYZQsTsxFIcV9Ra8fbg1sI66tHRLL6IvOvKgliw8mEyBMcQXHwdjEtrvT0S1Zx3CxYlD5x6ZKjJzCvm9InmjAElIPT3BjYow7JGVblyDBQOBqg6ZKjxwCEz0ERMw2tCu5lpVGqV4ghizHdIxfRI5iyW4JiSpdHBwYt7Ukw5ZRJhiJJ3CIGyJleXzJX6yIKGGwEYb0KAsDBXVbEynNiCEC8QUQ4TETMRpHoVoiRixEwU7uiDu7jGGslsggmA+Ho4uQ1qrcqkq40SDZ5BSM5cyMNJiGMRJJqOE5XIhAQSRK+JMYGTh6JIWxcKokDJDoE6O6L3RxHd3QdE9J//xAAuEAACAgEDAwMEAgICAwAAAAAAAQIDBBAREgUgMQYTISIwMkEUFSNAJDMWNEL/2gAIAQEAAQUC2EiSNjY20202OIoo4I4IVcThEcIjgbEoKGJgRjOc4OM+BwOA4m2uxsbG33kRJ+dH2IQu1jEt5Z3/AGVtwn1GMeaNjYaJdi/0EIl+Wj7l34i/ytuciv8Ay4BvoxmxsbffWiIk/wAvsruX0YUV8bGBPhfk1e1dpsOJxOJxNjb7kRrbRC8T/L7S1YkZ64m2ufHnj6vu2H29KxaLMbI6fAtxWlJbayfwIXifnT9aJGxsba7m5uYUed+Q3ZlsemF/mxSBsMkNm5uQimuK2sWz7Oj3bRoSkr6I8c6vjLsREl50/wDnRI20aJG5yZuIx9qsSqP08BxJRMWx1W9RqUMuEBVkoE4DWmxSvp4l0fp1rg5yeLkY7w8xpTu+M+al2rSR+h+EISNjYaLFqitfOUuNMIfDh8OBKAok172NVAVZKstgSicTiQ+GtmWpbSjr6Hw67cm/Hpth6j6d/Aulkz2nJy7Y6SP0iXhFflIYkbFqHpFGFV7l05e5lQRx3JQLEbGHHeVcCMScC2BZEcRIUTiSiTRJaeh8mNd56wjF9Nl3R0Z+kT8fqnytIjRcPyiCMdKinD+oricCyBZHSAoqUow+JwLoliJISEbEkTJ6Yl06Lemeo8adXqnqtWXFj7YD8PSJYfqnzFGxBHFstx7mPDyBYd5Xg3mRiznj4+JKtQjxN4lk6yxciOM5EcRo9tKKexOfxY1Ivriq5IQjYkiwnoiMiTGPtj4/T0RafrH/ACibFcdyEPngxVxEoozbpU0403ZR8m246YMVJw465VN9mTtpYjIX+F6QEicS5FmqejH2xfwvx03LPP6xPy0pWy8EJxk9jY2E0fBxRsfJuzkzkzke5Edsy+ee3bPPcZaQIki4t1RFEl8S7UVPeOmxLTE/I3KZkXu09LLKqyN1MiWXiwcGpRL8imgqyKLjYlm4kXVdRZU+o4O/9njJQtjdU5F84+0/DYpEJjkWst1RUS8W+e2v6Yo/SLNMby5HIqnsUWRdqidSv/jY2Dhx4XYFM59Ygv5qj8dWyXjUdKxIe1k4tNtdNt9uH0jKxlRj41dLoUI9eyXRGur2aK5Woum3WybHIVh7g5FmqK5Dl8WPd9kVuSFpEsP1UxyFIhIw3/yUdaW9UfHwdX/9068lKPT5KeF8HTZRWRnYFd50266u5VLI6ndg1kZ1o5/N0pe1NF3mUvnkKRyJPsTOQ+2oe2sSeiY2JkGVfXOjF9p31RuqqeXVGdWVkW5mNl5N3HqMo4nT/bqpxsrElOrLvjfgxniVY/UK40YXslWJl15HDMMfGkrUo8p+63YjK8z13+1xjw2IeNV4lo9ERMB/8vTcWu/dL2izZk4QZ7dZY+EJfjleXFslHvS3f8DJVSxbXBkPzekPx7Ho9Fp075zlI5CYmc0c0czkzmzmchyHKQ9xbD3LnNR2lOzpnp7Gpj/Gx+PrPpVdMX3encRWOEU11Cv2sjOjxvRKe62IfjqvMtJabm5GUoyWflH8/KP5mSyGXkiy8pkbMmQubOEDpX8OGTXg4DT6fhFvSunbX4OGpdVqrpx65/V7mOhzg5ej61d1HT1Zx/pJedIQc2sX6ZLi/TSX9fWvnrMk8jMnzuw6Hfbg+mMaWP8A+OXkPH60j5lo+5EBFSIjZOezVh0/q+TilXVvdrsyZ2FkzrOSrJWP5rZzPRGQodR09b5SeJLzp0+n6dkl1GHG30/1OGHPP69jQWbnyu09OVc7PEfcgQH40RPyPuiRIsrYmSZYxESi+ylrqlm1+ZdariXlG50m7hkYvX17WX1yycc233ZXr69MT/ob+Ooz5WdnRM6rFl1L1Ti+x/ZXkCXjWfkfchMUiMyNg5jYhCetxLzopNPHzZNSulIusW1j3emDkbVX5PxY+Uhdi3PkiPxrPR/Y3NxSYpCkKRyFI5HMsZLsi2hXslPceqI1ykSTjq9VpEf46y0f29zcUjkczmcxzH9qiOmR57WzciPxrLs2NjY2OJxNjY2NjY2FE4HEcTicTY2NjY2NuyjbjKUUTe7H3I/WstILc4nE4nE4nE4nE4nE4nE2FE2OI4nEcRxOJxOJscTY2+4u16VaoX2l9x/dXa9K+3f/AFWP/RekDdG6N0ckckbo3N0bm6N0bo3RujdG6N0No3Nzc3N0bo+B7D+5/8QAKhEAAgIBBAEDBAEFAAAAAAAAAAECEQMQEiExBBMgQQUUIjIVMDNAUXH/2gAIAQMBAT8BhAcDYjboxaIglTZtTh/zWitKKKK9mNHzrRtNpQkPhJGLuiWOnRtKKKK0ooa1xofej0sssxrc6J/tplXUhIfuwY4TgeT4+1WtYD70fWlkRIwLtkcQ8ZGNxohiJ4hxIoeMlEUTDkS/UzeRuVD0gfI+h9DLICRs2pIjEnEguSMaJxJxIxNvBOIjFjcZEokkUQXB8kv10kzFHfNIj9Ogj7PHHkWGL5NqHFM9OIijOkmRNvBkWkSRIZikIldEuhmDiaojdcm5Ckn0NpCkmb4nqx/2VuM62kJcm7gy6YzKh6QjRAn+o+ho8f8AuIyv8OCOOO0xL85C/LK7My/JEbg1GRiUqdIR5Yp0LKSlZZCVGSejF0RMj4H1pjjc0iONJUemeij0onpoWJIWKjZXRni/kk6ZZu13pj0XQiXQ+hMhLbJM/kMZ/IYz72AvITJ+Zs+BfUov4PueLoXmJnkeRaG7EWbjyZ1AxSdl1HkWVMj0WS6H7dzIZGJ2QjBGSXBfJknwLkS0k7Y4KcaZDBGBmTceBY2RfAiXQ9VpSEqExMk+CWi4L02L2KBF8CY+h+6xSN5vGUVpQ0UPTcyL4EN8D/oWX7Vo/YmIvj/Asv2f/8QAKREAAgEDBAAGAwADAAAAAAAAAAECAxEhBBASMQUTFCAwQSIyUUBScf/aAAgBAgEBPwFsuX2Wz3k82OVp/LL2X3uXF3cq9XIyurly5cv8Ehe+b4ohiJYovuI2IttZWvvqa1SnUNLqvMw95fBWfSJVskapKfGVypXyUq1xSJPBGt9CZWqeXG55vnvjM0+l8t33lt97LdslO7cidTJSncnLBUqFKoU5kpimQZXhzhYjTlzSsJ7z72XeyKkuEWx+Is9fOb4pE9TNfic85I14x6JamTKnSdynJGnlgkxTyUXs4iFtUXsTK36u5Nq+Dy592J0pRy0RhKfRKlKOGh6eostHpKv+pCXlv9ShLmurEoYODuUNplN7yYxdjEjUfozTRvWSkT1NXm2mapt0oE70tKuP2aKbdN3zYqQVaLlTf/UV4QlKPKQ4ZuzSoUB0kQjbaSuQjbd9jI971f1ZKtNyuepaylketla1ketqO9z1U8WwPW1GeslLtCq8syKLX0ReNrb81st1vKN4tD8Ml/R+GS/o/DX/AE9FFdsdCCdrnkRjlspxjJ4HpbEKfE4L7NP9res/xI3uLCHqIxH3su/axodNFSlFk9MzTULSuy2CcMYM/wAIxUVsiUbkaaRNYPKmx9/BYaJRHEhGz3Ytr+y4/iscTivisPdfM/8AHfu//8QAOhAAAQIDBAgEBAUDBQAAAAAAAQACAxExEBIgIQQiMDJAQVFxEzNhkVBygaEUI0JDglKS4TRgYqKx/9oACAEBAAY/AttRUVLWmWs4ownDeCLTy+FyQhj9Akg4cimxW0iD4XeNG5ouNjmc4eY+Fvd/WbotANHZJzeXL4VCgj9LcELSB8ruAMSKy8SZD0V6H7bE2jttG+mae71wRIHUTb32MzjMI9ZiwyxhHbxIvM5DC145HNOu7rtYbaQEypvhub9FIy2YR2kKD9ThomuO/DyPbY1wvjxBO5RXXsBXiQvLd9lKZWfCtBGrPNFyphMPk8SUtq+C471hJ68Pm6WaJxl4cD12rYkMycEBpJ8N/wBkIOjuvN5ngpBZQyvKPutz7qgH8k2CxzdXnP3VW+6qLKz7CaoR3WU/ZVKuT52clulF3G5VWbvss5+yoFeaLyY8zEws8GTVmF/lQ3Q4jWtFVWzmn5GnDnHIHPth5Ki5hVVbKBUav0rVhu/tU2NggepRDoIkenDnELfzIjW9ytWPDM6ayk6O2aDhmD6WfmxA09OalDjNcek5WS8S98rZoxYcS80VW+T/AAX7o/ghEhmbTY6py4M7Jreq3lfaRfJkMl40fXivzzzTXjVLeig+qqV+Wdd9D0QjxtZ7s80QWD0PRR9FmXObTt0QgxCIcT15p5Yd8zThqgTMlKKWhrsu68KGclQlHKWXXghgKOJuclVQzyD0LNGsaWkG4ZO9FCI6WRtJebsOcp9yr7cndQnaI8zAp6KLfoEJOkVcqVu/dO3R9eDPbAcTW9TJaukROyMN1CrhhNiyo69JMdFuMYwzuN5psSUOHd3RNS8WCzs1PbGPiX6o/h3MfDP6Xq5FeyGw1DKlfh2SYOSuePCLRS9mnxL/AIkY8yMk6MDDJdVfsD6TT4kaKSXdMlNmivd6lyDXQmNb6GfAS59bXYDihfNtMyqgrosysmXkbgu9kJ9NlILxDCN1Xg3KwYHYDihd1ywVsoVRf4W8uaoV0Wcyt1URn/4hDYLziZAIRNLaI0Xod0KXgQ5fKhpcBl0UcBj8Z4VwgXeiLRRGXOzVFrsBxXmmRXnFeaV5pXm/Zeb/ANQs9IetaPG/uWb4h/mgNJhh7HZa5nJauiwvZf6WF7KZ0cDsSEbkN0vnKLod5p+YoTcT9VrAKYbLpmnxD+0zLubY8+mDKySErD6BGSDfdeJEiRQXDVHRb7bHcIAHXmf0uQc1rc/Vaxs8NpyFcD2uOT2S+to0RjtYmbsEyqLJGHGn4TvspaKTEd1lkjdF2dbB/wAnAKSrY7AeB1HfRbjfdSndHQYZTkTTugI0Il3UKUFnh+pRJM8Dcc4sxI3gpaGHuiOFSJXV5j/ew8ZMVWbRNemG6eSqp7E8blwJwHj5nbn4cfiB/wBv1VVVVVcdbKquwrtv/8QAKBAAAgEEAQQCAgIDAAAAAAAAAAERECExQVEgYXGBkaEwwbHw0eHx/9oACAEBAAE/IVYJehKasQEnBEggQIIcI7AuI4E7U4wRwO/A6iXU9hXt209pi0LtDFVQjEECq2IIIrBH4CUIuJUbNCXQFRFqEkahMuw61KjnekGItyLYkQgQFiD6EobQ/wAqC4rKjdFRMYTpJI3RPCW/ouHNuSBImGz1E0SMxZ/IH1opQyU0PXfpQnQmIgdE1bV6LusLcd04lP4aFAkqVDpsMsQR0xJHQibvSTRiMgjQ9CNUggQqUxCXGtwlcWzFpH5ZYMWbOOBG5L2aFkQqGNjY2Mk1J3dNtdrMQQknKksu5GJoY0MYmSqqYC2USwaP5AjVBU1GiYgoFzL6w8vQ9ajQSFS3DOXP1C4rO4koSwLA1B0nLAK2SgZ2KOq3MEsH4CJdofRghrD7xpHHk28CNUkEqFpKaEmTbpbT7uSbVNqH+RoDQT9oWixgs4HIeRRJHhisLoapAiPMcJITN3ljNFyJZmB9C4FZIyfmiL+VcWXXoWywOqwIpyl7HctkQGOk2ZTH+ZCMEyS4LGCJS0XsF8dwgrmgRFk9iDqU3QaIFPY4V8vY1Kz5Q5SHNZcixIPI2uGujUWhqEwZzASkSk7aGQiRl4j6I7XJnEg81JKpkJxP+dfZDdlWYyNkmTsUblU8DsFouUiMZKmQhWCXGhro0IhKp+lFDHNDFLAgoSgy5lzm0wIoN5ZboZGyCSLi3tZ8iWQ4acOkskJfdSWi1gXJlSYrZTHdUK7auISBfQIIMfQSxsyErJGXow9UYugOANti67H3P0BfK/EZf3kNBCbQl7Fxd2ApL+gs3fyYaZiSrK+K+hpc3gZ5HoTR3VrTFLZJ+WbH3GmRdhBrNcuoUVp2xIMzY8MjJR6GPoUp/vgyFj2KfrQsoJyK4YHpG7XKm0NnoY5Houupi2u5NBzQxOVjEmyZlUvgRpyuMCms+kLsFl2G4sR3XcXkGlFnAmcsRklNiCYENEIlzdHSLFLDo3S0H+n6HkVkODQ0s6GncQlfImr0pO+9hwZnliQSK36NglsBMyp/YxLR/aFwDsIZc4uEGE/hSIZXwX2O2iFdIOihuLtTscaxgKJcdGJqKx1dEiGT64QnLbHhEHnVDVGTIsIQLQyRHMzi1IwUxgSXHBKruobaGwpCU0wp4ZDLXmv8ENu5iT4ZNZtGZ0Pk7rLeq9iGOkmV6yJQTPZ2OabV5oXFwHBsbsKZaUPRhnMUoRPIuMksmY81ohEEjpJNo+CpYW7XgheOTRaeMVxLvgSpttjsPYxzbytyRjYkniLjEmViRFa0UuM3FJECmmJ0cDbGUTzzTAtIcYLsMbjaco7hWdNqcfYtbJqmy8D7qxDxME5cZPYg0o95ND14/kR8O4ZwRMuSQbFNE49x5o1BO3RjpOT2Ooa7MyFovYa/lRAzvF2iqVoily/BiN53HsTY3YsV39kX5P2iGxykapbNbHxKLfY2ibbhInXMHdYJC535vJcRm5/TsIRnI5FZPU7bG10KThsUcsd4DjErEWkyzgtqjvlxIPNEQj7hqOv6UpCN2ZN3NEDO+XM0ZKcqDMR8IFizs35EBbtu8d0Prhlktu7PL8z8kiz0ZvCEaz6CRck449j9YZNaOJZaaGn5LkTIiiCwkeGQMcjDmBtnD2YZEpklJXHj+S9YpbleBMFhS4yRFsfXljxAS4pNufGjHhnQVGRRIJF9gnxJMC7Br4JFQhvyT2+SHpJeENJLCMtn2ORlwrVpFyn9jS59gYwmzQ2kuE/FO6JSOQxUdXqQ23pDjM5McnYCRY+wYE+KH60YnaDEKlUJwM0F3jIyF4HJAnshJ1+Thckgvfsx9lIP+kIa93tlz9AwrKHkuWSdmdx7F1X7L7IiDLWmW2zNNb+BS2JcKOCQVWY4S3ktfSh9kJY8GAFvC0HnoQvRXDNOVoVCyXmdHgNgPDdiRmA/kNUIQwFplGGhDb5F/oBW4JbPyjMZAMI/EI2EXP8AZB80EMR+RAdyW7MLbf1eZIY2v/UjscQ1zEmadyGj662QOpNknAiubnkRI6J8D8j1RANcryNa2hpng/kuPAlFwMS20pWFtstjDkcj2Z/zaTt0Rv8Ag3MQUQIopNyWHluf7keHomCQyOLeFgRBeWfLLbNJj05FbkimQvtYggVCdg6SLGmqWqhRgVPgydFkaEvA2ghDuQbdFS/9oQlorKypdC0Hilv5JK7muWBxycRTlrpiMG5+Q/OrRfI8hopcxIyX7BZEqhtyNiyPdLGNvm3sUmiqqZcClcxSUtEkyRSZEHCpmNHb8RP8nRrYGmujMPqKiGhExDQvkkIkBFdhaJFNsI5TIVzFxfDccEIMk+gFz1wvANY4zIeB0kdiBp0ZOxkxmXSiSaE5yhr3UEO5WlRn0NZaBlXbOcNNWemIJHkOiGraiTCuQqD6z6ExBNQRVBlzX4yWwshk7KPoQlahsDX0WRUnSGSrotxsTJ0pyYiwTExhIbD6gIIEqdTkuwhurUm6iFk/kGXAgkFTVN9o+s2RY7B4UE0osOk6UEtYcDbYzX4WxU381kIYakjYxEEDF0JJGNDVGOp0box/iI2YjNxOiYmISTRVdESTRk0YxkDoyoxsb/AiRCZI1qPDYuZHepFwDsDtCHA7iEvIuYfMjvI7iFxB8yFxDsDkIacojyiPKGvKHyI7iG+A7gyGyfxf/9oADAMBAAIAAwAAABDa6ynDPRqra2i/EVCJ/PfD33y0F/LX+ttpFX/BPYQ+I3bD+2G5f6nBi72/lMrW3n4a213ioYc8RRirEXKboKOYEDxeOtBfmfFDK7ppWmeitZIBZtw8sSnQd1qz2spy+AgnSHf4JwBci8laXNU4e4CwUQNQfuOEvf0X/wB+sbAMweIazzZBBAdTwUOtH/S0yNCRyzt3de8fVsEvaH8OJAOqui+tiW8s+snsrCL6z6DhheMeqJLqU9q8oSS0YZ3JBbvrl84wqad+h8kS3SK2dKM9/X4QeyklaXW+MJJHreLk3eXmy9yglvMFWyQa4hr5E/zfnoqPMd/m8I7z4vXoMM8xQaghQ//EAB4RAQEBAQEBAQADAQAAAAAAAAEAESEQMUEgUZFh/9oACAEDAQE/EAYNjKxPJS/uWzGZPD+xbbDAkyAz5MTP4CTOWYXUw9c/6kg2+PLbUGBYkTU8OvANcsDwM/L4YSTGomLHqz5DjbYfsjBJgWdHstsA07DA8Zdjh4Bxb7Wz1DfDH/jImtnMztSzLGxYvtjEvYjf8RZoSXxMGX6XE9XxbMD9V7c7MsYAhSxfBrCBvZAvzwxnxA2HIvHy339b9Bsml5LBgOXAYD8sKmfLEYyOs1kx9ui5vuW35Mxdlpvy+kG0r72wH6nfFksUbqwHGEcHxcOMyNdjgWMZu7M26ksG3XLn0Q/1nGqABICM/mByHA5v2YRp+N9AG2AMn0tE5Ytnrxaksuz5uLhJZE22D+7C/klMVyBV17YZnMtR3u3/AGojgtsZTGrbdI7jRLrbhs/ulshKKcfgFD8Yy+MJ+Nv8L4hbu1jNwekazIlSVazX7EQM3L9uTZ2gWyh43y22LUgG35L93QCHYWyo+RQ7bJ4RfjWAmXwqVXmeOQkcMhiZwyxI+MHW5+SWQZ20vSfoW+Ec+BHV1at2QmVYwZfXilhF3wfFvbbfNhh9G7a2+NlPnLAlYj/A8z3LfchyYzfG/8QAIhEBAQEAAwEAAgMAAwAAAAAAAQARECExQSBRYXGhkcHh/9oACAECAQE/EMI6WttvHCtZZUxRD42222wy222/go8t7tsWy2LMxU05endjDicZB52Hl5eL7HvBJJbrdAfbsSAnyAlsRcNYQjlVj1b/AKc9uo84+yxPG7+2w6RsQH702E3Rtv0kyaWrU4WL48YHj1HkRu1nGRJ8g6LDpapmd1i2pYXdbzOZOpo3VDwsm4S2pGP9LD+EDi1h1/uS6nlO7piyZKvz9RmR3dG2U1Jg3Y8C+pPUBvU+X6JiXi/gMOYWf1BjjZbDrJahidOf1H0USiN/m7IH9JGIQocLC1jjRzj3vYuqH/FD5CYwtX/TBTort+yaewT+5Bo/S0AEDyVYK/zED1aE612WLOUQ4BM7vJ4x8IhvstiUX2ePF51aFlH4+Wb0g7w8jMAN9w9hYjv9Wr1/y+ZhEHW0eATHjvCZ9k7h3Hsl/PBLfEP4h+m/8zf9ZJJ4IUL3+LX7/lj6ljBtsPiPKnSKDfRLYwjwFlnA2FJ/yFxLT12WFGHE7+6FdPa6Z6+2QyA5K77MsJboQiR7HLwqSRl+TaR5ZProg+vGngngO5Oo9ixsssssk2ICLPwEJi2xDuYO71bP5ZwNrHLOTh4zuLPweH8jhln4f//EACcQAQACAgEDBAMAAwEAAAAAAAEAESExQVFhcRCBkbGhwdEg4fDx/9oACAEBAAE/ECcoIYQIASri5SeiYBo3+pW8kwOIW4lrAeI4yGdKecYoLhXj8MpYL2hVoQSgIMMkrYcB42w7Q1KxZElY95dxqJepbpDtgcMwTiPZKMCATUx4Z2Y1j6VSvQqV/loeJhPMGJ2zMuiWiHSAvpibT3lZTNqHLiAhAggVHQWRVDuFpuUo2g8uIFe2l9QzFMQxa6NxTwt+BuDCGT0BjBKqGoyNkoSqxCJKgRI+if4VLA9o1LoztdLlZ1xMcyiju4QGHxCXmG8SoIMKCQlrmXmfRnWUaws/NRyFZX3hmTQEtWVbr2v4iBx+IEg71FGSdJFXAeiqMTLrcSJj0S/QJgRMxieoL9AcG5jLxhSDZM2wO/EKCdqBOHxAwQ3F6TYBzLppiq1L9JTfMRheoiv9AjAvnLKQdIdKbtx+ftjVSWctvP4MIumKxAJOAVAuAGCGJm1M0r3jSJHUrPoPII1iRIkoKl3szyjSqhyXmHx3NGBfnB7c18ehw6gYIZRQXDjUdaixO5F8Tg6hOwmgjJEAXZdbEAAAJWOightXp4gNliY8Mr7jIPT0OzIRlZgHOINQr3Kbr2hWq+ZYawixlwl5j2MAFcbVfxDhzGidn+wY0rMfhSbm0QRgcwb9AUo/3C03iDm5Zy9WXQrlglnRPSnziUczNqa95QY4mPHpDluAsWHldTNn+1QZgsAcAYiZDM0ndICvGsDdWFcarvcWAUmyJdeIgNoxbXSPSENEpcMsY9UIFQ0F1bGJHuuUrew1L4ihuEpED5dlJ+Bl3A3xvEqVbqiGEomD62QD4CAYu35mfkSiSslRVvW/LNPaB0y2v5MOp2YlYJaEtoIbuO9GDO4Ra35zJW2/KfEMs1Vt8xokxNu444sikqgVVl7gpCgTQZp83GRibENc0YyiaYJYu+kEmJ3En5jFqgacmSKOqiQVwxwgLV6TSrAgr34gtlSrGYhp2buOEq7m0cMdemh2IANv/MVp3ThC3QpKhhtPqIovmVhNZ2mDVQ1qdHKFNoLBZ3ivNmM3afcyPy17StJoqWyGax5nOJhcMzoU8EN1bHK9R7n5huFOkxLXxLHAl6TDvGFhuJgkbpNyjSdZdrnRUwQOYAbjClSteIRSlIWw3ewgeHppYVCr6CBZHRgS0Weo5JTM19iZIAKzmZHpbGqS5Wqbgo75fqYL2gI8zSkpJfM25SMGfmDNSgoiqJBQYBlPcI1wcA4K+pgIqVrWUXi4BQZhnVtfcCyg7Wz9gRkC5uwmGV5dKihbPmCXFK4YBkTPglvEDWYANCDbEKA8QrjJe74+6gXkg+gRaawzKlD6GJXoEoF4PqZOjNXMxvvLEpHaHdUaMe8trLtTncbcOKl7qVuUipMzF5h3VS1FKLq4BoGNqrUdaIY7J353MDT7S+wzUsraR8BMdY4FIZB1lB5QKWCzO8594KMZlDov2mZjzMxUyIko4mHIQNaIFmkv0xADjljdAwfXiEqUIPcGOMRTEXYj24m9h3BmViVDi3ggFhxrxFp3zKu8/csN3WEKEd2fmDSuZNLSbzozFwWA5jijeQP7MNA9Q/cWCx/zzDJ5gP3Lo2lLW38lB2IIAroj+oAvPugdjCtiotdLIi/EWtZzd/JYNe5UHysdEjuJczgQWYpr8QyJB0GCKo7DuODvzr8pAmQXVrvoFQM1mC2ql6EwKI1NxnFQZUVEPRF2rqcv5gU9ZWHL0m0dPo6Gv+JZZpCNhUNjGoq3yS40ZSjHbzK8W5lOBA4cxSgo6wyL0XUEyb4C/klYrykfU2Edzf1EzUABjvAaj0XSHK760wWTzvRAQoezKuhTebfcMUNXCnwMygeqX/s7BXXEdRfcScgAVq3bTlTEAKajsFwaLDtKhsD+H+RqVV20xxDLdQog1LmJC2o5a4iW3KnHlBrU5CZK2HF8ShqO2O5gr0Wjvf4lrfODbI6PEO20bgEH/VHbzFhZcq1aqdRHlWQfKXeaKoeJRAAsz8hT7XEXVF6qxQZPLiUGAdC02A9L0SpSR0cxAehsKgaCuhUAbwe5A7T2Sd383/IC0t7scit3Wo7idGfwEM8+lL3RAaFS1Z34Im6gSjk3fpbFnmGOXxLQnMQuEjR7wBPM3i0YlyROeJW6htIx3NvRgmStQKbcfjE7OMoL2gux5R0gV7rP3mniNYVm6x4lYF517SwEwa/8mxVfEPcLLHs2ntB9UqxrpV3cqvetx0wQjBhCx5zBTHkxUUUZaFDrQvzUIpukr8C+1zjKdR9nE+1kYoY+Lg37VgUl008oJt3F0+LmZY7ofdQObLcHGxHSQqbPVVQxpFQYNQ5ckL+IFpLlXKheXmKVDMA5RWj0nU3MXHcd5ajBajcHcYyoVzRCqcWl+IKPLcyOMhCUGUgjFpl9dTjEOvaEWIqC7yoF/EojwWqDHWAZJg8Q4Qi32H5qHrQC2LkM81A8BamgbpP3A7OLLwmeuJZlACjH1HMNvWkWHfIEM66MIdZdvdjJggAcBGDxgcx2Nt1YRijwqe8PAeEYQwBRaMeHPvHvBEBcEr8xOGBLrYVWb88RWbyit2vYlF8x+xTKPLVdV0LlHbX69B56u0VlQ4ZvMruWpamPaLiVovEIDMLlbEBUnX0WPQqbFWgiF5okw61BZlxbDkVgJceTN+p+0XfUrM7Q9HMswNRCOkQDbEoBRT2fxHGsYdYKFfUqBKDKAVWMEsVpmhQFvGYnU3Vvcik6PMS8tNoSA4cSqHFnQYRhNhKvAGX6lnE0mLH+0IKGoVg7DD5lXQUWWOF1DqXpBUwtUEOKw2UfEzRbOA6xDRzS1MjxjbDNTitLQoxEHlqNYjlLcd436/MYIKtxktxwuIo2jUdKylz6LiNy4RtcUS4lUMjrEGTpFQeCYO6g+47rQaSqzWSOw5e0frGFlQx1auaYVlKvvTcVmCqaJod7zA+9WsDBcOe5DIkUkas28XolDcayY3dqsuoopaX09xcD3l/sFXVeXN3m5srjiXUGnvzA/f5MDUda3K4vkF9zk3zH8IJcPYS8d4JBKqmxc4Cwlk0boQt8ZIUgRm/yFxMPFHVD9diJLHwMu9sFSIkUroO8vYMASjyhhVwzFuXzeE4gstSI3HEBANuCXhPPqvp4nY/MaN4wMVoAV/EKruRa8S5sCH3HY+bixHVTMWuZsDLFUzfcbD8n/s1FIeJgwnzUBpQPEBfJ2qKi6luQuLqHmBa0u1Sy0Gu6DMJCYLwtQx6gtl8SyNKgaD5jLYd/4lRiN1U+6llnsUl/EansZytLYbxNMtUjqCzKt7mDFF9BCNDegLVmJPcFnk494/uKq4XwbjNRSbhEXJSB90rAM87GKDs0icpMfxGQXafc5m7/AHNC4tMVsri5Sik5PxCwILDvFH9IKDk3uCfzf2NZF7x1lbKFgmBu7iJoqPc/kI1iZyn7qM22o2DZ8ZiGxTpdLKX10T+aiIQNaS6/alB8w5gPIjMZY1rC7RmIwAoW4C/eG6wAWwEThQyCewp1ZRvygM+oIT9Oy1XrDZ1g4uLGGZ0RXCnM0MNd1x4jqwUAW6KhDKZTwEDgAYmi4LqtWQ4KWQ+B18y3VOerUC3tqWbXcWoFY4Sae5+ZoRYIsyhi4d19qpIGFIK0f1NYI8P5C8PrQEHP+GckwAW6F+pTIXT+SAfM6fRNgHN/3gubBf3jJoHT7StRBVHUDUDtSFeQyifiKe24LX3zF0UFAl9zAos5D2/MXKWsK28Ax4ZB0hrbD7bvx+AA/MFb4lCRC1o29xUsZ3g+gUvLKgMG4LNKgZCifIhFp2WRDTEne7miAb4jZZ76JMvKGAaYwZvpP/bQWHFYi9g/ccC94uDxOz0gSveMeCE5lxcS2FyQCql8tFtQuCQgc17zJlbrD8qeZUw8xYOebw1HASwCrxXXtGMpuHQhmqMMiums6J1r7iDKPDUdp3DMlqG8KReFh7lzLPEodIcIRK9oHutS4thfQzMdRz5lUFNZlRqgUukNq6hG2ojO9by+IvQs77R3ngl25g6BsfDZ+okoAB+J2XzLtc1YTFGhYmxBtDiKy9qljzBFnD1z6BBMQ6wBzAxIoipLllc3GeYurxHzyvsI/cLjHIH4mEGSFWd3coKFREvrKkv1jcxQtIlkPfIDT606gvQqgJ2NEWoKqrU7biocM+obuYq1F2AjADTiCIpVbLBuLTMjNSk1ntshBRRnt3hyHHE/9NFMepFV1f3NjDceGbx2mxOP+DuCYMxLgFNnzLRGGLeMRI1F9hpuMGIjUM8z3gEhBeZfoZYUB0kNuYWsX3lJfiL8sAg2S9fXDHgM8RSLFwAx0VWaVBhK4zJg4qYg29p2GMSh0m+dYX1xFziUbcTJ716dEv0PUUjNusBCYwgGYDlYHDc47h2JB3xtyfMLaRimLL9BbVGIZirlLTc59COYXpLAv3lZ8+jpuWanPoc5uW6zRWNRCFkuhJksd32Jg+z0cH0Mepfoz/gJwwUQ5qUcy0lv+IhKkxXzHf8Ahdf41WsNTAUQmjJOYE4l+owyalurKQcQEe0Vtihlvciz5TaJc7EE4YLowfSL0lDTOinanYgziaFR6UZwkVhhAiBKTiMicXFGKuDeIPpHLWJa8EWejLMAWnmMVhnpReJtLJXq+lKhweY7jzU1RwyTsT2CF0lzJcJ4gekq0Q7IFMD0lXiBeJQdShx+JW6ohHEGtQINQjiB6RHET3gckDp6KOkqNRygTcNmw4ZuG30VDua9GPpgHiOR8S42hvM1XdL1FnwPSswCB0uCN4lKg1EMA8E8IitSnSU3AVFrUWojMcohfSoYnqIsWEm8Xn0LiijUa9FmJcWCLh8enXBsfuLLyzaOk+J3JdTJiV+gzbMHG42EWb3BzLhLTI6Rl4WZZALAE2xG0wPWLiImT0Bi+mfR16MlKcxQNQAhZOp5i5uChasJU/dK+PzAM0+YD+kP9pP/AEJf/SH+6nQ/mVNfme6usU180q/tOJDA+70Y8fySg/dOH80OX5py/mjX90Fv5oN/aZ32R0wJdww4wvMY6mf8an//2Q==);
366 | background-size: cover;
367 | background-position: center center;
368 | }
369 | .user .head .headimg .pictrue {
370 | overflow: hidden;
371 | width: 80px;
372 | height: 80px;
373 | border-radius: 50%;
374 | box-shadow: 0 0 10px #fff, 0 0 20px #000;
375 | background-size: cover;
376 | background-position: center center;
377 | }
378 | .user .head .headimg .name {
379 | padding-top: 10px;
380 | font-size: 16px;
381 | font-weight: bolder;
382 | color: rgba(255, 255, 255, 0.9);
383 | }
384 | .user .logins {
385 | margin-top: 20px;
386 | height: 38px;
387 | }
388 | .user .logins .item {
389 | padding: 0 20px;
390 | }
391 | .user .logins .item a {
392 | display: block;
393 | line-height: 38px;
394 | font-size: 14px;
395 | font-weight: bolder;
396 | text-align: center;
397 | border-radius: 8px;
398 | color: #fff;
399 | background: red;
400 | }
401 | .user .nav {
402 | overflow: hidden;
403 | margin: 20px 0;
404 | background: #fff;
405 | }
406 | .user .nav li {
407 | padding: 5px 10px;
408 | }
409 | .user .nav li + li {
410 | border-top: 1px solid #eee;
411 | }
412 | .user .nav li a {
413 | height: 38px;
414 | line-height: 38px;
415 | font-size: 14px;
416 | color: #666;
417 | }
418 | .user .nav li a .font {
419 | width: 40px;
420 | }
421 | .user .nav li a .font .iconfont {
422 | font-size: 24px;
423 | }
424 | .user .nav li a .arrow {
425 | color: #ddd;
426 | }
427 |
428 | @font-face {font-family: "iconfont";
429 | src: url(/build/iconfont.eot); /* IE9*/
430 | src: url(/build/iconfont.eot#iefix) format('embedded-opentype'),
431 | url(/build/iconfont.woff) format('woff'),
432 | url(/build/iconfont.ttf) format('truetype'),
433 | url(/build/iconfont.svg#iconfont) format('svg'); /* iOS 4.1- */
434 | }
435 |
436 | .iconfont {
437 | font-family:"iconfont" !important;
438 | font-size:16px;
439 | font-style:normal;
440 | -webkit-font-smoothing: antialiased;
441 | -webkit-text-stroke-width: 0.2px;
442 | -moz-osx-font-smoothing: grayscale;
443 | }
444 | .icon-zhuye:before { content: "\E601"; }
445 | .icon-caidan:before { content: "\E600"; }
446 | .icon-gerenzhongxin:before { content: "\E604"; }
447 | .icon-guanyu:before { content: "\E603"; }
448 | .icon-weixuanzhong:before { content: "\E60A"; }
449 | .icon-xiaoxi:before { content: "\E608"; }
450 | .icon-shezhi:before { content: "\E606"; }
451 | .icon-fanhui:before { content: "\E602"; }
452 | .icon-wenzhang:before { content: "\E609"; }
453 | .icon-arrow-right:before { content: "\E605"; }
454 | .icon-lianxi:before { content: "\E607"; }
455 | .icon-xuanzhong:before { content: "\E60C"; }
456 |
--------------------------------------------------------------------------------
/static/build/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/static/build/iconfont.eot
--------------------------------------------------------------------------------
/static/build/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
75 |
--------------------------------------------------------------------------------
/static/build/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/static/build/iconfont.ttf
--------------------------------------------------------------------------------
/static/build/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/static/build/iconfont.woff
--------------------------------------------------------------------------------
/static/build/user-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzxb/react-kelink/fddd2d1f70bba99c11647fc42712a1715950b862/static/build/user-bg.jpg
--------------------------------------------------------------------------------
/webapp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | react-kelink
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var ExtractTextPlugin = require('extract-text-webpack-plugin');
3 |
4 | module.exports = {
5 | entry: {
6 | app: './src/app', //编译的入口文件
7 | },
8 | output: {
9 | publicPath: '/build/', //服务器根路径
10 | path: './static/build', //编译到当前目录
11 | filename: '[name].js' //编译后的文件名字
12 | },
13 | module: {
14 | loaders: [{
15 | test: /\.js$/,
16 | exclude: /^node_modules$/,
17 | loader: 'babel?presets=es2015'
18 | }, {
19 | test: /\.css$/,
20 | exclude: /^node_modules$/,
21 | loader: ExtractTextPlugin.extract('style-loader', 'css-loader!autoprefixer-loader')
22 | }, {
23 | test: /\.less/,
24 | exclude: /^node_modules$/,
25 | loader: ExtractTextPlugin.extract('style-loader', 'css-loader!autoprefixer-loader!less-loader')
26 | }, {
27 | test: /\.(eot|woff|svg|ttf|woff2|gif|appcache)(\?|$)/,
28 | exclude: /^node_modules$/,
29 | loader: 'file-loader?name=[name].[ext]'
30 | }, {
31 | test: /\.(png|jpg)$/,
32 | exclude: /^node_modules$/,
33 | loader: 'url?limit=20000&name=[name].[ext]' //注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图片
34 | }, {
35 | test: /\.jsx$/,
36 | exclude: /^node_modules$/,
37 | loaders: ['jsx', 'babel?presets[]=es2015,presets[]=react']
38 | }]
39 | },
40 | plugins: [
41 | new webpack.DefinePlugin({ //编译成生产版本
42 | 'process.env': {
43 | NODE_ENV: JSON.stringify('production')
44 | }
45 | }),
46 | new ExtractTextPlugin('[name].css')
47 | ],
48 | resolve: {
49 | extensions: ['', '.js', '.jsx'], //后缀名自动补全
50 | }
51 | };
52 |
--------------------------------------------------------------------------------