feat(ui): 修改useApp实现,与ui-react中保持一致

This commit is contained in:
roymondchen 2023-04-10 19:59:53 +08:00
parent abcac71826
commit befaf67ba7
11 changed files with 213 additions and 492 deletions

View File

@ -35,18 +35,18 @@ export default ({ config, methods }: UseAppOptions) => {
const node = app?.page?.getNode(config.id);
const [created, setCreated] = useState(false);
const emitData = {
config,
...methods,
};
if (!created) {
// 只需要触发一次 created
setCreated(true);
node?.emit('created', { methods });
node?.emit('created', emitData);
}
useEffect(() => {
const emitData = {
config,
...methods,
};
node?.emit('mounted', emitData);
return () => {

View File

@ -1,6 +1,7 @@
<template>
<component
v-if="display()"
ref="component"
:is="tagName"
:id="config.id"
:class="`magic-ui-component${config.className ? ` ${config.className}` : ''}`"
@ -9,39 +10,34 @@
></component>
</template>
<script lang="ts">
import { computed, defineComponent, getCurrentInstance, inject, provide } from 'vue';
<script lang="ts" setup>
import { computed, inject } from 'vue';
import Core from '@tmagic/core';
import { toLine } from '@tmagic/utils';
export default defineComponent({
props: {
config: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: Record<string, any>;
model: any;
}>(),
{
config: () => ({}),
model: () => ({}),
},
);
setup(props) {
const vm = getCurrentInstance()?.proxy;
const app: Core | undefined = inject('app');
const app: Core | undefined = inject('app');
provide('hoc', vm);
const tagName = computed(() => `magic-ui-${toLine(props.config.type)}`);
const style = computed(() => app?.transformStyle(props.config.style));
return {
tagName: computed(() => `magic-ui-${toLine(props.config.type)}`),
style: computed(() => app?.transformStyle(props.config.style)),
const display = () => {
const displayCfg = props.config?.display;
display: () => {
const displayCfg = props.config?.display;
if (typeof displayCfg === 'function') {
return displayCfg(app);
}
return displayCfg !== false;
},
};
},
});
if (typeof displayCfg === 'function') {
return displayCfg(app);
}
return displayCfg !== false;
};
</script>

View File

@ -1,63 +1,34 @@
<template>
<button class="magic-ui-button" @click="clickHandler">
<button class="magic-ui-button">
<slot>
<magic-ui-text :config="textConfig"></magic-ui-text>
</slot>
</button>
</template>
<script lang="ts">
import { computed, defineComponent, getCurrentInstance, PropType, reactive } from 'vue';
<script lang="ts" setup>
import { computed } from 'vue';
import { MComponent } from '@tmagic/schema';
import { MButton, MButtonInstance, MText } from '../../../src/types';
import useApp from '../../useApp';
export default defineComponent({
props: {
config: {
type: Object as PropType<MButton>,
default: () => ({}),
},
model: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: MComponent;
model: any;
}>(),
{
model: () => ({}),
},
setup(props) {
useApp(props);
const vm: MButtonInstance = getCurrentInstance()?.proxy as MButtonInstance;
const actions = reactive<Function[]>([]);
const actualActions = computed(() => [
typeof props.config.preAction === 'function' ? props.config.preAction : () => true,
...actions,
typeof props.config.postAction === 'function' ? props.config.postAction : () => true,
]);
function pushAction(action: Function): void {
actions.push(action);
}
async function clickHandler(): Promise<void> {
for (const fn of actualActions.value) {
if (typeof fn === 'function') {
const ret = await fn(vm, { model: props.model });
if (ret === false) {
break;
}
}
}
}
);
const textConfig = computed<MText>(() => ({
type: 'text',
text: props.config?.text || '',
disabledText: props.config?.disabledText || '',
html: props.config?.html || '',
}));
const textConfig = computed(() => ({
type: 'text',
text: props.config?.text || '',
}));
return {
pushAction,
clickHandler,
textConfig,
};
},
useApp({
config: props.config,
methods: {},
});
</script>

View File

@ -6,47 +6,47 @@
:style="style"
>
<slot></slot>
<magic-ui-component v-for="item in config.items" :key="item.id" :config="item"></magic-ui-component>
<MComponent v-for="item in config.items" :key="item.id" :config="item"></MComponent>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue';
<script lang="ts" setup>
import { computed, inject } from 'vue';
import Core from '@tmagic/core';
import type { MContainer } from '@tmagic/schema';
import Component from '../../Component.vue';
import MComponent from '../../Component.vue';
import useApp from '../../useApp';
import useCommonMethod from '../../useCommonMethod';
export default defineComponent({
components: {
'magic-ui-component': Component,
const props = withDefaults(
defineProps<{
config: MContainer;
model: any;
}>(),
{
model: () => ({}),
},
);
props: {
config: {
type: Object as PropType<MContainer>,
default: () => ({}),
},
},
const app: Core | undefined = inject('app');
setup(props) {
const app = useApp(props);
const style = computed(() => app?.transformStyle(props.config.style || {}));
return {
style: computed(() => app?.transformStyle(props.config.style || {})),
const display = () => {
const displayCfg = props.config?.display;
display: () => {
const displayCfg = props.config?.display;
if (typeof displayCfg === 'function') {
return displayCfg(app);
}
return displayCfg !== false;
};
if (typeof displayCfg === 'function') {
return displayCfg(app);
}
return displayCfg !== false;
},
...useCommonMethod(props),
};
useApp({
config: props.config,
methods: {
...useCommonMethod(props),
},
});
</script>

View File

@ -1,32 +1,27 @@
<template>
<img class="magic-ui-img" :src="config.src" @click="clickHandler" />
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
<script lang="ts" setup>
import { MComponent } from '@tmagic/schema';
import { MImg } from '../../types';
import useApp from '../../useApp';
export default defineComponent({
props: {
config: {
type: Object as PropType<MImg>,
default: () => ({}),
},
model: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: MComponent;
model: any;
}>(),
{
model: () => ({}),
},
setup(props) {
useApp(props);
);
return {
clickHandler() {
if (props.config.url) window.location.href = props.config.url;
},
};
},
const clickHandler = () => {
if (props.config.url) window.location.href = props.config.url;
};
useApp({
config: props.config,
methods: {},
});
</script>

View File

@ -3,60 +3,55 @@
<slot></slot>
</magic-ui-container>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
<script lang="ts" setup>
import { inject, ref } from 'vue';
import Core from '@tmagic/core';
import type { MNode } from '@tmagic/schema';
import type { MComponent, MNode } from '@tmagic/schema';
import useApp from '../../useApp';
export default defineComponent({
props: {
config: {
type: Object,
default: () => ({}),
},
model: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: MComponent;
model: any;
}>(),
{
model: () => ({}),
},
);
setup(props) {
const visible = ref(false);
const app: Core | undefined = useApp(props);
const node = app?.page?.getNode(props.config.id);
const visible = ref(false);
const app: Core | undefined = inject('app');
const node = app?.page?.getNode(props.config.id);
const openOverlay = () => {
visible.value = true;
if (app) {
app.emit('overlay:open', node);
}
};
const openOverlay = () => {
visible.value = true;
if (app) {
app.emit('overlay:open', node);
}
};
const closeOverlay = () => {
visible.value = false;
if (app) {
app.emit('overlay:close', node);
}
};
const closeOverlay = () => {
visible.value = false;
if (app) {
app.emit('overlay:close', node);
}
};
app?.page?.on('editor:select', (info, path) => {
if (path.find((node: MNode) => node.id === props.config.id)) {
openOverlay();
} else {
closeOverlay();
}
});
app?.page?.on('editor:select', (info, path) => {
if (path.find((node: MNode) => node.id === props.config.id)) {
openOverlay();
} else {
closeOverlay();
}
});
return {
visible,
openOverlay,
closeOverlay,
};
useApp({
config: props.config,
methods: {
openOverlay,
closeOverlay,
},
});
</script>

View File

@ -7,40 +7,39 @@
:style="style"
>
<slot></slot>
<magic-ui-component v-for="item in config.items" :key="item.id" :config="item"></magic-ui-component>
<MComponent v-for="item in config.items" :key="item.id" :config="item"></MComponent>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue';
<script lang="ts" setup>
import { computed, inject } from 'vue';
import Core from '@tmagic/core';
import type { MPage } from '@tmagic/schema';
import Component from '../../Component.vue';
import MComponent from '../../Component.vue';
import useApp from '../../useApp';
export default defineComponent({
components: {
'magic-ui-component': Component,
const props = withDefaults(
defineProps<{
config: MPage;
model: any;
}>(),
{
model: () => ({}),
},
);
props: {
config: {
type: Object as PropType<MPage>,
default: () => ({}),
},
},
const app: Core | undefined = inject('app');
setup(props) {
const app = useApp(props);
const style = computed(() => app?.transformStyle(props.config.style || {}));
return {
style: computed(() => app?.transformStyle(props.config.style || {})),
const refresh = () => {
window.location.reload();
};
refresh() {
window.location.reload();
},
};
},
useApp({
config: props.config,
methods: { refresh },
});
</script>

View File

@ -2,46 +2,41 @@
<img class="magic-ui-qrcode" :src="imgUrl" />
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watch } from 'vue';
<script lang="ts" setup>
import { ref, watch } from 'vue';
import QRCode from 'qrcode';
import { MQrcode } from '../../types';
import type { MComponent } from '@tmagic/schema';
import useApp from '../../useApp';
export default defineComponent({
props: {
config: {
type: Object as PropType<MQrcode>,
default: () => ({}),
},
model: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: MComponent;
model: any;
}>(),
{
model: () => ({}),
},
);
setup(props) {
useApp(props);
const imgUrl = ref();
const imgUrl = ref();
watch(
() => props.config.url,
(url = '') => {
QRCode.toDataURL(url, (e: any, url: string) => {
if (e) console.error(e);
imgUrl.value = url;
});
},
{
immediate: true,
},
);
return {
imgUrl,
};
watch(
() => props.config.url,
(url = '') => {
QRCode.toDataURL(url, (e: any, url: string) => {
if (e) console.error(e);
imgUrl.value = url;
});
},
{
immediate: true,
},
);
useApp({
config: props.config,
methods: {},
});
</script>

View File

@ -1,63 +1,24 @@
<script lang="ts">
import { computed, defineComponent, getCurrentInstance, h, inject, PropType } from 'vue';
<template>
<span>{{ config.text }}</span>
</template>
<script lang="ts" setup>
import { MComponent } from '@tmagic/schema';
import { MComponentInstance, MText, MTextInstance } from '../../../src/types';
import useApp from '../../useApp';
export default defineComponent({
props: {
config: {
type: Object as PropType<MText>,
default: () => ({}),
},
model: {
type: Object,
default: () => ({}),
},
vars: {
type: Object,
default: () => ({}),
},
const props = withDefaults(
defineProps<{
config: MComponent;
model: any;
}>(),
{
model: () => ({}),
},
setup(props) {
useApp(props);
const vm: MTextInstance = getCurrentInstance()?.proxy as MTextInstance;
const hoc: MComponentInstance = inject('hoc');
const displayText = computed(() => {
let text = props.config?.text || '';
const { vars } = props;
if (hoc?.disabled && props.config?.disabledText) {
text = props.config.disabledText;
}
if (typeof text === 'function') {
return text.bind(vm)(vm, { model: props.model });
}
if (Object.prototype.toString.call(vars) === '[object Object]') {
let tmp: string = text;
Object.entries(vars).forEach(([key, value]) => {
tmp = tmp.replace(new RegExp(`{{${key}}}`, 'g'), value);
});
return tmp;
}
return text || '';
});
);
return {
displayText,
};
},
render() {
const className = this.config?.multiple ? 'magic-ui-text' : 'magic-ui-text magic-ui-text--single-line';
if (typeof this.$slots?.default === 'function') {
return h('div', { class: className }, [this.$slots?.default?.() || '']);
}
return h('div', {
class: className,
...(this.displayText ? { innerHTML: this.displayText } : {}),
});
},
useApp({
config: props.config,
methods: {},
});
</script>

View File

@ -16,8 +16,6 @@
* limitations under the License.
*/
import { ComponentPublicInstance } from 'vue';
/* style */
export type PartCSSStyle = {
[key in keyof CSSStyleDeclaration]?: string | number;
@ -45,203 +43,3 @@ export interface MEventBus {
$once: (...args: any) => void;
$emit: (...args: any) => void;
}
/* component */
export interface MComponent {
type: string;
id?: number | string;
name?: string;
style?: StyleCfg;
disabledStyle?: StyleCfg;
className?: string | ((p1: any, p2: any) => string);
display?: boolean | ((p1: any, p2: any) => boolean);
html?: string;
created?: (p1: any, p2: any) => Promise<any>;
mounted?: (p1: any, p2: any) => Promise<any>;
renderType?: number;
events?: MEvent[];
}
export interface MComponentProps {
config: MComponent;
model: Object;
}
export type MComponentInstance =
| ComponentPublicInstance<
MComponentProps,
{},
{
[propName: string]: any;
disabled: boolean;
}
>
| null
| undefined;
/* container */
export interface MContainer extends MComponent {
items?: MComponent[] | MContainer[];
}
export interface MContainerProps {
config: MContainer;
model: Object;
}
export type MContainerInstance =
| ComponentPublicInstance<
MContainerProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
/* page */
export interface MPage extends MContainer {
title?: string;
cssFile?: string;
}
export interface MPageProps {
config: MPage;
}
export type MPageInstance =
| ComponentPublicInstance<
MPageProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
/* pop */
export interface MPop extends MContainer {
activate: () => void;
maskClose: boolean;
}
export interface MPopProps {
config: MPop;
model: Object;
fillWithSlot: boolean;
beforeOpen: (p1: MPopInstance, p2: any) => boolean;
beforeClose: (p1: MPopInstance) => boolean;
}
export interface MPopObj {
name: string;
options: object;
}
export type MPopInstance =
| ComponentPublicInstance<
MPopProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
/* app */
export interface MApp extends MComponent {
items: MPage[];
}
export interface MAppProps {
config: [MApp];
pageConfig: MPage;
}
export enum MAppElementType {
pages = 'pages',
containers = 'containers',
components = 'components',
pops = 'pops',
}
export type MAppInstance =
| ComponentPublicInstance<
MAppProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
export type MCommonInstance = MContainerInstance | MPageInstance | MComponentInstance | MPopInstance;
/* tabs */
export type MTabs = MContainer;
export interface MTabsProps {
config: MTabs;
model: Object;
}
export type MTabsInstance =
| ComponentPublicInstance<
MTabsProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
/* text */
export interface MText extends MComponent {
text?: string | ((p1: any, p2: any) => string);
disabledText?: string | ((p1: any, p2: any) => string);
multiple?: boolean;
}
export interface MTextProps {
config: MText;
model: Object;
vars: Object;
}
export type MTextInstance =
| ComponentPublicInstance<
MTextProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
/* button */
export interface MButton extends MComponent {
preAction?: (p1: any, p2: any) => string;
postAction?: (p1: any, p2: any) => string;
text?: string | ((p1: any, p2: any) => string);
disabledText?: string | ((p1: any, p2: any) => string);
}
export interface MButtonProps {
config: MButton;
model: Object;
}
export type MButtonInstance =
| ComponentPublicInstance<
MButtonProps,
{},
{
[propName: string]: any;
}
>
| null
| undefined;
export type ArrayOneOrMore = { 0: string } & string[];
export interface MImg {
src: string;
url: string;
}
export interface MQrcode {
url: string;
}
export interface MPop extends MComponent {
items?: MComponent[] | MContainer[];
closeButtonStyle?: any;
closeButton?: boolean;
}

View File

@ -16,24 +16,35 @@
* limitations under the License.
*/
import { getCurrentInstance, inject, onMounted, onUnmounted } from 'vue';
import { inject, onMounted, onUnmounted } from 'vue';
import Core from '@tmagic/core';
import type { MComponent } from '@tmagic/schema';
export default (props: any) => {
interface UseAppOptions {
config: MComponent;
methods?: {
[key: string]: Function;
};
}
export default ({ config, methods }: UseAppOptions) => {
const app: Core | undefined = inject('app');
const node = app?.page?.getNode(props.config.id);
const node = app?.page?.getNode(config.id);
const vm = getCurrentInstance()?.proxy;
const emitData = {
config,
...methods,
};
node?.emit('created', vm);
node?.emit('created', emitData);
onMounted(() => {
node?.emit('mounted', vm);
node?.emit('mounted', emitData);
});
onUnmounted(() => {
node?.emit('destroy', vm);
node?.emit('destroy', emitData);
});
return app;