Jak słuchać zdarzenia zmiany dla contentEditable
sterowania opartego na bazie danych?
var Number = React.createClass({
render: function() {
return <div>
<span contentEditable={true} onChange={this.onChange}>
{this.state.value}
</span>
=
{this.state.value}
</div>;
},
onChange: function(v) {
// Doesn't fire :(
console.log('changed', v);
},
getInitialState: function() {
return {value: '123'}
}
});
React.renderComponent(<Number />, document.body);
initialValue
gostate
i używamrender
, ale nie pozwalam, aby React go dalej aktualizował.contentEditable
, zmieniając swoje podejście - zamiastspan
lubparagraph
użyłem znakuinput
wraz z jegoreadonly
atrybutem.Odpowiedzi:
Edycja: Zobacz odpowiedź Sebastiena Lorbera, która naprawia błąd w mojej implementacji.
Użyj zdarzenia onInput i opcjonalnie onBlur jako rezerwy. Możesz chcieć zapisać poprzednią zawartość, aby zapobiec wysyłaniu dodatkowych zdarzeń.
Osobiście miałbym to jako moją funkcję renderującą.
jsbin
Który używa tego prostego opakowania wokół contentEditable.
źródło
this.setState({html: "something not in the editable div"}})
this.getDOMNode().innerHTML
inshouldComponentUpdate
nie jest zbyt dobrze zoptymalizowanestate.html
ostatnią „znaną” wartość, React nie zaktualizuje DOM, ponieważ nowy html jest dokładnie taki sam, jeśli chodzi o Reacta (nawet jeśli rzeczywisty DOM jest inny). Zobacz jsfiddle . Nie znalazłem na to dobrego rozwiązania, więc wszelkie pomysły są mile widziane.shouldComponentUpdate
powinno być czyste (bez efektów ubocznych).Edytuj 2015
Ktoś wykonał projekt na NPM z moim rozwiązaniem: https://github.com/lovasoa/react-contenteditable
Edycja 06/2016: Właśnie napotkałem nowy problem, który pojawia się, gdy przeglądarka próbuje „przeformatować” kod HTML, który właśnie mu przekazałeś, co prowadzi do tego, że komponent zawsze renderuje się ponownie. Widzieć
Edycja 07/2016: oto moja zawartość produkcyjna Edytowalna implementacja. Ma kilka dodatkowych opcji,
react-contenteditable
które możesz chcieć, w tym:Podsumowanie:
Rozwiązanie FakeRainBrigand działało dla mnie całkiem dobrze przez jakiś czas, dopóki nie pojawiły się nowe problemy. ContentEditables są uciążliwe i nie są łatwe w obsłudze React ...
Ten JSFiddle demonstruje problem.
Jak widać, po wpisaniu niektórych znaków i kliknięciu
Clear
zawartość nie jest czyszczona. Dzieje się tak, ponieważ próbujemy zresetować zawartość edytowalną do ostatniej znanej wartości wirtualnej domeny.Więc wydaje się, że:
shouldComponentUpdate
zapobiegać skokom pozycji karetkishouldComponentUpdate
ten sposób.Potrzebujesz więc dodatkowej linii, aby zawsze, gdy
shouldComponentUpdate
zwróci wartość tak, masz pewność, że zawartość DOM jest rzeczywiście zaktualizowana.Tak więc wersja tutaj dodaje a
componentDidUpdate
i staje się:Wirtualny dom pozostaje nieaktualny i może nie jest to najbardziej wydajny kod, ale przynajmniej działa :) Mój błąd został rozwiązany
Detale:
1) Jeśli umieścisz shouldComponentUpdate, aby uniknąć skoków karetki, treść edytowalna nigdy nie będzie ponownie renderowana (przynajmniej po naciśnięciu klawisza)
2) Jeśli komponent nigdy nie jest ponownie renderowany po naciśnięciu klawisza, React przechowuje nieaktualną wirtualną domenę dla tej zawartości, którą można edytować.
3) Jeśli React zachowuje przestarzałą wersję edytowalnej treści w swoim wirtualnym drzewie dom, to jeśli spróbujesz zresetować zawartość edytowalną do wartości nieaktualnej w wirtualnym dom, to podczas wirtualnego różnic dom, React obliczy, że nie ma żadnych zmian zastosuj do DOM!
Dzieje się tak głównie wtedy, gdy:
źródło
{...this.props}
aby klient mógł dostosować to zachowanie z zewnątrzshouldComponentUpdate
kod zapobiega skokom karetki?To jest najprostsze rozwiązanie, które zadziałało.
źródło
onInput
jak podano w przykładzie.Prawdopodobnie nie jest to dokładnie odpowiedź, której szukasz, ale po tym, jak sam się z tym zmagałem i miałem problemy z sugerowanymi odpowiedziami, postanowiłem zamiast tego uczynić ją niekontrolowaną.
Kiedy
editable
prop jestfalse
, używamtext
rekwizytu bez zmian, ale kiedy jesttrue
, przełączam się na tryb edycji, w którymtext
nie ma żadnego efektu (ale przynajmniej przeglądarka nie wariuje). W tym czasieonChange
są odpalane przez sterowanie. Wreszcie, kiedyeditable
wracam dofalse
, wypełnia HTML tym, co zostało przekazanetext
:źródło
shouldComponentUpdate
tak łatwo zaimplementować , więc nawet to nie chroni mnie już przed skokami karetki. Na koniec mam:empty:before
symbole zastępcze pseudoelementów CSS, ale tashouldComponentUpdate
implementacja uniemożliwiła FF i Safari wyczyszczenie pola, gdy zostało wyczyszczone przez użytkownika. Pięć godzin zajęło mi uświadomienie sobie, że mogę ominąć te wszystkie problemy dzięki niekontrolowanemu CE.editable
sięUncontrolledContentEditable
. Czy możesz podać działający przykład?editable
z zewnątrz. Pomyśl o polu, które można edytować bezpośrednio, gdy użytkownik naciśnie „Edytuj” i powinno być ponownie odczytywane tylko wtedy, gdy użytkownik naciśnie „Zapisz” lub „Anuluj”. Więc kiedy jest tylko do odczytu, używam rekwizytów, ale przestaję na nie patrzeć za każdym razem, gdy wchodzę w „tryb edycji” i patrzę na rekwizyty dopiero po wyjściu z niego.escapeTextForBrowser
naescapeTextContentForBrowser
.Ponieważ po zakończeniu edycji fokus elementu jest zawsze tracony, możesz po prostu użyć haka onBlur.
źródło
W tym celu sugeruję użycie mutationObserver. Daje dużo większą kontrolę nad tym, co się dzieje. Zawiera również więcej szczegółów na temat sposobu, w jaki przeglądarka interpretuje wszystkie naciśnięcia klawiszy
Tutaj w TypeScript
źródło
Oto komponent, który zawiera wiele z tego przez lovasoa: https://github.com/lovasoa/react-contenteditable/blob/master/index.js
Zmienia zdarzenie w emitChange
Z powodzeniem stosuję podobne podejście
źródło