Como faço para ouvir o contentEditable
controle baseado em evento de mudança ?
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
emstate
e usá-lo emrender
, mas eu não deixo Reagir atualização ainda mais.contentEditable
mudando minha abordagem - em vez de umspan
ouparagraph
, usei uminput
junto com seureadonly
atributo.Respostas:
Edit: Veja a resposta de Sebastien Lorber que corrige um bug em minha implementação.
Use o evento onInput e, opcionalmente, onBlur como um fallback. Você pode querer salvar o conteúdo anterior para evitar o envio de eventos extras.
Eu pessoalmente teria isso como minha função de renderização.
jsbin
Que usa este invólucro simples em torno de contentEditable.
fonte
this.setState({html: "something not in the editable div"}})
this.getDOMNode().innerHTML
nosshouldComponentUpdate
não é muito otimizado direitostate.html
o último valor "conhecido". O React não atualizará o DOM porque o novo html é exatamente o mesmo no que diz respeito ao React (embora o DOM real seja diferente). Veja jsfiddle . Não encontrei uma boa solução para isso, então qualquer ideia é bem-vinda.shouldComponentUpdate
deve ser puro (não tem efeitos colaterais).Editar 2015
Alguém fez um projeto no NPM com minha solução: https://github.com/lovasoa/react-contenteditable
Editar 06/2016: Acabei de encontrar um novo problema que ocorre quando o navegador tenta "reformatar" o html que você acabou de fornecer a ele, levando a um componente sempre re-renderizado. Vejo
Editar 07/2016: aqui está minha implementação de produção de contentEditable. Ele tem algumas opções adicionais
react-contenteditable
que você pode desejar, incluindo:Resumo:
A solução do FakeRainBrigand funcionou muito bem para mim por algum tempo, até que encontrei novos problemas. ContentEditables são uma dor e não são realmente fáceis de lidar com React ...
Este JSFiddle demonstra o problema.
Como você pode ver, ao digitar alguns caracteres e clicar em
Clear
, o conteúdo não é apagado. Isso ocorre porque tentamos redefinir o contenteditable para o último valor dom virtual conhecido.Então, parece que:
shouldComponentUpdate
evitar saltos na posição do cursorshouldComponentUpdate
desta forma.Portanto, você precisa de uma linha extra para que, sempre que
shouldComponentUpdate
retornar sim, você tenha certeza de que o conteúdo DOM está realmente atualizado.Portanto, a versão aqui adiciona um
componentDidUpdate
e se torna:O Dom virtual permanece desatualizado e pode não ser o código mais eficiente, mas pelo menos funciona :) Meu bug foi resolvido
Detalhes:
1) Se você colocar shouldComponentUpdate para evitar saltos circunflexos, o contenteditable nunca será processado novamente (pelo menos nas teclas)
2) Se o componente nunca for renderizado novamente no pressionamento de tecla, o React manterá um dom virtual desatualizado para este conteúdo editável.
3) Se o React mantiver uma versão desatualizada do conteúdo editável em sua árvore de dom virtual, se você tentar redefinir o conteúdo editável para o valor desatualizado no dom virtual, durante a comparação do dom virtual, o React calculará que não há alterações em aplique ao DOM!
Isso acontece principalmente quando:
fonte
{...this.props}
para que o cliente possa personalizar esse comportamento de forashouldComponentUpdate
código evita saltos circulares?Esta é a solução mais simples que funcionou para mim.
fonte
onInput
conforme indicado no exemplo.Esta provavelmente não é exatamente a resposta que você está procurando, mas tendo lutado com isso sozinho e tendo problemas com as respostas sugeridas, decidi torná-la descontrolada.
Quando
editable
prop éfalse
, eu usotext
prop como está, mas quando étrue
, eu mudo para o modo de edição no qualtext
não tem efeito (mas pelo menos o navegador não enlouquece). Durante este tempoonChange
são disparados pelo controle. Finalmente, quando eu mudareditable
volta parafalse
, ele preenche o HTML com o que foi passado emtext
:fonte
shouldComponentUpdate
tão facilmente, então nem mesmo isso me salva mais de saltos circulares. Por fim, tenho:empty:before
placeholders de pseudoelemento CSS, mas essashouldComponentUpdate
implementação impediu que o FF e o Safari limpassem o campo quando ele fosse limpo pelo usuário. Levei 5 horas para perceber que posso contornar todos esses problemas com CE não controlado.editable
noUncontrolledContentEditable
. Você poderia fornecer um exemplo executável?editable
de fora. Pense em um campo que pode ser editado em linha quando o usuário pressiona “Editar” e deve ser novamente somente leitura quando o usuário pressiona “Salvar” ou “Cancelar”. Então, quando é somente leitura, eu uso adereços, mas paro de olhar para eles sempre que entro no “modo de edição” e só olho para os adereços novamente quando saio dele.escapeTextForBrowser
paraescapeTextContentForBrowser
.Uma vez que quando a edição é concluída, o foco do elemento é sempre perdido, você pode simplesmente usar o gancho onBlur.
fonte
Eu sugiro usar um mutationObserver para fazer isso. Isso lhe dá muito mais controle sobre o que está acontecendo. Também fornece mais detalhes sobre como o navegador interpreta todas as teclas digitadas
Aqui no TypeScript
fonte
Aqui está um componente que incorpora muito disso por lovasoa: https://github.com/lovasoa/react-contenteditable/blob/master/index.js
Ele corrige o evento no emitChange
Estou usando uma abordagem semelhante com sucesso
fonte