项目地址:
托管平台:
项目地址:
初心:一直想要做一个自己的一个作品——博客,可奈何某宝买的服务器经常出问题,域名需要钱,服务器需要钱。于是想出用gitee page来托管站点。可gitee托管只能是静态站点,该如何实现这么多的文章数据管理呢~ 于是,老夫用json来管理文章列表,异步请求json来生成网站的分类、文章列表、文章统计等等,通过不同路由来实现访问不同的文章。
聊聊技术:
整体使用了react with typescript
路由:使用了hash路由,由于只生成一个html,不能为每个路由自动生成html!!!,页面部分使用require.context
来读取文件,这样就不用手动来引用新写的页面
// ./src/App.tsximport React from "react";import { Switch, Route, HashRouter as Router } from "react-router-dom";// import Layout from './Layout';import { store } from "./util";import { Provider } from "react-redux";const context: any = (require as any).context("./page", true, /index\.tsx/);const keys: string[] = context.keys();const page404: any = (require as any).context("./page", false, /404\.tsx/);const keys404: string[] = page404.keys();export default class App extends React.Component{ render() { return ( ); }}复制代码 {/* */} */}{keys.map((key: string) => { const pathArr: string[] = key .replace(/^\./, "") .replace(/\/index\.tsx$/, "") .split("/"); const path: string = pathArr.join("/") || "/"; return ( {/*); })} {keys404.map((key: string) => { return })}
数据流部分:使用了,是真的好用啊!!
页面connect连接数据流使用了高阶组件来包裹。
/** * @description:用以connect组件和model的装饰器函数 */type IConnectFunc = (payload: any) => any;export const connectModel = ( stateFunc?: IConnectFunc, dispatchFunc?: IConnectFunc): any => { const mapState: any = stateFunc ? stateFunc : (state: any) => ({}); const mapDispatch: any = dispatchFunc ? dispatchFunc : (dispatch: any) => { }; return (WrapperComponent: any) => { class App extends React.Component{ public static displayName = "@connect" + (WrapperComponent.displayName ? `(${WrapperComponent.displayName})` : ""); public render() { return ; } } const connected: any = connect( mapState, mapDispatch )(App); return connected; };};/** * @description:获取store */export const store: any = (() => { const context: any = (require as any).context("../models", true, /\.ts$/); const keys: string[] = context.keys(); let models: {[propName:string]:any} = {}; keys.forEach((key: string) => { const name: string = key.replace(/^\.\//, "").replace(/\.ts$/, ""); let mdl: any = context(key); mdl[name] = _.cloneDeep(mdl.default); delete mdl.default; models = { ...models, ...mdl }; }); const store = init({ models }); return store;})();复制代码
这样在使用的时候只要装饰下,就能根据文件名读取store
//用类来当接口的好处是既可以当接口,也可以new来当初始值class Props{}class State{}@connectModel( (state: any) => ({ location: state.globalData.location, articles: state.globalData.articles, siteInfo: state.globalData.siteInfo, }), (dispatch: any) => ({ setData: dispatch.globalData.setData }))export default class Component extends React.Component{ public static defaultProps=new Props(); public state=new State(); public render(){ return app}}复制代码
动态运行代码:
目前支持动态运行js代码和简单的react代码,通过动态写入iframe来实现代码运行:
详情见:./src/util/index.tsx
$("body").append(``);const iframe: HTMLIFrameElement = $("#code-preview-wrapper iframe")[0];const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;iframeDoc.open();iframeDoc.write(html);//html部分需要将要运行的代码封装成一个html string来装入iframe达到动态运行效果iframeDoc.close();复制代码
文章统计:
使用,根据获取的文章列表数据来动态生成饼图和矩形树图。
支持插入在md中插入iframe并且展示:
功能原型就是动态运行代码的那几段函数: