RubyLouvre/anu

View on GitHub
packages/render/miniapp/index.h5.js

Summary

Maintainability
C
1 day
Test Coverage
import { Children } from 'react-core/Children';
import { PropTypes } from 'react-core/PropTypes';
import { Component } from 'react-core/Component';
import { PureComponent } from 'react-core/PureComponent';
import { createRef, forwardRef } from 'react-core/createRef';
import { createPortal } from 'react-core/createPortal';
import {
    createElement,
    cloneElement,
    isValidElement,
    createFactory
} from 'react-core/createElement';

import { createContext } from 'react-core/createContext';

import { Fragment, getWindow, miniCreateClass } from 'react-core/util';
import { memo } from 'react-fiber/memo';


//import { dispatchEvent, webview } from './eventSystem';
import { DOMRenderer} from '../dom/DOMRenderer';

// import { toStyle } from './toStyle';
import { 
    _getApp , 
    getCurrentPage, 
    useComponent } from './utils';
//小程序的API注入
import { registerAPIs } from './registerAPIs';
import { more } from './apiForH5/index';

import { registerComponent } from './registerComponent.bu';
// import { registerPage } from './registerPage.wx';
import { 
    useState,
    useReducer, 
    useCallback,
    useMemo,
    useEffect, 
    useContext,
    useRef
} from 'react-core/hooks';
import { findDOMNode } from '../dom/findDOMNode';
let { render } = DOMRenderer;

let __currentPages = [];
const MAX_PAGE_STACK_NUM = 10;

let React = (getWindow().React = {
    //平台相关API
  //  eventSystem: {
  //      dispatchEvent
  //  },

    findDOMNode,
    //fiber底层API
    version: 'VERSION',
    render: render,
    hydrate: render,
  //  webview,
    Fragment,
    PropTypes,
    Children,
    Component,
    createPortal,
    createContext,
    createElement,
    createFactory,
    PureComponent,
    isValidElement,

    toClass: miniCreateClass,
    
    registerComponent,
    getCurrentPage: function() {
        return __currentPages[__currentPages.length - 1];
    },
    getCurrentPages: function() {
        return __currentPages;
    },
    getApp: function() {
        return this.__app;
    },
    // registerPage,
    registerApp: function(app){
        this.__app = app;
    },
    registerPage: function(PageClass, path) {
        this.__pages[path] = PageClass;
        return PageClass;
    },
    // toStyle,
    memo,
    useState,
    useReducer, 
    useCallback,
    useMemo,
    useEffect, 
    useContext,
    useComponent,
    useRef,
    createRef,
    forwardRef,
    cloneElement,
    appType: 'h5',
    __app: {},
    __pages: {},
    __isTab: function(pathname) {
        if (this.__app.constructor.config.tabBar 
            && this.__app.constructor.config.tabBar.list 
            && this.__app.constructor.config.tabBar.list.some(
                item => item.pagePath.replace(/^\.\//, '') === pathname.replace(/^\//, '')
            )
        ) return true;
        return false;
    }
});

function router({url, success, fail, complete}) {
    const [path, query] = getQuery(url);
    const appInstance = React.__app;
    const appConfig = appInstance.constructor.config;
    if (appConfig.pages.indexOf(path) === -1){
        throw "没有注册该页面: "+ path;
    }
    if (__currentPages.length >= MAX_PAGE_STACK_NUM) __currentPages.shift();
    const pageClass = React.__pages[path];
    __currentPages.forEach((page, index, self) => {
        self[index] = React.cloneElement(self[index], {
            show: false
        });
    });
    const pageInstance = React.createElement(pageClass, {
        isTabPage: React.__isTab(path),
        path,
        query,
        url,
        app: React.__app,
        show: true,
        needBackButton: __currentPages.length > 0 ? true : false
    });
    __currentPages.push(pageInstance);
    appInstance.setState({
        path,
        query, 
        success, 
        fail, 
        complete,
        showBackAnimation: false
    });
}
const titleBarColorMap = {
    'backgroundColor': 'navigationBarBackgroundColor',
    'frontColor': 'navigationBarTextStyle'
};
const titleBarTitleMap = {
    'title': 'navigationBarTitleText'
};

const prefix = '/web';

let apiContainer = {
    redirectTo: function(options) {
        if (__currentPages.length > 0) {
            __currentPages.pop();
        }
        router(options);
        history.replaceState({url: options.url}, null, prefix + options.url);
    },
    navigateTo: function(options) {
        router(options);
        history.pushState({url: options.url}, null, prefix + options.url);
    },
    navigateBack: function(options = {}) {
        let { delta = 1, success, fail, complete } = options;
        __currentPages.slice(0, -delta).forEach(page => {
            const url = page.props.url;
            history.pushState({url: url}, null, prefix + url);
        });
        const appInstance = React.__app;
        appInstance.setState({
            showBackAnimation: true
        });
        setTimeout(() => {
            while (delta && __currentPages.length) {
                __currentPages.pop();
                delta--;
            }
            const { path, query } = __currentPages[__currentPages.length - 1].props;
            React.api.redirectTo({url: path + parseObj2Query(query), success, fail, complete});
        }, 300);
    },
    switchTab: function({url, success, fail, complete}) {
        var [path, query] = getQuery(url);
        var config = React.__app.constructor.config;
        if (config && config.tabBar && config.tabBar.list) {
            if (config.tabBar.list.length < 2 || config.tabBar.list.length > 5) {
                console.warn('tabBar数量非法,必须大于2且小于5个');
                return;
            }
            if (config.tabBar.list.every(item => item.pagePath !== path.replace(/^\//, ''))) {
                console.warn(`${path}未在tabBar.list中定义!`);
                return;
            }
            __currentPages = [];
            this.navigateTo.call(this, {url, query, success, fail, complete});
        }
    },
    reLaunch: function({ url, success, fail, complete }) {
        __currentPages = [];
        this.navigateTo.call(this, { url, success, fail, complete });
    },
    setNavigationBarColor: function(options) {
        const processedOptions = Object.keys(options).reduce(function(accr, curr) {
            let key = titleBarColorMap[curr];
            return Object.assign({}, accr, { [key || curr]: options[curr] });
        }, {}) ;
        const currentPage = __currentPages.pop();
        __currentPages.push(cloneElement(currentPage, {
            config: processedOptions
        }));
        var appInstance = React.__app;
        appInstance.setState({});
    },
    setNavigationBarTitle: function(options) {
        const processedOptions = Object.keys(options).reduce(function(accr, curr) {
            let key = titleBarTitleMap[curr];
            return Object.assign({}, accr, { [key || curr]: options[curr] });
        }, {}) ;
        const currentPage = __currentPages.pop();
        __currentPages.push(cloneElement(currentPage, {
            config: processedOptions
        }));
        var appInstance = React.__app;
        appInstance.setState({});
    },
    stopPullDownRefresh: function() {
        const pageInstance = React.getCurrentPages().pop();
        React.getCurrentPages().push(cloneElement(pageInstance, {
            stopPullDownRefresh: true
        }));
        const appInstance = React.__app;
        appInstance.setState({});
    },
    createModal: function(instance) {
        return createPortal(instance, document.getElementsByClassName('__internal__Modal__')[0]);
    }
};
function getQuery(url) {
    var [path, query] = url.split('?');
    query = parseQueryStr2Obj(query);
    return [path, query];
}

function parseQueryStr2Obj(query) {
    if (typeof query === 'undefined') {
        return {};
    }
    return query.split('&').reduce(function(accr, curr) {
        if (curr === '') {
            return accr;
        }
        var temp = curr.split('=');
        accr[temp[0]] = temp[1];
        return accr;
    }, {});
}

function parseObj2Query(obj) {
    const keys = Object.keys(obj);
    return (keys.length ? '?' : '') + keys.map(key => `${key}=${obj[key]}`).join('&');
}

registerAPIs(React, apiContainer, more);
export default React;