用react撸~了一个静态博客

项目地址:gitee.com/khigh/khigh

托管平台:gitee

项目地址:khigh.gitee.io/#/

初心:一直想要做一个自己的一个作品——博客,可奈何某宝买的服务器经常出问题,域名需要钱,服务器需要钱。于是想出用gitee page来托管站点。可gitee托管只能是静态站点,该如何实现这么多的文章数据管理呢~ 于是,老夫用json来管理文章列表,异步请求json来生成网站的分类、文章列表、文章统计等等,通过不同路由来实现访问不同的文章。

聊聊技术:

整体使用了react with typescript

路由:使用了hash路由,由于只生成一个html,不能为每个路由自动生成html!!!,页面部分使用require.context来读取文件,这样就不用手动来引用新写的页面

// ./src/App.tsx
import 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<any, any> {
    render() {
        return (
            <Provider store={store}>
                <Router>
                    {/* <Layout> */}
                        <Switch>
                            {keys.map((key: string) => {
                                const pathArr: string[] = key
                                    .replace(/^\./, "")
                                    .replace(/\/index\.tsx$/, "")
                                    .split("/");
                                const path: string = pathArr.join("/") || "/";
                                return (
                                    <Route
                                        key={path}
                                        path={path}
                                        exact
                                        component={context(key).default}
                                    />
                                );
                            })}
                            {keys404.map((key: string) => {
                                return <Route key={key} component={page404(key).default} />
                            })}
                        </Switch>
                    {/* </Layout> */}
                </Router>
            </Provider>
        );
    }
}

复制代码

数据流部分:使用了rematch,是真的好用啊!!

页面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<any, any> {
            public static displayName =
                "@connect" +
                (WrapperComponent.displayName
                    ? `(${WrapperComponent.displayName})`
                    : "");
            public render() {
                return <WrapperComponent {...this.props} />;
            }
        }
        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<Props,State>{
    public static defaultProps=new Props();
    public state=new State();
    public render(){
        return <div>app</div>
    }
}
复制代码

动态运行代码:khigh.gitee.io/#/codeRunne…

目前支持动态运行js代码和简单的react代码,通过动态写入iframe来实现代码运行:

详情见:./src/util/index.tsx

$("body").append(`
<div class="code-preview-wrapper" id="code-preview-wrapper">
        <iframe></iframe>
</div>
`);
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();
复制代码

文章统计:khigh.gitee.io/#/artSummar…

使用g2,根据获取的文章列表数据来动态生成饼图和矩形树图。

支持插入在md中插入iframe并且展示:khigh.gitee.io/#/aboutme

功能原型就是动态运行代码的那几段函数:

转载于:https://juejin.im/post/5cff61ef518825225162d182

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值