概览
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}><inputvalue={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 (<divcss={{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><LayoutslotTop={<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>);}
