web-dev-qa-db-fra.com

Implémentation de la saisie semi-automatique dans le projet JS mais sans "déclencheur" comme "@"

Je veux implémenter quelque chose comme un éditeur de tag. Cependant, il s’agit uniquement de ces balises. Par conséquent, je souhaite que l’utilisateur voie les suggestions de saisie semi-automatique sans avoir à saisir quelque chose comme @ ou # , juste le texte lui-même.

J'ai quelque chose qui fonctionne un peu , mais la fenêtre contextuelle s'affiche dans des positions étranges à l'écran:

  • lorsque je tape quelque chose pour la première fois et que le menu contextuel apparaît, il apparaît quelque part dans le coin supérieur gauche de l'écran
  • après la création de la première entité, lorsque vous appuyez sur SPACE et recommencez à taper, la fenêtre contextuelle apparaît quelques pixels à droite de sa position intuitive (c'est-à-dire sous la première lettre du mot)

Voici un exemple d'un éditeur de ce type bien connu (bien que non implémenté avec Draft), afin que vous puissiez mieux comprendre ce que je souhaite implémenter.

Gmail email composer

Tout d’abord, voici la fonction qui déclenche la fenêtre de suggestions:

private onChange(editorState: EditorState) {
  const content = editorState.getCurrentContent();
  const selection = editorState.getSelection();
  const currentBlock = content.getBlockForKey(selection.getAnchorKey());

  if (selection.isCollapsed()) {
    const blockText = currentBlock.getText();
    const wordMeta = getWordAt(blockText, selection.getAnchorOffset());
    const categoryRegex = /([\w]*)/;
    const matches = wordMeta.Word.match(categoryRegex);
    const existingEntity = currentBlock.getEntityAt(wordMeta.begin);

    if (!existingEntity && matches) {
      const categorySearch = matches[1];
      const selection = window.getSelection();
      if (this.state.autoComplete.search !== categorySearch && selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const boundingRect = getRangeBoundingClientRect(range);

        this.setState((prevState: StateType) => {
          let state = {
            autoComplete: {
              active: true,
              search: categorySearch,
              searchMeta: {
                begin: wordMeta.begin,
                end: wordMeta.end,
              },
            },
            selectionRect: prevState.selectionRect,
          };

          if (prevState.autoComplete.active === false) {
            state.selectionRect = boundingRect;
          }

          return state;
        });
      }
    }
  }

  this.props.onChange(editorState);
}

Voici la fonction getWordAt:

function getWordAt(text: string, pos: number): WordMeta
{
  const left = text.slice(0, pos + 1).search(/\S+$/);
  const right = text.slice(pos).search(/\s/);

  if (right < 0) {
    return {
      Word: text.slice(left),
      begin: left,
      end: text.length,
    };
  }

  return {
    Word: text.slice(left, right + pos),
    begin: left,
    end: right + pos,
  };
}

Quelle serait une meilleure façon de gérer la position de la fenêtre contextuelle et peut-être même la stratégie d'auto-complétion de ce type? Je vous remercie!

17
Victor

Au lieu de draft-js-typeahead - TypeaheadEditor est un composant de réaction qui enveloppe l'éditeur de brouillon. Vous pouvez utiliser React-Autosuggest composant qui répond aux exigences. Son rendu personnalisé fonctionne de manière native avec les éléments React. C'est rapide et assez facilement personnalisable. Avoir un contrôle total sur le rendu des suggestions.

Nous pouvons lui faire gérer des objets JS au lieu de chaînes simples.

  1. les accessoires onSuggestionSelected sont un rappel pour obtenir la suggestion sélectionnée
  2. La méthode suggestionRenderer accepte les suggestions et retourne le balisage React

Départ React-Autosuggest .

Vous pouvez utiliser le composant ci-dessus en utilisant un rendu de bloc personnalisé , il est possible d'introduire des interactions riches et complexes dans le cadre de votre éditeur. 

Vous devez vous casser la tête pour réaliser ce que vous voulez, ce n'est pas simple. C’était ma suggestion par laquelle vous pourriez y parvenir, mais ce n’est pas si facile. 

1
Varsha