UNPKG

zent

Version:

一套前端设计语言和基于React的实现

215 lines (159 loc) 7.11 kB
--- title: Design path: component/design group: Data Entry --- ## Design H5 page editor, build your H5 pages in a WYSIWYG way. ⚠️ Warning:The `Design` component exported by Zent uses `react-dnd-html5-backend`'s `HTML5Backend`. Each React component tree can have only one instance of `HTML5Backend`. Please use `zent/lib/design/Design` to replace the default export from Zent if you are using `HTML5Backend` somewhere else. There two components are almost the same, except the one in `zent/lib/design/Design` does not depend on `HTML5Backend`. ### API | Property | Description | Type | Default | Required | |------|------|------|--------|--------| | components | All available components in Design | array | [] | Yes | | value | Current value | array | [] | Yes | | onChange | Callback when value changes | func(value: array): void | Yes | | defaultSelectedIndex| Default selected index in value array | number | -1 | No | | preview | Custom Preview component | Component | DesingPreview | No | | confirmUnsavedLeave| Show a confirm dialog if there're unsaved changes | boolean | true | No | | cache | Cache unsaved changes to `localStorage` | boolean | false | No | | cacheId | Cache id, must be used with `cache` | string | | Yes if `cache` is `true`, No otherwise | | cacheRestoreMessage | Message to restore cache from `localStorage` | node | 提示:在浏览器中发现未提交的内容,是否使用该内容替换当前内容? | No | | disabled | Is Design disabled | boolean | false | No | | globalConfig | Global config across Design | object | | No | | children | Additional children inside Design | node | | No | | scrollTopOffset | Top scroll offset | number \| func | | No | | scrollLeftOffset | Left scroll offset | number \| func | | No | | className | Custom class name | string | | No | | prefix | Custom prefix | string | | No | `components` is an array, all available componets should be included in this array. Each item in this array is a component description, here are the possible options. ```js type Component = { // Component type, must be unique type: string | string[], // Default component type // If `type` is an array, `defaultType` can be a number // If `defaultType` is a function, it will be called with `type` as the sole argument defaultType?: number | (string[] | string) => string // Component to render preview preview: ReactComponent, // Component responsible for editing editor: ReactComponent, // Preview component container previewItem?: ReactComponent, // Preview controller, responsible for dnd, select and so on previewController?: ReactComponent, // Editor component container editorItem?: ReactComponent, // Is this component dragable? dragable?: boolean, // Should this component appear in the component list? appendable?: boolean, // Is this component configurable(edit/add/delete on the bottom right corner)? configurable?: boolean, // Is this component editable? Only editable components are selectable editable?: boolean, // Highlight preview when selected highlightWhenSelect?: boolean, // Maximum number of instances this component can have // Zero is no limit // If passing a function, return false to stop adding more limit?: number | (count: number) => boolean, // Callback when adding a new instance for component // Add only if Promise resolves. shouldCreate?: (comp: Component) => Promise, // Additional props passed to editor editorProps: (value: object) => object | object, // Addtional props passed to preview previewProps: (value: object) => object | object } ``` Each item in `value` array must have a `type` property, `Design` uses this property to determine why component in `component` array should be used to render this value. ### Design.group Declaration:`group(name: string): object` `Design` supports component grouping in add component area, all you have to do is insert `Desgin.group(groupName)` to the right place in your `components` array. ```js [ config, Design.group('分组1'), componentA, componentB, Design.group('分组2'), componentC, componentD ] ``` ### Design Instance Methods * `design.validate(): Promise`, trigger a validation, resolves only if there's no erro. * `design.markAsSaved()`, tell `Desgin` data has been saved. ### stripUUID There's a `stripUUID` method on `Design` instance, you can use this method to strip all internal ids used by `Design` before sending data to server. This may help reduce data size. Note: calling `stripUUID` before sending data to server is optional. ### How to Implement new Design Component? Each Desgin component are divided in two parts: Preview and Editor. Preview is just a component which accepts `{ value: any, globalConfig: any, design: object }` as props and renders a UI with these props. It is a little bit complex about Editor component. You are recommended to extend the `@youzan/design/lib/base/editor/DesignEditor` base class, this class has some useful methods you can use(e.g. `onChange` event handlers). Editor has these props: `{ value: any, onChange: func, showError: boolean, validation: object, design object }` - `validate(value): Promise` You should resolve an error object if there're errors - `props.design` There're some useful methods on this prop A editor component must have these static properties: `designType, designDescription, getInitialValue, validate` #### Example ```jsx // Preview import React, { PureComponent, Component } from 'react'; export default class NoticePreview extends (PureComponent || Component) { render() { const { value } = this.props; return ( <div className="rc-design-component-notice-preview">{value}</div> ); } } // Editor import React from 'react'; import { Input } from 'zent'; import { DesignEditor, ControlGroup } from '@youzan/design/base/editor/DesignEditor'; export const PLACEHOLDER = '请填写内容,如果过长,将会在手机上滚动显示'; export default class NoticeEditor extends DesignEditor { render() { const { value, showError, validation } = this.props; return ( <div className="rc-design-component-notice-editor"> <ControlGroup label="公告:" required showError={showError || this.getMetaProperty('content', 'touched')} error={validation.content} > <Input name="content" placeholder={PLACEHOLDER} value={value.content} onChange={this.onInputChange} onBlur={this.onInputBlur} /> </ControlGroup> </div> ); } static designType = 'notice'; static designDescription = '公告'; static getInitialValue() { return { content: '', scrollable: false }; } static validate(value) { return new Promise(resolve => { const errors = {}; const { content } = value; if (!content || !content.trim()) { errors.content = '请填写公告内容'; } resolve(errors); }); } } ```