以下片段是我的 SlateJS 实现。
在应用程序某处的文章详细信息页面上,我想嵌入此编辑器(表情符号)组件,将与该文章 ID 相关的相应值道具传递给它。不幸的是,现在 Emoji 组件的设置方式,我无法传入 value props。Emoji-Editor 将始终考虑 Value.json 或现有的 localStorage 值。
如何在 Emoji 组件中注入值?
旁注: 还有哪些其他可能的实现方式?实现渲染功能而不是利用表情符号(编辑器)组件是否更有意义?
import React, { Component } from 'react'
import styled from 'styled-components'
import { Editor } from 'slate-react'
import { Value } from 'slate'
import initialValue from '../../components/utilities/Value.json'
const Toolbar = styled.div`
display: flex;
justify-content: center;
`
const Icon = styled.span`
cursor: pointer;
`
const existingValue = JSON.parse(localStorage.getItem('content'))
const currentValue = Value.fromJSON(
existingValue || initialValue)
function MarkHotkey(options) {
const { type, key } = options
return {
onKeyDown(event, change) {
if (!event.ctrlKey || event.key !== key) return
event.preventDefault()
change.toggleMark(type)
return true
},
}
}
const plugins = [
MarkHotkey({ key: 'b', type: 'bold' }),
MarkHotkey({ key: '`', type: 'code' }),
MarkHotkey({ key: 'i', type: 'italic' }),
MarkHotkey({ key: '~', type: 'strikethrough' }),
MarkHotkey({ key: 'u', type: 'underline' }),
MarkHotkey({ key: 'q', type: 'blockquote' }),
]
const EMOJIS = [
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
]
const noop = e => e.preventDefault()
class Emoji extends Component {
state = {
value: currentValue,
}
onChange = ({ value }) => {
if (value.document !== this.state.value.document) {
const content = JSON.stringify(value.toJSON())
localStorage.setItem('content', content)
}
this.setState({ value })
}
// When clicking an emoji, insert it
onClickEmoji = (e, code) => {
e.preventDefault()
const { value } = this.state
const change = value.change()
change
.insertInline({
type: 'emoji',
isVoid: true,
data: { code },
})
.collapseToStartOfNextText()
.focus()
this.onChange(change)
}
renderToolbar = () => {
return (
<Toolbar>
{EMOJIS.map((emoji, i) => {
const onMouseDown = e => this.onClickEmoji(e, emoji)
return (
// eslint-disable-next-line react/jsx-no-bind
<Icon key={i} onMouseDown={onMouseDown}>
<span>{emoji}</span>
</Icon>
)
})}
</Toolbar>
)
}
renderEditor = () => {
return (
<Editor
placeholder="What do you want to say..? "
plugins={plugins}
value={this.state.value}
onChange={this.onChange}
renderNode={this.renderNode}
renderMark={this.renderMark}
/>
)
}
// Add a `renderNode` method to render nodes.
renderNode = props => {
const { attributes, children, node, isSelected } = props
switch (node.type) {
case 'heading':
return <h1 {...attributes}>{children}</h1>
case 'paragraph':
return <p {...attributes}>{children}</p>
case 'emoji':
const { data } = node
const code = data.get('code')
return (
<span
className={`emoji ${isSelected ? 'selected' : ''}`}
{...props.attributes}
contentEditable={false}
onDrop={noop}
>
{code}
</span>
)
default:
return
}
}
// Add a `renderMark` method to render marks.
renderMark = props => {
const { mark, children } = props
switch (mark.type) {
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'strikethrough':
return <del>{children}</del>
case 'underline':
return <u>{children}</u>
case 'blockquote':
return <blockquote>{children}</blockquote>
default:
return
}
}
render = () => {
return (
<div>
{this.renderEditor()}
{this.renderToolbar()}
</div>
)
}
}
export default Emoji