feat(vue-components): 添加页面片容器id prop

This commit is contained in:
roymondchen 2025-07-15 15:31:51 +08:00
parent 1736d495fd
commit a43825caa2
30 changed files with 285 additions and 1284 deletions

View File

@ -68,7 +68,7 @@
"prettier": "^3.5.3", "prettier": "^3.5.3",
"recast": "^0.23.11", "recast": "^0.23.11",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^4.44.1", "rollup": "^4.45.0",
"rollup-plugin-dts": "^6.2.1", "rollup-plugin-dts": "^6.2.1",
"semver": "^7.7.1", "semver": "^7.7.1",
"serialize-javascript": "^6.0.2", "serialize-javascript": "^6.0.2",

1398
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,6 @@ packages:
catalog: catalog:
vue: ^3.5.17 vue: ^3.5.17
'@vue/compiler-sfc': ^3.5.17 '@vue/compiler-sfc': ^3.5.17
vite: ^7.0.0 vite: ^7.0.3
typescript: "^5.8.3" typescript: "^5.8.3"

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.1", "version": "0.2.0",
"name": "@tmagic/react-runtime-help", "name": "@tmagic/react-runtime-help",
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,
@ -31,8 +31,8 @@
}, },
"peerDependencies": { "peerDependencies": {
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"@tmagic/core": ">=1.5.0", "@tmagic/core": ">=1.6.0-beta.0",
"@tmagic/stage": ">=1.5.0", "@tmagic/stage": ">=1.6.0-beta.0",
"react": ">=18.3.1", "react": ">=18.3.1",
"typescript": "catalog:" "typescript": "catalog:"
}, },

View File

@ -20,7 +20,7 @@
}, },
"dependencies": { "dependencies": {
"@tmagic/core": "1.6.0-beta.0", "@tmagic/core": "1.6.0-beta.0",
"@tmagic/react-runtime-help": "0.1.1", "@tmagic/react-runtime-help": "0.2.0",
"@tmagic/stage": "1.6.0-beta.0", "@tmagic/stage": "1.6.0-beta.0",
"axios": "^1.10.0", "axios": "^1.10.0",
"react": "^18.3.1", "react": "^18.3.1",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.5.18", "version": "1.6.0-beta.0",
"name": "@tmagic/ui", "name": "@tmagic/ui",
"type": "module", "type": "module",
"main": "dist/tmagic-ui.js", "main": "dist/tmagic-ui.js",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.1.5", "version": "1.2.1",
"name": "@tmagic/vue-runtime-help", "name": "@tmagic/vue-runtime-help",
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,
@ -30,8 +30,8 @@
"vue-demi": "^0.14.10" "vue-demi": "^0.14.10"
}, },
"peerDependencies": { "peerDependencies": {
"@tmagic/core": ">=1.5.0", "@tmagic/core": ">=1.6.0-beta.0",
"@tmagic/stage": ">=1.5.0", "@tmagic/stage": ">=1.6.0-beta.0",
"@vue/composition-api": ">=1.7.2", "@vue/composition-api": ">=1.7.2",
"typescript": "catalog:", "typescript": "catalog:",
"vue": ">=2.6.0 || >=3.5.0" "vue": ">=2.6.0 || >=3.5.0"

View File

@ -21,20 +21,20 @@
"dependencies": { "dependencies": {
"@tmagic/core": "1.6.0-beta.0", "@tmagic/core": "1.6.0-beta.0",
"@tmagic/stage": "1.6.0-beta.0", "@tmagic/stage": "1.6.0-beta.0",
"@tmagic/vue-runtime-help": "^1.1.5", "@tmagic/vue-runtime-help": "^1.2.0",
"axios": "^1.10.0", "axios": "^1.10.0",
"vue": "^2.7.16" "vue": "^2.7.16"
}, },
"devDependencies": { "devDependencies": {
"@tmagic/cli": "1.6.0-beta.0", "@tmagic/cli": "1.6.0-beta.0",
"@types/events": "^3.0.3", "@types/events": "^3.0.3",
"rollup": "^4.44.1", "rollup": "^4.45.0",
"rollup-plugin-external-globals": "^0.13.0", "rollup-plugin-external-globals": "^0.13.0",
"sass": "^1.89.2", "sass": "^1.89.2",
"terser": "^5.43.1", "terser": "^5.43.1",
"vite": "catalog:", "vite": "catalog:",
"@vitejs/plugin-legacy": "^6.0.0", "@vitejs/plugin-legacy": "^7.0.0",
"@vitejs/plugin-vue2": "^2.3.1", "@vitejs/plugin-vue2": "^2.3.3",
"vue-template-compiler": "^2.7.4" "vue-template-compiler": "^2.7.16"
} }
} }

View File

@ -21,7 +21,7 @@
"dependencies": { "dependencies": {
"@tmagic/core": "1.6.0-beta.0", "@tmagic/core": "1.6.0-beta.0",
"@tmagic/stage": "1.6.0-beta.0", "@tmagic/stage": "1.6.0-beta.0",
"@tmagic/vue-runtime-help": "^1.1.5", "@tmagic/vue-runtime-help": "^1.2.0",
"axios": "^1.10.0", "axios": "^1.10.0",
"vue": "catalog:" "vue": "catalog:"
}, },
@ -32,7 +32,7 @@
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.0",
"@vitejs/plugin-vue-jsx": "^5.0.1", "@vitejs/plugin-vue-jsx": "^5.0.1",
"@vue/compiler-sfc": "catalog:", "@vue/compiler-sfc": "catalog:",
"rollup": "^4.44.1", "rollup": "^4.45.0",
"rollup-plugin-external-globals": "^0.13.0", "rollup-plugin-external-globals": "^0.13.0",
"sass": "^1.89.2", "sass": "^1.89.2",
"terser": "^ 5.43.1", "terser": "^ 5.43.1",

View File

@ -16,9 +16,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { createApp, defineAsyncComponent } from 'vue'; import { createApp, defineAsyncComponent, resolveDirective, withDirectives } from 'vue';
import TMagicApp, { DataSourceManager, DeepObservedData, getUrlParam, registerDataSourceOnDemand } from '@tmagic/core'; import TMagicApp, { DataSourceManager, DeepObservedData, getUrlParam, registerDataSourceOnDemand } from '@tmagic/core';
import { UserRenderFunctionOptions } from '@tmagic/vue-runtime-help';
import components from '../.tmagic/async-comp-entry'; import components from '../.tmagic/async-comp-entry';
import asyncDataSources from '../.tmagic/async-datasource-entry'; import asyncDataSources from '../.tmagic/async-datasource-entry';
@ -56,6 +57,32 @@ Object.values(plugins).forEach((plugin: any) => {
vueApp.use(plugin, { app }); vueApp.use(plugin, { app });
}); });
vueApp.provide(
'userRender',
({ h, type, props = {}, attrs = {}, style, className, on, directives = [] }: UserRenderFunctionOptions) => {
const options: Record<string, any> = {
...props,
...attrs,
style,
class: className,
};
if (on) {
for (const [key, handler] of Object.entries(on)) {
options[`on${key[0].toLocaleUpperCase()}${key.substring(1)}`] = handler;
}
}
if (directives.length) {
return withDirectives(
h(type, options),
directives.map((directive) => [resolveDirective(directive.name), directive.value, directive.modifiers]),
);
}
return h(type, options);
},
);
registerDataSourceOnDemand(dsl, asyncDataSources).then((dataSources) => { registerDataSourceOnDemand(dsl, asyncDataSources).then((dataSources) => {
Object.entries(dataSources).forEach(([type, ds]: [string, any]) => { Object.entries(dataSources).forEach(([type, ds]: [string, any]) => {
DataSourceManager.register(type, ds); DataSourceManager.register(type, ds);

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.2", "version": "0.2.0",
"name": "@tmagic/vue-button", "name": "@tmagic/vue-button",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -29,6 +29,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),

View File

@ -1,5 +1,5 @@
{ {
"version": "1.1.0", "version": "1.2.0",
"name": "@tmagic/vue-container", "name": "@tmagic/vue-container",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -1,4 +1,4 @@
import { defineComponent, h, inject, type PropType, provide, resolveDirective, withDirectives } from 'vue-demi'; import { defineComponent, h, inject, type PropType, provide } from 'vue-demi';
import type TMagicApp from '@tmagic/core'; import type TMagicApp from '@tmagic/core';
import { Id, IS_DSL_NODE_KEY, MComponent } from '@tmagic/core'; import { Id, IS_DSL_NODE_KEY, MComponent } from '@tmagic/core';
@ -21,12 +21,16 @@ export default defineComponent({
type: Array as PropType<Id[]>, type: Array as PropType<Id[]>,
default: () => [], default: () => [],
}, },
pageFragmentContainerId: {
type: [String, Number] as PropType<Id>,
default: '',
},
}, },
setup(props) { setup(props) {
const userRender = inject<UserRenderFunction>( const userRender = inject<UserRenderFunction>(
'userRender', 'userRender',
({ h, type, props = {}, attrs = {}, style, className, on, directives = [] }) => { ({ h, type, props = {}, attrs = {}, style, className, on }) => {
const options: Record<string, any> = { const options: Record<string, any> = {
...props, ...props,
...attrs, ...attrs,
@ -38,14 +42,6 @@ export default defineComponent({
options[`on${key[0].toLocaleUpperCase()}${key.substring(1)}`] = handler; options[`on${key[0].toLocaleUpperCase()}${key.substring(1)}`] = handler;
} }
} }
if (directives.length) {
return withDirectives(
h(type, options),
directives.map((directive) => [resolveDirective(directive.name), directive.value, directive.modifiers]),
);
}
return h(type, options); return h(type, options);
}, },
); );
@ -78,12 +74,14 @@ export default defineComponent({
containerIndex: props.index, containerIndex: props.index,
iteratorIndex: props.iteratorIndex, iteratorIndex: props.iteratorIndex,
iteratorContainerId: props.iteratorContainerId, iteratorContainerId: props.iteratorContainerId,
pageFragmentContainerId: props.pageFragmentContainerId,
}, },
attrs: { attrs: {
'data-tmagic-id': props.config.id, 'data-tmagic-id': props.config.id,
'data-tmagic-iterator-index': props.iteratorIndex.join(',') || undefined, 'data-tmagic-iterator-index': props.iteratorIndex.join(',') || undefined,
'data-tmagic-iterator-container-id': props.iteratorContainerId.join(',') || undefined, 'data-tmagic-iterator-container-id': props.iteratorContainerId.join(',') || undefined,
'data-container-index': props.index, 'data-tmagic-container-index': props.index,
'data-tmagic-page-fragment-container-id': props.pageFragmentContainerId || undefined,
}, },
}); });
}; };

View File

@ -1,14 +1,15 @@
<template> <template>
<div @click="clickHandler"> <div @click="clickHandler">
<slot> <slot>
<template v-for="(item, index) in config.items" :key="item.id"> <ItemComponent
<ItemComponent v-for="(item, index) in config.items"
:config="item" :key="item.id"
:index="index" :config="item"
:iterator-index="iteratorIndex" :index="index"
:iterator-container-id="iteratorContainerId" :iterator-index="iteratorIndex"
></ItemComponent> :iterator-container-id="iteratorContainerId"
</template> :page-fragment-container-id="pageFragmentContainerId"
></ItemComponent>
</slot> </slot>
</div> </div>
</template> </template>
@ -44,6 +45,7 @@ export default defineComponent({
default: () => [], default: () => [],
}, },
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-img", "name": "@tmagic/vue-img",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -26,6 +26,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-iterator-container", "name": "@tmagic/vue-iterator-container",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -13,9 +13,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, inject, type PropType, watch } from 'vue-demi'; import { computed, defineComponent, type PropType, watch } from 'vue-demi';
import type TMagicApp from '@tmagic/core';
import { import {
COMMON_EVENT_PREFIX, COMMON_EVENT_PREFIX,
type Id, type Id,
@ -23,7 +22,7 @@ import {
type MIteratorContainer, type MIteratorContainer,
type MNode, type MNode,
} from '@tmagic/core'; } from '@tmagic/core';
import { registerNodeHooks, useNode } from '@tmagic/vue-runtime-help'; import { registerNodeHooks, useApp } from '@tmagic/vue-runtime-help';
import IteratorItem from './IteratorItem.vue'; import IteratorItem from './IteratorItem.vue';
@ -53,6 +52,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
@ -60,8 +60,7 @@ export default defineComponent({
}, },
setup(props) { setup(props) {
const app = inject<TMagicApp>('app'); const { app, node } = useApp(props);
const node = useNode(props, app);
registerNodeHooks(node); registerNodeHooks(node);
const configs = computed<IteratorItemSchema[]>(() => { const configs = computed<IteratorItemSchema[]>(() => {
@ -104,11 +103,11 @@ export default defineComponent({
return; return;
} }
const iteratorContainerNode = app?.getNode<TMagicIteratorContainer>( const iteratorContainerNode = app?.getNode<TMagicIteratorContainer>(props.config.id, {
props.config.id, iteratorContainerId: props.iteratorContainerId,
props.iteratorContainerId, iteratorIndex: props.iteratorIndex,
props.iteratorIndex, pageFragmentContainerId: props.pageFragmentContainerId,
); });
if (!iteratorContainerNode) { if (!iteratorContainerNode) {
return; return;

View File

@ -13,7 +13,7 @@
import { defineComponent, inject, type PropType } from 'vue-demi'; import { defineComponent, inject, type PropType } from 'vue-demi';
import type TMagicApp from '@tmagic/core'; import type TMagicApp from '@tmagic/core';
import type { Id } from '@tmagic/core'; import { type Id } from '@tmagic/core';
import { useComponent, useComponentStatus } from '@tmagic/vue-runtime-help'; import { useComponent, useComponentStatus } from '@tmagic/vue-runtime-help';
import { IteratorItemSchema } from './type'; import { IteratorItemSchema } from './type';

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-overlay", "name": "@tmagic/vue-overlay",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -27,6 +27,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-page-fragment-container", "name": "@tmagic/vue-page-fragment-container",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -4,6 +4,7 @@
:is="containerComponent" :is="containerComponent"
:iterator-index="iteratorIndex" :iterator-index="iteratorIndex"
:iterator-container-id="iteratorContainerId" :iterator-container-id="iteratorContainerId"
:page-fragment-container-id="config.id"
:config="containerConfig" :config="containerConfig"
:model="model" :model="model"
></component> ></component>
@ -11,11 +12,18 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, inject, type PropType } from 'vue-demi'; import { computed, defineComponent, type PropType, provide } from 'vue-demi';
import type TMagicApp from '@tmagic/core'; import {
import { cloneDeep, type Id, IS_DSL_NODE_KEY, type MComponent, NodeType, traverseNode } from '@tmagic/core'; cloneDeep,
import { registerNodeHooks, useComponent, useNode } from '@tmagic/vue-runtime-help'; type Id,
IS_DSL_NODE_KEY,
type MComponent,
NodeType,
PAGE_FRAGMENT_CONTAINER_ID_KEY,
traverseNode,
} from '@tmagic/core';
import { registerNodeHooks, useApp, useComponent, useDsl } from '@tmagic/vue-runtime-help';
export default defineComponent({ export default defineComponent({
name: 'tmagic-page-fragment-container', name: 'tmagic-page-fragment-container',
@ -28,6 +36,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
@ -35,13 +44,14 @@ export default defineComponent({
}, },
setup(props) { setup(props) {
const app = inject<TMagicApp>('app'); provide(PAGE_FRAGMENT_CONTAINER_ID_KEY, props.config.id);
const node = useNode(props, app);
const { app, node } = useApp(props);
registerNodeHooks(node); registerNodeHooks(node);
const containerComponent = useComponent({ componentType: 'container', app }); const containerComponent = useComponent({ componentType: 'container', app });
const fragment = computed(() => app?.dsl?.items?.find((page) => page.id === props.config.pageFragmentId)); const { pageConfig: fragment } = useDsl(app, props.config.id);
const containerConfig = computed(() => { const containerConfig = computed(() => {
if (!fragment.value) return { items: [], id: '', type: NodeType.CONTAINER }; if (!fragment.value) return { items: [], id: '', type: NodeType.CONTAINER };

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-page-fragment", "name": "@tmagic/vue-page-fragment",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.1", "version": "0.2.1",
"name": "@tmagic/vue-page", "name": "@tmagic/vue-page",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.2.0",
"name": "@tmagic/vue-qrcode", "name": "@tmagic/vue-qrcode",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -27,6 +27,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.1", "version": "0.2.1",
"name": "@tmagic/vue-text", "name": "@tmagic/vue-text",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -26,6 +26,7 @@ export default defineComponent({
iteratorIndex: Array as PropType<number[]>, iteratorIndex: Array as PropType<number[]>,
iteratorContainerId: Array as PropType<Id[]>, iteratorContainerId: Array as PropType<Id[]>,
containerIndex: Number, containerIndex: Number,
pageFragmentContainerId: [String, Number] as PropType<Id>,
model: { model: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),