{"id":22378672,"url":"https://github.com/holyhigh2/compelem","last_synced_at":"2025-08-02T12:33:41.201Z","repository":{"id":298758831,"uuid":"928928917","full_name":"holyhigh2/compelem","owner":"holyhigh2","description":"A modern, reactive, fast, lightweight and flexible lib for building web components","archived":false,"fork":false,"pushed_at":"2025-07-24T09:17:45.000Z","size":307,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-31T02:19:34.103Z","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/holyhigh2.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-07T13:53:22.000Z","updated_at":"2025-07-24T09:17:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"e41e289d-bd29-414e-8306-e42208b9785f","html_url":"https://github.com/holyhigh2/compelem","commit_stats":null,"previous_names":["holyhigh2/compelem"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/holyhigh2/compelem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holyhigh2%2Fcompelem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holyhigh2%2Fcompelem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holyhigh2%2Fcompelem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holyhigh2%2Fcompelem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/holyhigh2","download_url":"https://codeload.github.com/holyhigh2/compelem/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holyhigh2%2Fcompelem/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268257512,"owners_count":24221061,"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","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-12-04T23:07:03.333Z","updated_at":"2025-08-02T12:33:41.182Z","avatar_url":"https://github.com/holyhigh2.png","language":"JavaScript","readme":"# CompElem\n一个现代化、响应式、快速、轻量的WebComponent开发库。为开发者提供丰富、灵活、可扩展的声明式接口\n\n## 概览  \nCompElem 基于 Class 进行构建，该模型允许开发者使用装饰器进行声明式编码，核心特性包括：\n- 类JSX的原生模板系统\n- 丰富的装饰器及指令\n- 可选的生命周期\n- 原生插槽系统\n- 响应式域样式\n- ...\n\n创建一个WebComponent总会从声明一个组件元素(CompElem子类)开始\n```ts\nconst Slogan = ['complete', 'componentize', 'compact', 'companion']\n@tag(\"page-test\")\nexport class PageTest extends CompElem {\n  //////////////////////////////////// props\n  @prop arg:any\n\n  @state colorR = Math.random() * 255 % 255 \u003e\u003e 0;\n  @state colorG = Math.random() * 255 % 255 \u003e\u003e 0;\n  @state colorB = Math.random() * 255 % 255 \u003e\u003e 0;\n  @state rotation = 0\n\n  //////////////////////////////////// computed\n  @computed\n  get color() {\n    return `linear-gradient(90deg,rgb(${this.colorR},${this.colorG},${this.colorB}), rgb(${255 - this.colorR},${255 - this.colorG},${255 - this.colorB}));`\n  }\n\n  //////////////////////////////////// watch\n  @watch('rotation')\n  function(nv:number) {\n    console.log(nv)\n  }\n\n  //////////////////////////////////// styles\n  //静态样式\n  static get styles(): Array\u003cstring | CSSStyleSheet\u003e {\n    return [`:host{\n        font-size:16px;\n      }...`];\n  }\n  //动态样式\n  get styles() {\n    return [\n      () =\u003e `h2,p,i,h3{\n        background-image:${this.color};\n      }`,\n      () =\u003e `h2,p,i,h3{\n        filter:hue-rotate(${this.rotation}deg);\n      }`,\n    ]\n  }\n\n  @query('i[name=\"text\"]')\n  text: HTMLElement\n  sloganIndex = 0\n\n  //////////////////////////////////// lifecycles\n  mounted(): void {\n    setInterval(() =\u003e {\n      this.rotation += 1\n    }, 24);\n\n    setInterval(() =\u003e {\n      this.text.classList.add('hide')\n      setTimeout(() =\u003e {\n        this.text.innerHTML = Slogan[this.sloganIndex % 4]\n        this.sloganIndex++\n        this.text.classList.remove('hide')\n      }, 500);\n    }, 5000);\n  }\n  render(): Template {\n    return html`\u003cdiv\u003e\n            \u003ci\u003eWelcome to\u003c/i\u003e\n            \u003cbr\u003e\n            \u003ch2\u003eCompElem\u003c/h2\u003e\n            \u003cbr\u003e\n            \u003ci\u003eA modern, reactive, fast and lightweight library\u003c/i\u003e\n            \u003cbr\u003e\n            \u003ci\u003efor building\u003c/i\u003e\n            \u003ch3\u003eWeb Components\u003c/h3\u003e\n            \u003cp\u003e\n              \u0026lt;c-element\u0026gt; \u003ci name=\"text\"\u003e...\u003c/i\u003e \u0026lt;/c-element\u0026gt;\n            \u003c/p\u003e\n            ${this.arg}\n        \u003c/div\u003e`\n  }\n}\n```\n而后即可在HTML中直接使用，与使用一个原生元素如DIV没有任何区别\n```html\n\u003cbody\u003e\n    \u003cpage-test arg=\"args...\"\u003e\u003c/page-test\u003e\n\u003c/body\u003e\n```\n当然,也可以直接嵌入其他UI库中只要引入编译后的js即可\n\n## APIs  \n- ### 视图模板\n  使用`render()`函数定义组件视图模板\n  ```ts\n  render(): Template{\n    return html`\u003cdiv\u003eHello CompElem\u003c/div\u003e`\n  }\n  ```\n- ### 视图模板-属性表达式\n\n  通过再视图模板中插入表达式可以实现动态视图，表达式通过在不同位置使用分为不同类型见（#### 指令类型）。其中属性表达式根据前缀分为\n\n  | 前缀 | 描述                                                          | 示例                                   |\n  | ---- | ------------------------------------------------------------- | -------------------------------------- |\n  | @    | 事件属性，可用于任何标签                                      | `\u003cdiv @click=\"${this.onClick}\"\u003e`       |\n  | .    | 参数属性，仅用于给组件标签传递参数                            | `\u003cl-input .value=\"${this.text}\"\u003e`      |\n  | ?    | 可选属性，用于 disabled/readonly 等 toggle 类属性             | `\u003cinput ?disabled=\"${this.disabled}\"\u003e` |\n  | \\*   | 引用属性，表达式求值后才会设置该属性。常用于 SVG 相关属性设置 | `\u003ccircle *r=\"${this.r}\"\u003e`              |\n\n  \u003e 引用属性可通过属性参数进行格式转换，如\n\n  ```ts\n  render(): Template{\n    return html`\u003csvg *view-box:camel=\"\"\u003e...\u003c/svg\u003e`// \u003csvg viewBox=\"\"\u003e\n  }\n  ```\n\n  支持格式包括:\n\n  - camel 驼峰式\n  - kebab 短横线\n  - snake 下划线\n\n- ### 样式\n  使用静态函数定义组件样式或全局样式（如弹框）\n  ```ts\n  static get styles(): Array\u003cstring | CSSStyleSheet\u003e {\n    return [];\n  }\n  static get globalStyles(): Array\u003cstring\u003e {\n    return [];\n  }\n  ```\n  对于需要动态控制 host 元素样式可以使用组件实例 getter\n  ```ts\n  get styles(){\n    return [()=\u003e`:host{\n      ${this.border?'border: 1px solid rgb(var(--l-color-border-secondary)); ':''}\n    }`]\n  }\n  ```\n- ### 属性\n\n  属性是由组件外部提供参数的响应变量，可通过`@prop`注解定义\n\n  ```ts\n  @prop({ type: Boolean }) loading = false;//显式定义属性类型\n  @prop round = true;//通过默认值自动推断属性类型\n  @prop({ type: [Boolean,String] }) round = true;//多种类型使用数组定义\n  @prop({ type: Array }) datalist: Array\u003cstring\u003e;//没有默认值必须显式指定属性类型\n  @prop({ type: [String, Number], sync: true }) //通过get/set设置属性\n  get value() {\n    return this.__innerValue ?? ''\n  }\n  set value(v: any) {\n    this.__innerValue = v\n    if (isNil(v)) {\n      this.__innerValue = '';\n    }\n  }\n  ```\n\n  属性可以在组件内修改但默认不会同步父组件，除非显式指定`sync`或自行 emit update 事件\n  全部注解参数见 `PropOption`\n\n- ### 状态\n  状态是仅由组件内部初始化的响应变量，可通过`@state`注解定义\n  ```ts\n  @state hasLeft = false;//定义状态\n  @state({//自定义变化判断\n    hasChanged(nv: any[], ov: any[]) {\n      return isEqual(nv , ov)\n    }\n  }) private nodes: Array\u003cRecord\u003cstring, any\u003e\u003e;\n  ```\n  状态仅能在组件内修改\n  全部注解参数见 `StateOption`\n- ### 状态监视\n\n  使用`@watch`注解可以对属性/状态进行变化监视\n\n  ```ts\n  @prop width = \"auto\";\n\n  @watch(\"width\", { immediate: true })\n  watchWidth(nv: string, ov: string, sourceName: string) {\n    this.style.width = nv;\n  }\n  ```\n\n  对于同类属性共享处理逻辑的监视，可以批量处理\n\n  ```ts\n  @watch(['height', 'minHeight', 'maxHeight'], { immediate: true })\n  watchHeight(nv: string, ov: string, sourceName: string) {\n    this.style[srcName] = nv;\n  }\n  ```\n\n- ### 计算状态\n  计算状态会缓存 return 结果，只有当内部使用的任意属性/状态发生变化时才会重新计算\n  使用`@computed`注解的 Getter，如\n  ```ts\n  @computed\n  get hasHeader() {\n    return !isEmpty(this.slots.header) || !!this.header\n  }\n  ```\n- ### 节点引用\n  使用`@query/all`注解及`ref`属性\n  ```ts\n  //query\n  @query('l-icon')\n  iconEl: HTMLElement\n  //ref\n  refNode: HTMLElement\n  ```\n  ref可用于内部DOM被移出但仍需访问的场景，比如tooltip、toast、overlay等\n  ```ts\n  divRef = createRef\u003cHTMLDivElement\u003e();\n  //视图片段\n  return html` \u003cl-icon\u003e\u003c/l-icon\u003e\n    \u003cdiv ref=\"${divRef}\"\u003e\u003c/div\u003e`;\n  ```\n- ### 内置属性及函数\n  - `readonly` parentComponent 父组件引用，可能为空\n  - `readonly` wrapperComponent 包装(组件所在视图归属)组件引用，可能为空\n  - `readonly` renderRoot/renderRoots 渲染根元素/渲染根元素列表\n  - `readonly` shadowRoot 阴影DOM\n  - `readonly` slots 插槽元素映射\n  - `readonly` slotHooks 动态插槽钩子映射\n  - `readonly` css 组件样式对象列表\n  - `readonly` attrs 组件特性\n  - `readonly` props 组件属性\n  - slotComponent 所在插槽组件\n  - on(evName: string, hook: (e: Event) =\u003e void) 在root元素上绑定事件\n  - emit(evName: string, arg: Record\u003cstring, any\u003e, options?: {event?: Event;bubbles?: boolean;composed?: boolean;}) 抛出自定义事件\n  - nextTick(cbk: () =\u003e void) 下一帧执行函数\n  - forceUpdate() 强制更新一次视图\n\n## 组件渲染流程\n\nCompElem 组件既可以在 CompElem 环境内调用，也可以直接在原生环境调用，区别只是原生环境无法像组件传`递类型参数`。流程如下：\n\n\u003e 创建流程\n\n| 功能                                                         |     | 生命周期    |\n| ------------------------------------------------------------ | --- | ----------- |\n| 1. 创建组件实例，完成类属性默认值设置（prop/state/...)       |     |             |\n| 2. 初始化类全局样式（仅一次）及 实例样式(产生 styles 数组)   |     |             |\n| 3. 创建 shadowRoot 并挂载组件样式                            |     |  |\n| 4. 执行装饰器 create 回调                                      |     |    constructor         |\n| 5. 绑定 parentComponent                                               |     |    |\n| 6. 验证及初始化 props |     |  propsReady |\n| 7. 初始化 states |     |   |\n| 8. @computed                       |     |             |\n| 9. @watch(immediate)                       |     |             |\n| 10. 渲染 render 及依赖绑定                                    |     | render      |\n| 11. 绑定 renderRoot 及 renderRoots                                            |     |             |\n| 12. 初始化插槽 slots                                            |     |     |\n| 13. 执行装饰器 beforeMount 回调 ，如 @query                                     |     |    beforeMount      |\n| 14. 初始化动态 css                                                   |     |     mounted        |\n| 15. 执行装饰器 mounted 回调                                |     |             |\n\n\u003e 更新流程【普通】\n\n| 功能                           | 生命周期     |\n| ------------------------------ | ------------ |\n| 1. 父组件 props 变更【或】     | propsReady   |\n| 1. 子组件 states 变更【或】     |              |\n| 2. 执行@watch 注解             |              |\n| 3. 合并变更内容并判断是否更新  | shouldUpdate |\n| 4. 更新依赖域指令（非 render） |              |\n| 5. 更新动态 slot               |              |\n| 6. 执行 ref                    |              |\n| 7. 执行@query 注解             | update       |\n\n\u003e 更新流程【强制】\n\n| 功能               | 生命周期 |\n| ------------------ | -------- |\n| 1. forceUpdate     |          |\n| 2. 渲染 render     | render   |\n| 3. 执行@query 注解 | update   |\n\n## 插槽 Slot\n\n#### 定义插槽\n\n使用原生 `\u003cslot\u003e\u003c/slot\u003e` 标签来嵌入插槽\n\n```html\n\u003cslot\u003e\u003c/slot\u003e\n\u003c!-- 命名插槽 --\u003e\n\u003cslot name=\"content\"\u003e\u003c/slot\u003e\n```\n\n#### 插入节点(静态)\n\n```html\n\u003cl-tooltip\u003e\n  \u003cl-button\u003e默认插槽内容\u003c/l-button\u003e\n  \u003cdiv slot=\"content\"\u003e命名插槽内容\u003c/div\u003e\n\u003c/l-tooltip\u003e\n```\n\n#### 插入节点(动态)\n\n动态内容插入仅可在 CompElem 组件中编码，可以通过组件注入参数动态生成插槽内容\n\n```ts\n//仅可用于CompElem组件中\nreturn html` \u003cl-tooltip\u003e\n  //动态内容通过slot指令定义 ${slot(\n    (args: Record\u003cstring, any\u003e) =\u003e html`\n      \u003cdiv\u003e我是动态内容-${args.data.id}\u003c/div\u003e\n    `,\n    \"content\"\n  )}\n\u003c/l-tooltip\u003e`;\n```\n\n在`slot`标签上注入参数\n\n```html\n\u003cslot .data=\"${this.row}\"\u003e\u003c/slot\u003e\n```\n\n**_注意_**，动态插槽必须关闭自动插槽，否则无效\n\n```ts\nstatic get autoSlot() {\n  return false;\n}\n```\n\n## 指令 Directive\n\n指令用于分支/循环/动态插槽等结构及隐藏显示等\n\n#### 指令类型\n\n不同的指令类型限制了指令仅能用于对应的插入点\n|指令|插入位置|描述|示例|  \n|-------|-------|-------|-------|\n|ATTR|特性|可用于任何特性值之中，仅能插入一个|`attr=\"${xxx}\"`|\n|PROP|属性|可用于任何属性值之中，必须是组件标签，仅能插入一个|`.value=\"${xxx}\"`|\n|TEXT|文本|标签体内，可插入多个|`\u003cdiv\u003e${xx1}${xx2}${...}\u003c/div\u003e`|\n|CLASS|样式类|用于 class 属性值中，仅能插入一个|`class=\"a ${b}\"`|\n|STYLE|样式规则|用于 style 属性值中，仅能插入一个|`style=\"a:1;${b}\"`|\n|SLOT|插槽|与 TEXT 类似，但标签必须是组件||\n|TAG|标签|直接插入在节点标签上|`\u003cdiv a=\"b\" ${show(..)}\u003e`|\n\n#### 内置指令\n\n| 指令    | 类型      | 描述                                                        | 示例                                                   |\n| ------- | --------- | ----------------------------------------------------------- | ------------------------------------------------------ |\n| bind    | TAG       | 绑定属性/特性到标签上，根据标签类型及组件 prop 定义自动判断 | `\u003cdiv a=\"b\" ${bind(obj)}\u003e`                             |\n| show    | TAG       | 隐藏/显示标签（基于 display）                               | `\u003cdiv a=\"b\" ${show(visible)}\u003e`                         |\n| model   | TAG       | 双向绑定                                                    | `\u003cdiv a=\"b\" ${model(xx,modelPath?)}\u003e`                             |\n| classes | CLASS     | 绑定样式类属性，支持对象/数组/字符串。可以和静态字符混用    | `\u003cdiv class=\"otherClass ${classes(obj)}\u003e\"`             |\n| styles  | STYLE     | 绑定样式规则属性，支持对象/字符串。可以和静态字符混用       | `\u003cdiv style=\"a:b;${styles(obj)}\u003e\"`                     |\n| forEach | TEXT/SLOT | 输出循环结构                                                | `...\u003e${forEach(ary,(item)=\u003ehtml`...`)}\u003c...`            |\n| ifTrue  | TEXT/SLOT | 当条件为 true 时输出模板内容                                | `...\u003e${ifTrue(condition,()=\u003ehtml`...`)}\u003c...`           |\n| ifElse  | TEXT/SLOT | 当条件为 true/false 时输出对应模板内容                      | ` ...\u003e${ifElse(condition,()=\u003ehtml``,()=\u003ehtml``)}\u003c... ` |\n| when    | TEXT/SLOT | 多条件分支，支持 switch/ifelse 两种模式                     | ` ...\u003e${when(condition,{c1:()=\u003ehtml``,c2:...})}\u003c... `  |\n| slot    | SLOT      | 动态插槽                                                    | ` ...\u003e${slot((args) =\u003e html``)}\u003c... `                  |\n\n## 装饰器 Decorator\n\n- @state 定义组件内状态属性。可选参数{prop}，可指定 propName 初始化值\n- @prop 定义父组件参数，默认不可修改。可选参数{type,required,sync,getter,setter}\n  \u003e 设置 getter/setter 后，该属性的`@watch` 将会失效\n- @query/queryAll 定义 CssSelector 查询结果\n- @tag 自定义组件的标签名\n- @event 定义全局事件\n- @watch 监控 state/prop 变更\n- @computed 计算属性，仅在响应变量变更时更新缓存值\n- @debounced 定义函数防抖\n\n#### 继承\n  部分指令可由子类继承不会覆盖，包括@state/@prop/@watch/@computed\n\n## 事件\n\n在CompElem中事件分为三类\n\n1. 原生事件 —— `\u003cdiv @click=\"...\"`，监听器回调参数返回原生事件对象\n2. 扩展原生事件 —— `\u003cdiv @resize=\"...\"`，监听器回调参数返回`CustomEvent`事件对象\n3. 组件自定义事件 —— `\u003cl-select @change=\"...\"`，监听器回调参数返回`CustomEvent`事件对象\n\n### 事件修饰符\n通过`.`号可使用修饰符修饰事件如 `@scroll.throttle:100=\"${...}\"`\n- 全部通用 —— `debounce/throttle/once` 可组合\n- 原生通用 —— `stop/prevent/self` 可组合\n- 鼠标 —— `left/right/middle` 不可组合\n- 键盘 —— `ctrl/alt/shift/meta` 可组合 `esc/a/b/c/d...` 不可组合,多个key并列表示可选\n- mutate —— `attr/child/char/tree` 可组合\n\u003e 部分修饰符支持参数，可使用冒号传参 —— `throttle:100 / debounce:100`。支持列表如下\n  - throttle:wait\n  - debounce:wait\n  ```html\n  \u003c!-- 示例 --\u003e\n  \u003cdiv @mutate.child.throttle:100=\"...\"\u003e\n  \u003cdiv @click.left.once=\"...\"\u003e\n  \u003cdiv @mousedown.stop.prevent=\"...\"\u003e\n  ```\n### 扩展原生事件\n可直接用于DOM元素的扩展事件（非组件事件），支持列表如下\n- resize 元素尺寸变化时触发\n- outside 鼠标点击元素外部时触发，可通过修饰符限制鼠标点击类型`outside.[mousedown/up/click/dblclick]`，默认click\n- mutate 内容变化时触发。基于  Mutation Observer API","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholyhigh2%2Fcompelem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fholyhigh2%2Fcompelem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholyhigh2%2Fcompelem/lists"}