{"id":20064867,"url":"https://github.com/baidu/san-factory","last_synced_at":"2025-05-05T18:31:03.899Z","repository":{"id":52896639,"uuid":"133775538","full_name":"baidu/san-factory","owner":"baidu","description":null,"archived":false,"fork":false,"pushed_at":"2021-04-14T19:44:00.000Z","size":114,"stargazers_count":16,"open_issues_count":0,"forks_count":10,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-21T21:04:12.793Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/baidu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-17T07:26:07.000Z","updated_at":"2023-03-27T08:48:41.000Z","dependencies_parsed_at":"2022-08-23T15:10:21.270Z","dependency_job_id":null,"html_url":"https://github.com/baidu/san-factory","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2Fsan-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2Fsan-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2Fsan-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2Fsan-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baidu","download_url":"https://codeload.github.com/baidu/san-factory/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252552947,"owners_count":21766803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T13:48:02.605Z","updated_at":"2025-05-05T18:31:03.542Z","avatar_url":"https://github.com/baidu.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# san-factory\n\n[![NPM version](http://img.shields.io/npm/v/san-factory.svg?style=flat-square)](https://npmjs.org/package/san-factory)\n[![License](https://img.shields.io/github/license/baidu/san-factory.svg?style=flat-square)](https://npmjs.org/package/san-factory)\n\n当我们在编写 [San](https://baidu.github.io/san/) 组件的时候，为了方便使用，通常会暴露给使用者组件的构造函数，即采用类似如下的方式编写：\n\n使用`san.defineComponent`创建：\n\n```js\nvar san = require('san');\nvar componentProto = {\n    template: '\u003cdiv\u003eHello {{name}}\u003c/div\u003e'\n};\n\nmodule.exports = san.defineComponent(componentProto);\n```\n\n继承`san.Component`创建：\n\n```js\nimport san from 'san';\n\nexport default class MyComponent extends san.Component {\n    static template = '\u003cdiv\u003eHello {{name}}\u003c/div\u003e';\n}\n```\n\n这样编写的组件有一些限制：\n\n- 在组件的实现中，静态地依赖了`san`的实现，因此也就无法满足动态注入`san`实现的场景\n- 如果组件内部实现依赖了其他的子组件，这个依赖也是静态的，没有办法动态地去替换子组件的实现。\n\nsan-factory 就是在这样的需求下诞生的。你可以从下面找到 san-factory 的下载和使用说明，也可以直接通过 [测试用例](./test/index.spec.js) 查看其是如何使用的。\n\n下载\n----\n\nNPM:\n\n```\n$ npm i san-factory\n```\n\n\n使用\n----\n\n### Webpack + Babel\n\n通过 import 导入\n\n```js\nimport san from 'san';\nimport SanFactory from 'san-factory';\n\nlet factory = new SanFactory({\n    san: san,\n    components: {\n        test: {\n            template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e'\n        }\n    }\n});\n\nlet instance = factory.createInstance({\n    component: 'test',\n    options: {\n        data: {\n            name: 'San'\n        }\n    }\n});\n\ninstance.attach(document.body);\n```\n\n### AMD\n\n通过 require 引入\n\n```js\nvar san = require('san');\nvar SanFactory = require('san-factory');\n\nvar factory = new SanFactory({\n    san: san,\n    components: {\n        test: {\n            template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e'\n        }\n    }\n});\n\nvar instance = factory.createInstance({\n    component: 'test',\n    options: {\n        data: {\n            name: 'San'\n        }\n    }\n});\n\ninstance.attach(document.body);\n```\n\n请为 amd loader 正确配置 san-factory 的引用路径。通过 npm 安装的项目可以采用下面的配置\n\n```js\nrequire.config({\n    baseUrl: 'src',\n    paths: {\n        'san-factory': '../dep/san-factory/dist/san-factory.source'\n    }\n});\n```\n\n开始使用\n----\n\n### 基本使用\n\nsan-factor 对外提供一个 `SanFactory` 的组件工厂类，这个类接收一个 `factoryConfig` 配置对象。该对象包含两个属性，`san`是你传入的 [San](https://baidu.github.io/san/) 框架实现，`components` 是你传入的组件 prototype 对象集合。\n\n下面是一个基本的示例：\n\n```js\nvar factory = new SanFactory({\n    san: san,\n    components: {\n        test: {\n            template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e'\n        }\n    }\n});\n```\n\n你可以使用 `createInstance` 方法，来获取 test 组件的一个实例：\n\n```js\nvar instance = factory.createInstance({\n    // 这里的 test 和创建工厂类时，components 字段的 test 字段的组件原型对应\n    component: 'test',\n    // 这里的 options 和 new ComponentClass(option) 中的 option 对应\n    // 关于 options 的更多细节还请参考 san 的官方文档\n    // @see: https://baidu.github.io/san/doc/api/#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%82%E6%95%B0\n    options: {\n        data: {\n            name: 'San'\n        }\n    }\n});\n```\n\n将这个实例当做正常的 San 组件实例即可。组件实例的方法请参考 [San 的官方文档](https://baidu.github.io/san/doc/api/#%E7%BB%84%E4%BB%B6%E6%96%B9%E6%B3%95)。\n\n```js\ninstance.attach(document.body);\n```\n\n当然，如果你想直接获取 test 组件的构造函数，可以通过 `getComponentClass` 直接获取。\n\n```js\nvar ComponentClass = factory.getComponentClass('test');\nvar instance = new ComponentClass({\n    data: {\n        name: 'San'\n    }\n});\ninstance.attach(document.body);\n```\n\n### 定义子组件\n\n在 San 里面，组件中通常通过声明自定义元素，使用其它组件，详见 [components文档](https://baidu.github.io/san/tutorial/component/#components)。下面是一个基本的例子：\n\n```js\nvar Title = san.defineComponent({\n    template: '\u003ch4\u003e{{text}}\u003c/h4\u003e'\n});\n\nvar Article = san.defineComponent({\n    template: ''\n        + '\u003cdiv\u003e'\n        + '  \u003cx-title text=\"{{title}}\"/\u003e'\n        + '  \u003cp\u003e{{text}}\u003c/p\u003e'\n        + '\u003c/div\u003e',\n    // 在 san 中，要求 components 字段的值是组件的类\n    components: {\n        'x-title': Title\n    }\n});\n```\n\n在 san-factory 中，`components` 字段支持的类型更加灵活，除了组件类和之外，你可以使用组件原型对象和对应 `factoryConfig.components` 对象中配置key字符串来配置依赖，如下面的例子：\n\n**使用组件原型对象**\n\n```js\nvar factory = new SanFactory({\n    san: san,\n    components: {\n        test: {\n            template: '\u003cdiv\u003e\u003cx-child name=\"{{name}}\"/\u003e\u003c/div\u003e',\n            components: {\n                'x-child': {\n                    template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e'\n                }\n            }\n        }\n    }\n});\n```\n\n**使用 factoryConfig.components 对象的 key 值**\n\n```js\nvar factory = new SanFactory({\n    san: san,\n    // factoryConfig.components 字段\n    components: {\n        // key 为 test 的组件原型对象，其 components 属性，包含了一个 'child' 值\n        test: {\n            template: '\u003cdiv\u003e\u003cx-child name=\"{{name}}\"/\u003e\u003c/div\u003e',\n            components: {\n                'x-child': 'child'\n            }\n        },\n        // 根据上面的 'child' 值，映射到对应的组件原型\n        child: {\n            template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e'\n        }\n    }\n});\n```\n\n这是一个非常强大的功能。他允许你在定义组件的时候，同一个父组件原型对象，其子组件只要key值和接口保持一致，可以通过key值进行任意组合。\n\n比如我编写了一个`form`组件的原型，其依赖了`x-input: 'input'`子组件。我可以创建多个工厂类，其包含不同的`components.input`。这样在不修改`form`组件实现的情况下，只要保证各个`input`的接口表现一致，就能保证逻辑组件可以正常工作。\n\n### 属性/接口注入\n\n用于在实例构造完毕后需要依赖的场景。在组件配置中，通过 `properties` 配置来声明属性/接口依赖：\n\n下面是一个例子：\n\n```js\nvar factory = new SanFactory({\n    san: san,\n    components: {\n        test: {\n            template: '\u003ch4\u003eHello {{name}}\u003c/h4\u003e',\n            setAdder: function (adder) {\n                this.add = adder;\n            }\n        }\n    }\n});\n\nvar instance = factory.createInstance({\n    component: 'test',\n    options: {\n        data: {\n            name: 'San'\n        }\n    },\n    properties: {\n        // 当属性名\n        adder: function (a, b) {\n            return a + b + 10;\n        },\n\n        max: function (a, b) {\n            return Math.max(a, b);\n        }\n    }\n});\n\ninstance.add(5, 10);        // 25\ninstance.max(5, 10);        // 10\n```\n\n`createInstance`方法会根据声明创建对应的依赖，按照以下步骤将依赖注入给实例：\n\n- 当定义`properties`字段时，`createInstance`方法将查找属性名称对应的setter方法(set${Name})，将依赖作为参数传入，返回。如上例中，`instanceConfig.properties.adder`作为参数传入了`factoryConfig.components.test.setAdder`，最终创建了`instance.add`方法。\n- 若实例不存在属性setter，则直接通过赋值的方式将依赖注入给实例，即：instance.propertyName = propertyValue。如上例中，`instanceConfig.properties.max`方法，直接创建了`instance.max`方法。\n\nAPI\n----\n\n### SanFactory\n\n`描述`：SanFactory({Object}factoryConfig)\n\n`说明`：\n\n组件工厂类。\n\n`参数`：\n\n- `Object` factoryConfig.san - 传入san环境\n- `Object` factoryConfig.components - 组件prototype对象集合\n\n#### createInstance\n\n`描述`：{san.Component} createInstance({Object}instanceConfig)\n\n`说明`\n\n根据`instanceConfig`创建一个组件实例。\n\n`参数`\n\n- `string|Object` instanceConfig.component - string类型时，为组件类名称，与factoryConfig.components的key对应；\n    Object类型时，组件原型对象，会创建匿名组件实例，组件类不会注册在factory中\n- `Object?` instanceConfig.properties - 注入实例属性的对象\n- `Object?` instanceConfig.options - 实例创建时的参数，详见[San文档](https://baidu.github.io/san/doc/api/#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%82%E6%95%B0)\n\n#### getComponentClass\n\n`描述`：{Function} getComponentClass({string}name)\n\n`说明`\n\n根据name（key值）获取组件类\n\n`参数`\n\n- `string` name - 组件类名称，与factoryConfig.components的key对应\n\n\n#### addComponent\n\n`描述`：{Function} addComponent({string}name, {Object}component)\n\n`说明`\n\n动态增加组件对象，如果组件名称已经存在则忽略\n\n`参数`\n\n- `string` name - 组件名称\n- `Object` components - 组件 prototype 对象\n\n#### addComponents\n\n`描述`：{Function} addComponents({Object}components)\n\n`说明`\n\n动态增加组件对象集合\n\n`参数`\n\n- `Object` components - 组件 prototype 对象集合，格式同 factoryConfig.components\n\n\n## ChangeLogs\n\n### 1.0.1\n\n- [feat] 增加 `addComponent` 和 `addComponents` 方法\n- [feat] 支持子组件循环引用\n\n### 1.1.0\n\n- [feat] `createInstance` 支持通过 组件原型对象 创建实例\n\n### 1.1.1\n\n- [feat] 增加 `_getAllComponentClasses` 方法\n\n### 1.1.2\n\n- [opti] 优化组件类定义过程，以提升性能\n- [opti] 增加子组件 ready 标记，避免组件编译过程再次遍历处理子组件\n\n\n## License\n\nSan is [MIT licensed](./LICENSE).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaidu%2Fsan-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaidu%2Fsan-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaidu%2Fsan-factory/lists"}