npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@schema-plugin-flow/sifo-react

v1.6.0

Published

A highly extensible JavaScript library, for React. 高扩展性、可二开的插件式前端开发框架

Downloads

10

Readme

sifo-react

sifo-react 是组装了sifo-modelsifo-singleton 的一个React组件。

sifo-react 以 sifo-model 为内核,使用插件式的开发模式,为页面提供了多级定制与扩展能力。包含但不限于:页面结构的修改、渲染组件的替换、组件属性的变更、组件事件的监听与阻断等。结合不同的模型插件,可以实现更加丰富的特定功能。

  • 插件示例

codesandbox.io

SifoApp (sifo-react) Props

参数 | 说明 | 类型 | 是否必传 | 默认值 -------------|-------------|-----|-----|----- namespace | 命名空间,这是一个功能集合的主要标识,第三方将根据命名空间来进行功能扩展 | string | 是 | - | schema | schema,描述了页面结构 | object | 是 | - | components | 组件 | object | 是 | {} | plugins | 插件,分为模型插件、页面插件和组件插件 | array:[{ componentPlugin, pagePlugin, modelPlugin }, { modelPlugin: otherModelPlugin }] | 否 | [] | externals | 任意其它信息 | object | 否 | {} | sifoExtProps | 任意对象,mApi.getSifoExtProps 可以取到即时的值,这点与 externals 相区别 | object | 否 |{}| modelApiRef | 模型接口外传方法,调用参数为 mApi(接口构建完成时) 或 null(模型销毁时) | function | 否 | openLogger | 是否在控制台打印出执行日志,不建议在生产环境使用 | bool | 否 | false | getModelPluginArgs | 获取模型插件实例化时的构造函数参数 | function:(modelPluginId, info) => ([arg1, arg2, ...]) | 否 | | - | className | 样式类 |string | 否 | |

扩展的 mApi 模型接口

mApi说明

| 方法名 | 参数/类型 | 返回值类型 | 描述 | | ---------------- | -----------------------| --------------------- | ---------------------------------------------------------------------------------------------------| | getSifoExtProps | ✘ | 任意对象 | 获取 SifoApp.sifoExtProps 即时的值 |

如何使用

  • 项目

    • extend.js

      import SifoSingleton from '@schema-plugin-flow/sifo-singleton';
      const singleton = new SifoSingleton('quick-start'); // target namespace
      singleton.registerItem('testExtendId', () => {
        return {
          plugins,
          components
        }
      });
    • app.js

      import React from 'react';
      import ReactDOM from "react-dom";
      import SifoApp from '@schema-plugin-flow/sifo-react';
      class App extends React.Component {
        render() {
          return (
            <SifoApp
              namespace='quick-start'
              components={components}
              schema={schema}
              plugins={plugins}
            />
          );
        }
      }
      ReactDOM.render(
        <App />
        rootElement
      );
  • runtime

    • load extend js

    • load app js

      你应该在 sifoApp 渲染前加载扩展 js 资源

      <script src="extend.js"></script>
      <script src="app.js"></script>

QuickStart

下面的例子演示了如何监听一个按钮组件的点击事件,并在点击事件中修改其它组件的属性,同时也演示了多个插件的情形。想了解更多的功能请参考sifo-model

import React from 'react';
import SifoApp from '@schema-plugin-flow/sifo-react';
// 一些组件
const Container = props => <div {...props} />;
const Slogan = ({ content, ...other }) => <h2 {...other}>{content}</h2>;
const Button = props => <button {...props}>click to change</button>;
// schema 定义了初始的页面结构
const schema = {
  component: "Container",
  id: 'mainId',
  attributes: {},
  children: [
    {
      component: "Slogan",
      id: 'slogan_id',
      attributes: {
        content: 'hello world'
      }
    },
    {
      component: "Button",
      id: 'test_btn_id',
      attributes: {}
    }
  ]
};
// 组件插件可以实现与组件相关的功能
const componentPlugin1 = {
  test_btn_id: {
    onComponentInitial: params => {
      const { event, mApi } = params;
      mApi.addEventListener(event.key, 'onClick', (context, e) => {
        mApi.setAttributes('slogan_id', {
          content: 'hello sifo'
        });
      })
    }
  }
};
// 第二个插件
const componentPlugin2 = {
  test_btn_id: {
    onComponentInitial: params => {
      const { event, mApi } = params;
      mApi.addEventListener(event.key, 'onClick', () => {
        console.log('test_btn_id clicked!')
      })
    }
  }
};
const components = { Container, Slogan, Button };
const plugins = [
  { componentPlugin: componentPlugin1 },
  { componentPlugin: componentPlugin2 }
];
class App extends React.Component {
  render() {
    return (
      <SifoApp
        className='quick-start'
        namespace='quick-start'
        components={components}
        schema={schema}
        plugins={plugins}
        openLogger={false}
      />
    );
  }
}
export default App;

外部扩展

如果一个页面是用 sifo 开发的,开发者可以在不接触原始代码的情况下,对页面进行扩展。这里用到了 sifo-singleton 全局扩展容器,只要在目标页面渲染前载入了扩展插件、组件,扩展功能就会在目标页面上生效。

import SifoSingleton from '@schema-plugin-flow/sifo-singleton';
const singleton = new SifoSingleton('test_namespace');// 对目标命名空间进行扩展
// 插件的功能与使用跟前面的示例完全一致
const plugins = [{ pagePlugin, componentPlugin }];
const components = {};
singleton.registerItem('testExtendId', () => {
  return {
    plugins,
    components,
    openLogger: true, 
  }
});

sifoAppDecorator

为一个组件追加扩展能力时,可用修饰器方式。sifoAppDecorator 第一个参数是命名空间,第二个参数与上文的“SifoApp参数”一致(namespace 和 schema 除外)。此外还增加了如下参数:

参数 | 说明 | 类型 | 是否必传 | 默认值 -------------|-------------|-----|-----|----- fragments | 片段列表。片段可以只定义一个id,通过 getFragment 方法获取片段来渲染;也可以传一个 schema,以 schema 的第一层 id 来标识 | array | 否 | - |

被 sifoAppDecorator 修饰的组件,props 中将出现 sifoApp 对象,对象包含 addEventListener、 watch、getFragment 等方法和 mApi 接口。

sifoAppDecorator 示例

下面的示例包含:

  • View 组件标注命名空间为 main_namespace;
  • View 组件向外暴露 onSubmit、setState、onChange 事件,扩展件就可以监听与干预这些事件;
  • View 注册了 getState、setState 观测,扩展件可以发布相应观测消息来与 View 通信;
  • View 定义了 $header 片段,以使扩展件可以在页面指定位置渲染内容。 完整示例请参照这里
import React from 'react';
import { sifoAppDecorator } from '@schema-plugin-flow/sifo-react';
@sifoAppDecorator('main_namespace', {
  fragments: ['$testFragment', '$fragment2', innerSchema],
  components: {},
  plugins: [],
  openLogger: true
})
class View extends React.Component {
  constructor(props) {
    super(props);
    const { sifoApp } = props;
    this.state = { value: '' };
    // 加入事件监听,这些事件实际上是挂在了以当前命名空间为id的schema节点上
    this.onSubmit = sifoApp.addEventListener('onSubmit', this.onSubmit);
    this.setState = sifoApp.addEventListener('setState', this.setState.bind(this));
    // prepose传入true可使事件先于扩展件注册,在希望外部能够覆盖(扩展)内部方法时可使用
    this.onChange = sifoApp.addEventListener('onChange', this.onChange, true); 
    // 注册观测任务
    sifoApp.watch('getState', (context, getter) => {
      getter(this.state);
    });
    sifoApp.watch('setState', (context, state) => {
      this.setState({
        ...state
      });
    });
  }
  onSubmit = () => {
    //...
  }
  onChange = () => {
    //...
  }
  render() {
    // 将声明的片段放到指定的位置,扩展插件就可以在相应位置渲染自定义的内容了
    const testFragment = this.props.sifoApp.getFragment('$testFragment');
    // 动态传参
    const testFragment2 = this.props.sifoApp.getFragment('$fragment2', {
      stateValue: this.state.value, others: {}
    });
    return (
      <Comp
        onChange={this.onChange}
        onSubmit={this.onSubmit}
      >
        {testFragment}
        {testFragment2}
      </Comp>
    )
  }
}

sifoAppDecorator 下的外部扩展示例

import React from 'react';
import SifoSingleton from '@schema-plugin-flow/sifo-singleton';
// 
const pagePlugin = {
  onNodePreprocess: (node, info) => {
    const { id, component } = node;
    // sifoAppDecorator 内置了 $sifo-header 和 $sifo-footer 两个节点
    if (id === '$sifo-header') {
      return {
        ...node,
        attributes: {},
        children: ['this is ext-header']
      }
    }
    if (id === '$sifo-footer') {
      return {
        ...node,
        children: ['this is ext-footer']
      }
    }
    if (id === '$fragment2') {
      // 将片段直接换成新的组件,这个组件就可以拿到getFragment的参数
      return {
        ...node,
        component: 'DynamicPropsCom'
      }
    }
    if (id === '$testFragment') {
      return {
        ...node,
        children: [
          {
            component: 'Input',
            id: 'custom'
          }
        ]
      }
    }
    return node;
  },
}
const componentPlugin = {
  // 命名空间认作根节点id
  main_namespace: {
    onComponentInitial: params => {
      const { event, mApi } = params;
      mApi.addEventListener(event.key, 'onSubmit', (context, e) => {
      });
      mApi.addEventListener(event.key, 'onChange', (context, e) => {
        mApi.dispatchWatch('setState', { testState: 'test' })
      });
      mApi.addEventListener(event.key, 'setState', (e, state) => {
        const nextState = {
          ...state,
          customState: new Date().getMilliseconds()
        };
        e.event.next(nextState);
      });
    }
  },
  custom: {
    onComponentInitial: params => { }
  }
};
const singleton = new SifoSingleton('main_namespace');
singleton.registerItem('this_ext_id', () => {
  return {
    plugins: [
      {
        pagePlugin,
        componentPlugin
      }
    ]
  }
});
//
export default {};

在函数式组件上使用

import React from 'react';
import { sifoAppDecorator } from "@schema-plugin-flow/sifo-react";
const TestFnDecorator = props => {
    const { sifoApp } = props;
    console.log('render ---- mApi instance:', sifoApp.mApi.instanceId);
    const dynamicPanel = sifoApp.getFragment('$temp_panel', { 
      stateValue: '函数式',
      others: { ok: true } 
    });
    return (
      <div>
      <h3>函数式组件</h3>
        { dynamicPanel }
      </div>
    );
}
const App = sifoAppDecorator('test-sifo-decorator', {
  externals: { aa: 1 },
  fragments: ['$temp_panel'],
  className: "decorator-fn-test",
  openLogger: true
})(TestFnDecorator);
export default App;

非标准的组件接入

const TestComponent = {
  name: "TestNonStandard", // 组件名
  useSifoRenderProxy: true, // 标注组件需要使用代理
  /**
   * 渲染方法
   * target: dom对象
   * props: 属性
   * update: 是否是更新
   * preInstance: 前一个render调用返回的对象(更新时)
   */
  render: (target, props, update, preInstance) => {
    // Svelte 组件
    // if (!update) {
    //   return renderTest(props, props.children, target); // 返回instance
    // } else {
    //   preInstance.update(props);
    //   return preInstance;
    // }
    ReactDOM.render(React.createElement(Demo, props), target); // react
  },
  /**
   * 卸载方法,如果不传,默认调用 ReactDOM.unmountComponentAtNode(target);
   */
  unmount: (target, instance) => {
    // instance.unmount(target);
    ReactDOM.unmountComponentAtNode(target); // react
  }
  /**
   * 渲染类型:normal 指在每次react节点渲染时调用render方法,rerenderKey 指在 props.rerenderKey 变化时才调用render方法,默认为 normal,也可以在 props.rerenderType 中指定渲染类型。
   */
  rerenderType: "normal",// "normal"|"rerenderKey"
}

模型插件推荐列表