UPDATE Voici quelques démonstrations
contenuDémo éditable - nécessite un double clic pour que H1 devienne éditable
remplacer par la démo d'entrée - adopte event.target
mais l'interface utilisateur se met à trembler lorsqu'elle est rendue.
J'ai donc des composants fonctionnels, par exemple :
component1.js
import React from 'react';
const component1 = props => (
<div>
<h1>Title</h1>
</div>
);
export { component1 };
Ils sont variables. event.target
Il peut s'agir de n'importe quel élément de texte, comme un paragraphe, un titre, etc. J'essaie de permettre aux utilisateurs de modifier le contenu en ligne en cliquant dessus, donc je vais passer une fonction editMode
à ces composants fonctionnels, qui mettront à jour l'état du parent avec les informations d'édition, disons comme ceci :
<h1 onClick={event => {editMode(event, props.name, props.title, 'title')}}>title</h1>
Cela change l'état local du parent pour avoir toutes les informations nécessaires pour récupérer la valeur de redux, définir une cible, etc. Pour cet exemple, props.name
est le nom du composant, props.title
est la valeur, et 'title'
est la clé de l'objet dans redux.
Donc je vais ajouter quelque chose à mon component1.js et le faire ressembler un peu à ça :
import React from 'react';
const component1 = props => (
<div>
{props.editState === 'true' &&
<EditLayout
name={props.name}
target={props.target}
value={props.value}
onChange={event => someFunc(event)}
/>
}
<h1>Title</h1>
</div>
);
export { component1 };
Maintenant, cela fonctionne bien, sauf qu'il n'y a pas d'échelle. EditLayout
dans ce cas, retournera simplement une entrée avec une valeur correcte. Ce que je veux qu'il fasse, c'est s'adapter à ce qui est cliqué, obtenir la taille de la police, l'arrière-plan, le rembourrage, la marge, la position. Est-ce que je fais bien les choses ? Chaque fois que j'essaie, je rencontre d'énormes problèmes :
Idée 1 - déménager EditLayout
en dehors du composant fonctionnel
Question : positionnement
Je vais donc déplacer EditLayout vers le composant parent qui contient les deux éléments suivants component1.js
y EditLayout
. Cela me permettra de le manipuler depuis l'intérieur du composant fonctionnel, sans avoir à l'inclure partout. Je vais ensuite récupérer les coordonnées et d'autres informations importantes à partir de event.target
comme ça :
const coords = event.target.getBoundingClientRect();
const offsetX = coords.left;
const offsetY = coords.top;
const childHeight = coords.height;
const childWidth = coords.width;
const childClass = event.target.className;
Je vais ensuite envelopper le EditLayout
pour retourner un conteneur qui contient une entrée, et appliquer la taille/les coordonnées au conteneur positionné de manière absolue. Cela posera le problème du décalage de l'entrée d'un nombre aléatoire de pixels, en fonction de la taille et de l'emplacement de l'élément d'entrée. event.target
.
Idée 2 - transmettre les styles calculés pertinents à EditLayout
Problème : twitching sur le rendu, et je dois ajouter EditLayout
pour chaque event.target
qu'il y a, ainsi que la condition son' render
Je vais donc saisir tous les styles calculés importants comme ceci :
const computedTarget = window.getComputedStyle(event.target);
const childMargins = computedTarget.marginBottom;
const childPaddings = computedTarget.padding;
const childFontSize = computedTarget.fontSize;
const childTextAlign = computedTarget.textAlign;
Et le transmettre à component1.js
et le transmet ensuite à EditLayout
à l'intérieur de l'élément component1.js. I'll then condition the
event.target à cacher s'il est édité comme ceci :
<h1 className={ props.target === 'title' ? 'd-none' : ''}>Title</h1>
Et conditionner le EditLayout
à ne montrer que si c'est nécessaire :
{props.target === 'title' && <EditLayout />}
Dans cet exemple, cliquer sur h1 affichera l'entrée, mais la mise en page elle-même avec twitch sur le rendu. L'entrée aura exactement la même marge et taille de police que le h1, soit event.target
mais il apparaîtra plus grand et prolongera la mise en page. Démonstration :
Idée 3 - Utiliser du contenu conditionnelEditable
Problème : Nécessite un double-clic pour être activé, ne fonctionne pas dans Safari, ne me permet pas de présélectionner la valeur.
C'est le plus bizarre de tous. Je pensais que ce serait assez simple, faire quelque chose comme ça dans le composant fonctionnel render :
<h1 contentEditable={props.target === 'title'} onClick={event => props.setTarget(event)}>Title</h1>
Cependant, je dois double-cliquer pour l'activer. Je n'ai aucune idée de la raison pour laquelle, si je joins un journal de console chaque fois que onClick
est déclenchée, j'obtiendrai des sorties correctes, ainsi que la valeur cible correcte. J'ai essayé de nombreuses façons, mais il faut simplement double-cliquer. J'ai même essayé de gérer cela à l'intérieur du composant fonctionnel, car la plupart des choses sont gérées par un composant parent, mais cela ne fait aucune différence.
J'ai simplifié à l'extrême les exemples, de sorte qu'il est prudent de supposer/comprendre ce qui suit :
- Je passe les props de manière correcte, ils ne sont pas indéfinis.
- J'utilise bootstrap
- J'utilise des composants stylisés, et
EditLayout
est un composant stylé qui accepte les props et les transforme en CSS :font-size: ${props => props.fontSize};
- Les valeurs devraient être correctes, je ne manipule rien de ce que je reçois en retour de l'ordinateur.
getComputedStyle()
ogetBoundingClientRect()
- Je tiens à ce que mes composants fonctionnels restent fonctionnels et faciles à utiliser. ajouter. Les composants fonctionnels, dans ce cas, sont de simples structures HTML, et j'aimerais qu'elles restent aussi simples que possible.