简体   繁体   English

如何根据文本选择更新下拉列表中的值

[英]How to update value in dropdown based on text selection

I am working on a React-based Google Docs clone as a side project.我正在开发一个基于 React 的 Google Docs 克隆作为一个副项目。 I'm using TipTap as the base.我使用 TipTap 作为基础。

I wanted to try to mimic the functionality in Google Docs where the select field would update with the appropriate value based on whatever text the user selects (ex., "heading 1" would show up on the select field if a user highlights text with <h1></h1> styling).我想尝试模仿 Google Docs 中的功能,其中选择字段将根据用户选择的任何文本更新为适当的值(例如,如果用户使用 < 突出显示文本,则“标题 1”将显示在选择字段上h1></h1> 样式)。

Here's a small video of the functionality I want to mimic: https://i.gyazo.com/18cc57f0285c8c5cd80d5dd6051f0ee7.mp4这是我想模仿的功能的小视频: https ://i.gyazo.com/18cc57f0285c8c5cd80d5dd6051f0ee7.mp4

This is the code I have so far with the React Hook used for the select fields:这是我迄今为止使用用于选择字段的 React Hook 的代码:

const [font, setFont] = useState('sans-serif')
const handleFontChange = (e) => {
   setFont(e.target.value)
   editor.chain().focus().setFontFamily(e.target.value).run()
}

return (
   <select value={font} onChange={handleFontChange}>
    {fontFamilies.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}
   </select>
) 

I've tried to wrap my head around React Hooks and the Selection API, but I'm stuck.我试图围绕 React Hooks 和 Selection API,但我被困住了。 Is this at all possible in Javascript/React?这在 Javascript/React 中是否可行?

EDIT:编辑:

I found a function from Tiptap's API that does exactly what I'm looking for.我从 Tiptap 的 API 中找到了一个函数,它完全符合我的要求。 I guess now the problem is how do I update that value into the select?我想现在的问题是如何将该值更新到选择中? Here's my new code:这是我的新代码:

const font = [
     { value: 'sans-serif', label: 'Sans-serif' }, ...
   ]

const [selectedFont, setSelectedFont] = useState([])

const handleFontChange = (obj) => {
    setSelectedFont(obj)
    editor.chain().focus().setFontFamily(obj.value).run()
    console.log(editor.isActive('textStyle', {fontFamily: selectedFont.value})) // prints true if the user clicked on text with the property active, otherwise prints false
}

return (
    <Select
       name="fontFamily"
       options={font}
       isClearable="true"
       isSearchable="true"
       value={selectedFont}
       onChange={(option) => handleFontChange(option)}
    />
)

It feels like the solution is really simple but I'm just overthinking it.感觉解决方案非常简单,但我只是想多了。

So I finally figured out what to do.所以我终于想出了该怎么做。 I needed to pass a function in value that iterated over the array:我需要传递一个遍历数组的值函数:

const fontList = [
    { label: 'Sans-serif', value: 'sans-serif' },
    ...
]

<Select
    name="fontFamily"
    placeholder="Select font..."
    value={
      editor.isActive('textStyle', {fontFamily: font}) ? (
        selectedFont.find(index => fontList[index])
      ) : ''
    }
    options={fontList}
    onChange={({value: fontSel}) => {
      setFont(fontSel)
      editor.chain().focus().setFontFamily(fontSel).run()
    }}
  />

It only took me a whole week of tearing my hair out... Glad to finally get this done.我只花了整整一周的时间把头发扯掉……很高兴终于完成了。

Just to add to this, I was able to do the following in Vue to select headings with a dropdown.除此之外,我可以在 Vue 中执行以下操作来选择带有下拉菜单的标题。

<select
    :value="editor.isActive('heading') ? editor.getAttributes('heading').level : 0"
    @input="setSelectedHeading"
  >
    <option
      v-for="heading in headings"
      :key="heading.value"
      :label="heading.label"
      :value="heading.value"
    />
</select>

headings: [
    { value: 0, label: 'Normal text' },
    { value: 1, label: 'Heading 1' },
    { value: 2, label: 'Heading 2' },
    { value: 3, label: 'Heading 3' },
    { value: 4, label: 'Heading 4' },
    { value: 5, label: 'Heading 5' },
    { value: 6, label: 'Heading 6' }
  ]

setSelectedHeading (selected) {
  if (selected === 0) {
    const selectedLevel = this.editor.getAttributes('heading').level
    return this.editor.chain().focus().toggleHeading({ level: selectedLevel }).run()
  }
  return this.editor.chain().focus().setHeading({ level: selected }).run()
}

In case someone wants to create a simple dropdown menu with vue and tiptap , since this doesn't seem to work:如果有人想用vuetiptap创建一个简单的下拉菜单,因为这似乎不起作用:

<select class="font-type">
  <option @click="editor.chain().focus().setParagraph().run()" selected>Paragraph</option>
  <option @click="editor.chain().focus().toggleHeading({level: 1}).run()">Heading 1</option>
  <option @click="editor.chain().focus().toggleHeading({level: 2}).run()">Heading 2</option>
  <option @click="editor.chain().focus().toggleHeading({level: 3}).run()">Heading 3</option>
</select>

you can do this:你可以这样做:

<select class="font-type" @change="toggleType(editor, $event)">
  <option value="p" selected>Paragraph</option>
  <option value="1">Heading 1</option>
  <option value="2">Heading 2</option>
  <option value="3">Heading 3</option>
</select>

and add this to your <script> :并将其添加到您的<script>

const toggleType = (editor, event) => {
    if (event.target.value == 'p') {
        editor.chain().focus().setParagraph().run()
    } else {
        editor.chain().focus().toggleHeading({level: Number(event.target.value)}).run()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM