├── 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 | ![Alt text](shot/1.png) 36 | 37 | ![Alt text](shot/2.png) 38 | 39 | ![Alt text](shot/3.png) 40 | 41 | ![Alt text](shot/4.png) 42 | 43 | ![Alt text](shot/5.png) 44 | 45 | ![Alt text](shot/6.png) 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 |
23 |
24 |
25 |
{config.indexTitle} {config.version}
26 |
github:134064134
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 |
139 |
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 |
55 |
56 |
57 |
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 |
51 |
52 |
53 |
54 |
55 | { this.state.logname = e.target.value; } } /> 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | { this.state.logname = e.target.value; } } /> 65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | { this.state.logname = e.target.value; } } /> 74 |
75 |
76 |
77 |
78 |
79 |
80 |
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 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
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 |
23 |
24 |
25 |
狼族小狈
26 |
27 |
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 |
74 |
75 |
    76 |
  • 77 | 78 | 首页 79 | 80 |
  • 81 |
  • 82 | 83 | 分类 84 | 85 |
  • 86 |
  • 87 | 88 | 我的 89 | 90 |
  • 91 |
92 |
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">&#x33;</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 | 4 | 5 | Created by FontForge 20120731 at Fri Jun 10 16:23:52 2016 6 | By admin 7 | 8 | 9 | 10 | 24 | 26 | 28 | 30 | 32 | 36 | 38 | 42 | 44 | 47 | 50 | 52 | 55 | 59 | 63 | 67 | 70 | 73 | 74 | 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,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); 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 | 4 | 5 | Created by FontForge 20120731 at Fri Jun 10 16:23:52 2016 6 | By admin 7 | 8 | 9 | 10 | 24 | 26 | 28 | 30 | 32 | 36 | 38 | 42 | 44 | 47 | 50 | 52 | 55 | 59 | 63 | 67 | 70 | 73 | 74 | 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 | --------------------------------------------------------------------------------