概览
Mitosis 受到许多现代框架的启发。您会看到组件看起来像 React 组件,并使用类似 React 的 hooks,但具有类似 Vue 的简单可变状态,使用类似 Solid 的静态形式的 JSX,像 Svelte 一样编译,并且使用类似 Angular 的简单、规范的结构。
示例 Mitosis 组件:
import { For, Show, useStore } from '@builder.io/mitosis';
export default function MyComponent(props) {
const state = useStore({
newItemName: 'New item',
list: ['hello', 'world'],
addItem() {
state.list = [...state.list, state.newItemName];
},
});
return (
<div>
<Show when={props.showInput}>
<input
value={state.newItemName}
onChange={(event) => (state.newItemName = event.target.value)}
/>
</Show>
<div css={{ padding: '10px' }}>
<button onClick={() => state.addItem()}>Add list item</button>
<div>
<For each={state.list}>{(item) => <div>{item}</div>}</For>
</div>
</div>
</div>
);
}
组件
Mitosis 类似于大多数现代前端框架,以组件为驱动。每个 Mitosis 组件应位于自己的文件中,并且是单一的默认导出。它们是简单的函数,返回 JSX 元素。
export default function MyComponent() {
return <div>Hello world!</div>;
}
样式
css
通过 dom 元素和组件上的 css 属性进行样式设置。它接受驼峰式的 CSS 属性(类似于 DOM 元素上的 style 对象)和作为有效 CSS 字符串的属性。
export default function CSSExample() {
return <div css={{ marginTop: '10px', color: 'red' }} />;
}
还可以将媒体查询作为键,值为样式对象包含在内。
export default function ResponsiveExample() {
return (
<div
css={{
marginTop: '10px',
'@media (max-width: 500px)': {
marginTop: '0px',
},
}}
/>
);
}
class vs className
Mitosis 更喜欢您使用 class 提供类名字符串,但也允许您提供 className。如果在同一个组件中同时使用两者,它将尝试合并两者。我们建议只使用一个(最好是 class,因为 Mitosis 内部首选它)。
状态
状态由 useStore
hook 提供。当前此值的名称必须为 state,如下所示:
export default function MyComponent() {
const state = useStore({
name: 'Steve',
});
return (
<div>
<h2>Hello, {state.name}</h2>
<input onInput={(event) => (state.name = event.target.value)} value={state.name} />
</div>
);
}
如果初始状态值是计算值(基于 props 或某个函数的输出),则不能将其内联。而是使用 getter 方法:
import { kebabCase } from 'lodash';
export default function MyComponent(props) {
const state = useStore({
name: 'Steve',
get transformedName() {
return kebabCase('Steve');
},
get transformedName() {
return props.name;
},
});
return (
<div>
<h2>Hello, {state.name}</h2>
<input onInput={(event) => (state.name = event.target.value)} value={state.name} />
</div>
);
}
组件在状态值更改时会自动更新。
方法
state 对象还可以包含方法。
export default function MyComponent() {
const state = useStore({
name: 'Steve',
updateName(newName) {
state.name = newName;
},
});
return (
<div>
<h2>Hello, {state.name}</h2>
<input onInput={(event) => state.updateName(event.target.value)} value={state.name} />
</div>
);
}
控制流
Builder 中的控制流是静态的,类似于 Solid。与 React 中的自由形式 JavaScript 不同,您必须使用诸如 <Show>
和 <For>
这样的控制流组件。
Show
export declare function Show<T>(props: {
when: T | undefined | null | false;
else?: JSX.Element;
children?: JSX.Element | null;
}): any;
用于条件逻辑的 <Show>
。它接受一个 when 属性,表示匹配的条件。当条件为真时,子项将呈现,否则它们将不呈现。
export default function MyComponent(props) {
return (
<>
<Show when={props.showContents} else={<span {...props.attributes}>{props.text}</span>}>
Hello, I may or may not show!
</Show>
;
</>
);
}
For
用于重复项的 <For>
,例如遍历数组。它接受一个 each 属性,表示要迭代的数组。此组件将一个函数作为子项,该函数将相关项目和索引传递给该函数,如下所示:
export default function MyComponent(props) {
const state = useStore({
myArray: [1, 2, 3],
});
return <For each={state.myArray}>{(theArrayItem, index) => <div>{theArrayItem}</div>}</For>;
}
Children
我们使用标准方法通过 props.children 传递子项。
export default function MyComponent(props) {
return <div>{props.children}</div>;
}
对于 Web 组件,您需要使用 ShadowDom 元数据
Slot
当要注册命名插槽时,使用 slot 属性进行注册。
<div>
<Layout
slotTop={<NavBar/>}
slotLeft={<Sidebar/>}
slotCenter={<Content/>}
/>
anything else
</Layout>
</div>
在此示例中,我们为 Layout 组件注册了 top、left 和 center。
如果 Layout 组件也是 Mitosis 组件,
那么我们只需在 props 中使用引用。
export default function Layout(props) {
return (
<div className="layout">
<div className="top">{props.slotTop}</div>
<div className="left">{props.slotLeft}</div>
<div className="center">{props.slotCenter}</div>
{props.children}
</div>
);
}
或者使用由组件提供的 Slot 组件
import { Slot } from '@builder.io/mitosis';
export default function Layout(props) {
return (
<div className="layout">
<div className="top">
<Slot name="top" />
</div>
<div className="left">
<Slot name="left" />
</div>
<div className="center">
<Slot name="center" />
</div>
<Slot />
</div>
);
}
对于 vue 组件,slot 属性将被编译为命名插槽
<div class="layout">
<div class="top"><slot name="top" /></div>
<div class="left"><slot name="left" /></div>
<div class="center"><slot name="center" /></div>
<slot />
</div>
Mitosis 一次只编译一个组件,只关注为每个框架输出正确的方法。对于上面的两个示例,以下是 Angular 和 HTML 的输出。
<div>
<layout>
<sidebar left></sidebar>
<nav-bar top></nav-bar>
<content center></content>
anything else
</layout>
<div></div>
</div>
@Component({
selector: 'layout',
template: `
<div class="layout">
<div class="top">
<ng-content select="[top]"></ng-content>
</div>
<div class="left">
<ng-content select="[left]"></ng-content>
</div>
<div class="center">
<ng-content select="[center]"></ng-content>
</div>
<ng-content></ng-content>
</div>
`,
})
class LayoutComponent {}
对于 Web 组件,您需要使用 ShadowDom 元数据来命名插槽
对于 Web 组件,您需要使用 ShadowDom 元数据的命名插槽
默认 Slot 内容
import { Slot } from '@builder.io/mitosis';
export default function Layout(props) {
return (
<div className="layout">
<div className="top">
<Slot name="top">Top default</Slot>
</div>
<div className="left">
<Slot name="left" />
</div>
<div className="center">
<Slot name="center" />
</div>
<Slot>Default child</Slot>
</div>
);
}