【电子病历】1-自定义 Slate-plugins 分割线插件

在这里插入图片描述

背景

项目电子病历技术选型采用 slate, 使用 slate-plugins 加快开发效率。本文主要叙述如何采用 slate-plugins 的形式开发自定义插件。以分割线组件举例。

组件开发

目录结构如下

├── plugins
│   ├── line   逻辑组件
│   │   ├── createLinePlugin.ts
│   │   ├── defaults.ts
│   │   ├── index.ts
│   │   └── withLine.ts
│   └── line-ui 样式组件
│       ├── LineElement
│       ├── ToolBarLine
│       └── index.ts

插件采用逻辑和样式分离的开发方式。

逻辑组件 line

line/ 文件夹下存放组件逻辑行为的代码。 核心是返回一个 SlatePlugin 函数。

export interface SlatePlugin<T extends SPEditor = SPEditor> extends Partial<DOMHandlers<T>> {
    /**
     * @see {@link Decorate}
     */
    decorate?: Decorate<T>;
    /**
     * @see {@link DeserializeHtml}
     */
    deserialize?: Deserialize<T>;
    /**
     * Inline element types.
     */
    inlineTypes?: (editor: T) => string[];
    /**
     * @see {@link OnChange}
     */
    onChange?: OnChange<T>;
    /**
     * Plugin keys to support configuration.
     */
    pluginKeys?: string | string[];
    /**
     * @see {@link RenderElement}
     */
    renderElement?: RenderElement<T>;
    /**
     * @see {@link RenderLeaf}
     */
    renderLeaf?: RenderLeaf<T>;
    /**
     * @see {@link SerializeHtml}
     */
    serialize?: Serialize;
    /**
     * Void element types.
     */
    voidTypes?: (editor: T) => string[];
    /**
     * Editor method overriders.
     */
    withOverrides?: WithOverride | WithOverride[];
}

组件的所有行为逻辑都可以使用单个文件的形式开发,最后由 createLinePlugin.ts 方法导出。

// createLinePlugin.ts

import {
  getRenderElement,
  // eslint-disable-next-line no-unused-vars
  getSlatePluginTypes,
  SlatePlugin
} from '@udecode/slate-plugins-core'
import { ELEMENT_LINE } from './defaults'
import { withLine } from './withLine'

export const createLinePlugin = (): SlatePlugin => ({
  pluginKeys: ELEMENT_LINE,
  renderElement: getRenderElement(ELEMENT_LINE),
  voidTypes: getSlatePluginTypes(ELEMENT_LINE),
  withOverrides: withLine()
})

方法指定了组件的 type、渲染函数、对 editor 的方法重写、serializedeserialize 等等。

其中 index.ts 文件为 barrelsby 自动生成, 可以方便的导出所有方法和变量,易于引用。

barrelsby -d "you dirPath" -n -q -S

/**
 * @file Automatically generated by barrelsby.
 */

export * from './createLinePlugin'
export * from './defaults'
export * from './withLine'

样式组件 line-ui

样式组件主要分为两块

组件渲染函数

即为 render 函数,渲染出想要的组件即可,样式内容在 LineElement.styles.ts 中定义。使用的样式框架为 Component-Styling

// LineElement.tsx

import * as React from 'react'
import {
  ClassName,
  getRootClassNames,
  RootStyleSet,
  StyledElementProps
} from '@udecode/slate-plugins-ui-fluent'
import { styled } from '@uifabric/utilities'
import { getLineElementStyles } from './LineElement.styles'

const getClassNames = getRootClassNames()

export const LineElementBase = ({
  attributes,
  children,
  className,
  styles
}: StyledElementProps) => {
  const classNames = getClassNames(styles, {
    className
    // Other style props
  })

  return (
    <div {...attributes} className={classNames.root}>
      {children}
    </div>
  )
}

/**
 * BlockElement
 */
export const LineElement = styled<
  StyledElementProps,
  ClassName,
  RootStyleSet
>(LineElementBase, getLineElementStyles, undefined, {
  scope: 'BlockElement'
})

toolbar渲染函数

核心代码为 ToolbarLink.tsx 文件,导出一个放在 Toolbar 上的组件,此处可以定义工具条的交互,比如点击插入、高亮状态等等。

// ToolbarLink.tsx

import * as React from 'react'
import {
  insertNodes
} from '@udecode/slate-plugins-common'
import {
  getSlatePluginType,
  useEventEditorId,
  TElement,
  useStoreEditorState
} from '@udecode/slate-plugins-core'
import {
  ToolbarButton,
  ToolbarButtonProps
} from '@udecode/slate-plugins-toolbar'
import { Editor, Transforms } from 'slate'
import { ELEMENT_LINE } from '../../line'
export interface ToolbarLineProps extends ToolbarButtonProps {}

export const ToolbarLine = ({ getLinkUrl, ...props }: ToolbarLineProps) => {
  const editor = useStoreEditorState(useEventEditorId('focus'))

  return (
    <ToolbarButton
      onMouseDown={async (event) => {
        if (!editor) return
        // 跳到前一个元素
        const afterPath = Editor.after(editor, editor.selection, { unit: 'block' })
        event.preventDefault()
        // 插入一个line 元素   光标移动到下一行
        insertNodes<TElement>(editor, {
          type: ELEMENT_LINE,
          children: [{ text: '' }],
          at: afterPath
        })
        const pPath = Editor.after(editor, editor.selection)
        insertNodes<TElement>(editor, {
          type: 'p',
          children: [{ text: '' }],
          at: pPath
        })
        Transforms.select(editor, pPath)
        Transforms.collapse(editor, {
          edge: 'start'
        })
      }}
      {...props}
    />
  )
}

引入组件

逻辑组件引入

完成逻辑组件和样式组件的开发,一个组件就算开发完成,应该如何引入改组件呢。 方法和引入 slate-plugins 自身组件一样。

在初始化 SlatePlugins 的时候,在 plugins 中调用导出函数即可。

...

const pluginsMemo = useMemo(() => {
    const plugins = [
      ...
      createLinePlugin()
      ...
    ]
    return plugins
  }, [])
    
...
<SlatePlugins
    plugins={pluginsMemo}
    components={components}
    ...
  >
  ....
</SlatePlugins>

完成以上操作,即可把逻辑组件加入到编辑器当中。

样式组件引入

组件样式引入

在初始化 SlatePlugins 时,还有一个 components 参数,这个参数用于正确渲染元素。

import { ELEMENT_LINE } from './plugins/line'

const components = withStyledPlaceHolders(
  createSlatePluginsComponents({
    [ELEMENT_H1]: withProps(StyledElement, {
      styles: {
        root: {
          color: '#000'
        }
      }
    }),
    [ELEMENT_LINE]: LineElement  // 加入分割线组件
  })
)

<SlatePlugins
    plugins={pluginsMemo}
    components={components}
    ...
  >
  ....
</SlatePlugins>

以上完成了组件渲染。

toolbar组件引入

import { ToolbarLine } from './plugins/line-ui'

export const ToolbarButtons = () => {
  return (
    <>
      <ToolbarElement type={getSlatePluginType(editor, ELEMENT_H1)} icon={<LooksOne />} />
      <ToolbarLine icon={<FileBreak />} />
    </>
  )
}

只需要简单的在工具条组件中引入我们开发好的组件即可。

下次在分享

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值