Vue: Adicionar modificadores de modelo v personalizados

Criado em 13 set. 2016  ·  52Comentários  ·  Fonte: vuejs/vue

Temos .lazy , .number , .trim e .undef está a caminho.

Além de .lazy todos eles funcionam como filtros bidirecionais.

Como o 2.0 não suporta filtros de 2 vias, pode haver uma nova API para adicionar modificadores de modelo v personalizados para atender à mesma necessidade.

feature request

Comentários muito úteis

Alguma chance de conseguirmos reabrir esse problema? Um caso de uso comum para mim é a necessidade de formatar automaticamente os dados em um campo conforme estão sendo digitados. Algo como pegar '101216' e transformá-lo em '10/12/16'. Ser capaz de criar um modificador de v-model personalizado simplificaria muito meu código, pois eu poderia escrever v-model.date em vez de ter que construir um componente de entrada personalizado com props e eventos.

Todos 52 comentários

As propriedades computadas @posva não são reutilizáveis.

Quase tudo é reutilizável através de um mixin.
Você pode usar uma função que gera um mixin. Desta forma, você pode vincular um
propriedade computada dinamicamente. Eu não posso colocar esse exemplo em um violino agora
mas eu faria isso o mais rápido possível.
No entanto, concordo que é um caso de uso muito comum para entradas terem
transformações aplicadas. Uma API adequada ou pelo menos uma explicação sobre o
guia é necessário

Em Ter, 13 Set 2016, 18:48 Francisco Lourenço, [email protected]
escrevi:

@posva https://github.com/posva propriedades computadas não são reutilizáveis.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/vuejs/vue/issues/3666#issuecomment -246746524 ou silenciar
o segmento
https://github.com/notifications/unsubscribe-auth/AAoicf33lCvETQc9LBQ5GGZ93ExPcLS_ks5qptPegaJpZM4J7vQ0
.

Quase tudo é reutilizável através de um mixin.
Você pode usar uma função que gera um mixin. Desta forma, você pode vincular um
propriedade computada dinamicamente. Eu não posso colocar esse exemplo em um violino agora
mas eu faria isso o mais rápido possível.
No entanto, concordo que é um caso de uso muito comum para entradas terem
transformações aplicadas. Uma API adequada ou pelo menos uma explicação sobre o
guia é necessário

Dito de outra forma, as propriedades computadas não são reutilizáveis. Você pode usar funções de fábrica + mixins como uma solução alternativa , mas a usabilidade e a legibilidade não se comparam.

Para o meu projeto, eu precisava muito desse recurso, então usei a abordagem de entrada personalizada recomendada:

InputCustom.js

define(function () {
  return Vue.extend({
    data: function () {
      return {
        focused: false
      };
    },
    template: '<input @focus="onFocus" @blur="onBlur" @input="onInput" @change="setDisplayValue">',
    props: ['value'],
    watch: {
      value: function () {
        if (!this.focused) {
          this.setDisplayValue();
        }
      }
    },
    mounted: function () {
      this.setDisplayValue();
    },
    methods: {
      onInput: function () {
        this.$emit('input', this.parse(this.$el.value));
      },
      onFocus: function () {
        this.focused = true;
      },
      onBlur: function () {
        this.focused = false;
        this.setDisplayValue();
      },
      setDisplayValue: function () {
        this.$el.value = this.format(this.value);
      }
    }
  });
});

InputText.js

define(['js/InputCustom'], function (InputCustom) {
  return InputCustom.extend({
    methods: {
      parse: function (val) {
        val = val.trim();
        return val === '' ? null : val;
      },
      format: function (val) {
        return val === null ? '' : val;
      }
    }
  });
});

Na minha opinião, essa abordagem é muito conveniente e decidi não usar nenhum modificador v-model, incluindo .lazy .

Para casos de uso mais personalizados que os modificadores integrados não podem suportar, o que @ecmel mencionou é a abordagem recomendada. Vamos documentar isso com mais detalhes no guia oficial.

A ideia desta proposta de recurso é aproveitar a diretiva v-model existente, que já funciona com todos os elementos input . Para salvar o trabalho de escrever _InputCustom.js_ em cada projeto, pois isso já foi feito em v-model , bastando apenas escrever o equivalente a _InputText.js_ em um modificador customizado, que contém toda a lógica necessária para ser modificado na maioria das vezes. O fato de que v-model já vem com modificadores prova que é um padrão intuitivo e desejável. É natural facilitar a criação de modificadores personalizados, economizar o trabalho de criar elementos personalizados e ter que implementar manualmente a vinculação dom/model.

Se fizer sentido do ponto de vista da API, seria interessante saber quais são as limitações técnicas que estão conduzindo a decisão de não implementar esse recurso.

Alguma chance de conseguirmos reabrir esse problema? Um caso de uso comum para mim é a necessidade de formatar automaticamente os dados em um campo conforme estão sendo digitados. Algo como pegar '101216' e transformá-lo em '10/12/16'. Ser capaz de criar um modificador de v-model personalizado simplificaria muito meu código, pois eu poderia escrever v-model.date em vez de ter que construir um componente de entrada personalizado com props e eventos.

Depois de usar o vue js por um tempo no meu projeto, acho que esse problema deve realmente ser reaberto.

Pelo menos precisamos de um modificador undef .

Concordo que esta questão deve ser reaberta. Não tenho certeza do que undef deveria fazer, mas gostaria de um modificador v-model que defina minha variável para null caso o valor aparado da entrada seja uma string vazia.

Eu adoraria ser capaz de fazer isso sozinho de uma maneira direta.

Funcionalidade mais redundante do que isso foi adicionada, por exemplo, com https://github.com/vuejs/vue/issues/5194 . Do lado de fora, Vue parece estar lentamente comprometendo alguns de seus princípios em favor de convenções e práticas promovidas pela comunidade react. Ligeiramente desviando das qualidades que o fizeram se destacar em primeiro lugar. Seria interessante saber se esta é uma decisão consciente com a intenção de facilitar a migração de react, ou apenas coincidência.

Escrever componentes personalizados é bom, mas se você quiser usar um componente personalizado de terceiros como https://github.com/text-mask/text-mask/tree/master/vue#readme , não há uma maneira direta de higienizar o mascarado entrada para valores de modelo, exceto usando propriedades computadas.

Então, eu só quero usar um campo padrão HTML input[type=date] para editar um tipo de data no meu modelo e essa estrutura maravilhosamente poderosa e extensível não pode fazer isso imediatamente? Não consigo ler a data no campo, substituir minha data por uma string em meus dados depois de selecionar uma data. Esta solução pode ser escrita em duas linhas com filtros bidirecionais ou com modificador.

Mas a melhor solução seria apenas suportá-lo nativamente, como fazem para caixa de seleção e outro campo de entrada padrão, por que "data" é uma coisa especial?

+1 para modificadores personalizados. Parece um acéfalo, a menos que haja uma boa razão para não fazê-lo?

Mascarar a entrada e analisar o valor para uso do aplicativo é uma prática muito comum, e fazer algum "açúcar sintático" como v-model.lazy.currency="amount" seria incrível!

1+ para modificadores personalizados.
Eu tenho uma entrada de rádio simples com valores true|false que são avaliados como strings - mas eu preciso deles como um booleano - propriedades computadas não serão inteligentes neste caso, pois preciso reimplementar uma propriedade computada para cada entrada de rádio. Por exemplo, ter 100 entradas de rádio resultará em 100 propriedades computadas

+1 para modificadores personalizados, mas concordo com tobei -- input[type=date] deve funcionar automaticamente.

+1 para modificadores personalizados.

Eu venho de um background Angular, e comecei com o vue, e vi este tópico.

Eu sinto que realmente ajudaria ter algo como os analisadores e formatadores do Angular, no Vue também. Se eu pudesse fazer algo como v-model.dateFormat e resultar em algo como mm/dd/aaaa, seria muito legal.

EDIT: parece que reiterou o que @restored18 disse. +1 para você também

+1 para modificadores de modelo v personalizados.

No meu caso, faço um loop sobre alguns objetos aninhados recuperados em JSON e uso um único modelo HTML (em vez de um modelo por objeto). Neste caso acredito que as propriedades computadas não funcionam?

Atualmente, estou colocando métodos de conversão personalizados entre o formato do servidor e o formato v-model ao buscar e enviar dados, mas adoraria algo apenas "incorporado" para o qual eu pudesse passar as funções.

+1 para isso. Ele costumava estar disponível antes de 2.2. Você pode acessar a propriedade através,

this.$vnode.data.directives

Ele foi removido com a adição de valores de entrada de modelo personalizado, mas era um recurso muito útil e deveria estar de volta na estrutura.

+1 para isso.

Modificadores de modelo v personalizados seriam ótimos!

eu também

+1 em 2018 também...

+1 É um recurso necessário para o código DRY na minha opinião. Agora eu tenho que criar 10 observadores que fazem a mesma coisa para um formulário com muita entrada. Um modificador personalizado resolveria tudo.

+1 Acabei de iniciar o vue e já preciso desse tipo de filtros bidirecionais ...

+1 definitivamente necessário

+1

Você pode construir auxiliares como este para a maioria dos casos de uso IMO

@nickmessing que não cobre o caso de uso (realmente útil) descrito aqui, que é a modificação no local do texto de entrada. Se você tiver uma caixa de entrada que deseja que sempre seja formatada como um telefone, terá <input v-model.phone="some_data"> . Quando o usuário digitava o texto, ele o formava automaticamente.

Isso parece um recurso tão básico e é mais difícil do que deveria ser agora. O comportamento já existe na estrutura, mas por algum motivo está restrito ao código somente da estrutura. Queremos poder adicionar um modificador personalizado que faça isso, que seja reutilizável em componentes e projetos, assim como filtros e diretivas são agora.

@bbugh concordo totalmente, estou tendo um caso semelhante com a formatação de IBANs e seria uma maneira tão agradável e declerativa de simplesmente colocar v-model.iban="payment.iban" lá ...

@franciscolourenco talvez alguém possa explicar por que isso não deve ser suportado pelo framework para que fique mais óbvio.

+1 para modificadores personalizados, há muitos casos de uso que podem ser realizados com esse recurso

Em nosso aplicativo, existem poucas entradas diferentes para formatar moedas, sempre armazenamos o valor de centavos no modelo, mas exibimos valores em dólares bem formatados nas entradas (portanto, 123456 no modelo mostrado como $ 1.234,56) <input v-model.dollars="cents" />

Outro caso de uso é limpar e liberar campos html para evitar ataques XSS (o modelo armazena " A &amp; B " enquanto a entrada mostra " A & B ") <input v-model.html="text" />

+1

+1

+1 para modificadores personalizados.
Fiquei realmente surpreso por não poder fazer algo como v-model.trim.uppercase=...

+1

+1

+1

+1
Modificadores de entrada v-model nativos seriam um ótimo recurso. Como as pessoas mencionam aqui, há muitos casos de uso. Eu precisava de modificadores de data e moeda para todos os projetos em que estive trabalhando.

devemos abrir um problema aqui? https://github.com/vuejs/rfcs

eu já marquei isso com +1, mas quero deixar um recado para as pessoas que precisam de algo “agora”

enquanto o modificador é muito mais eficiente, consegui obter o mesmo efeito usando uma entrada/componente transparente com um campo getter/setter computado.

posso compartilhar um exemplo se alguém precisar

Não implementamos isso porque há muitas coisas a serem consideradas nesse recurso aparentemente fácil:

  • Os modificadores internos são, na verdade, dicas de tempo de compilação que geram código compilado diferente. Modificadores personalizados provavelmente precisam ser definidos usando uma configuração de tempo de execução, que é um mecanismo diferente.

  • Para configuração de tempo de execução, que tipo de API devemos expor para isso?

  • Tínhamos filtros bidirecionais no passado. Uma transformação de valor bidirecional requer que o usuário implemente uma lógica impecável para que a ligação bidirecional possa se estabilizar. Caso contrário, você corre o risco de colocar todo o seu aplicativo em um loop infinito para casos extremos.

    • A razão pela qual temos .number e .trim é porque eles são de fato transformações unidirecionais (aplicadas apenas ao sincronizar o valor DOM com os dados do componente) e, portanto, com garantia de estabilização.
  • Como os modificadores personalizados devem se comportar quando v-model é usado em um componente?

  • Como os modificadores personalizados devem se comportar em tipos de entrada que não sejam de texto, por exemplo, radio , checkbox e o mais importante, <select> ?

Todas essas perguntas ficam sem resposta e tornam o pedido mais complexo do que parece. É por isso que concordo que seria um bom candidato para um RFC adequado que cubra tudo isso, se alguém realmente quiser esse recurso. Até então, mais +1s não o movem para frente de forma alguma.

@rkingon Já existe um exemplo em https://github.com/vuejs/vue/issues/3666#issuecomment -249583603, mas se o seu for diferente/melhor, basta postar. Pode ser útil para iniciantes.

@Gotterbild eu perdi essa amostra, mas é muito complicado em versões posteriores do Vue (que poderia ter sido suporte a componentes pré-transparentes)

aqui está um muito simples que eu tenho que apenas converte uma porcentagem para decimal (ou seja: 4,5 -> 0,045) e vice-versa (valor "view" e valor "model")

<template>
    <input type="number" v-on="listeners" v-model="innerValue">
</template>

<script>

    export default {
        props: ['value'],
        computed: {
            listeners () {
                const { input, ...listeners } = this.$listeners
                return listeners
            },
            innerValue: {
                get () {
                    return (this.value) ? `${(this.value * 100)}` : ''
                },
                set (_val) {
                    const val = (_val) ? (_val / 100) : ''
                    this.$emit('input', val)
                }
            }
        }
    }

</script>

isso é mais simples do que o acima, pois você não precisa especificar novamente todo o foco/desfoque/etc

@yyx990803 obrigado por fornecer mais informações básicas sobre este tópico.

para meus casos de uso, não "preciso" de modificadores personalizados. é só que, do ponto de vista do consumidor, faria sentido que o vue tenha uma maneira de construir o seu próprio. basicamente tem isso para tudo, exceto modificadores 😄

embora eu pudesse encontrar maneiras de criar algo que encapsulasse adequadamente minha lógica de transformação e que eu pudesse reutilizar, acho que ter uma API adequada para esses casos de uso abriria uma maneira muito mais ampla de compartilhar código comum por meio de uma coleção de "melhores modificadores de prática".

Eu vim aqui porque eu estava procurando fazer modificador para converter string para maiúscula
Eu queria criá-lo como v-model.uppercase="username"

Acabei usando a diretiva personalizada

Vue.directive('uppercase', {
    update (el) {
        el.value = el.value.toUpperCase()
    },
})

<input type="text" v-model="username" v-uppercase>

Diretivas personalizadas devem ser suficientes para uma alternativa.
Ou há algo que só é possível com o modificador de modelo v personalizado?

@Christhofernatalius considerando que v-model é simplesmente uma diretiva, você não poderia eliminar o v-model em favor da diretiva personalizada? desta forma você não está atualizando duas vezes?

@Christhofernatalius considerando que v-model é simplesmente uma diretiva, você não poderia eliminar o v-model em favor da diretiva personalizada? desta forma você não está atualizando duas vezes?

@rkingon Está atualizando duas vezes?
Portanto, se eu não usar o v-model, também preciso adicionar o gancho de ligação e desvinculação para o ouvinte de entrada e atualizar o valor do nome de usuário?

EDIT: Não está usando computado com setter e getter também atualizando duas vezes?
EDIT 2: Tentei logar no console o observador e a diretiva, cada um imprime apenas uma vez para cada pressionamento de tecla.

eu não tentei, apenas especulação - suponho que a ideia de duas diretivas para atualizar um valor seja um pouco engraçada para mim, mas se você verificou, não vejo nada de errado com isso.

minha solução de componente também tem limitações, e é por isso que ainda sou a favor de um modificador - ou seja: requer um elemento, mais tempo de renderização e funciona apenas como um componente na forma como esse componente é definido (ou seja: um campo de entrada ) vs poder simplesmente usá-lo em algum componente/elemento arbitrário que é o poder de uma diretiva.

duas maneiras de esfolar o gato, bom ter opções :)

Existe um RFC para isso?

Acho que não

Eu poderia criá-lo, mas isso significa apenas adicionar um problema nesse repositório RFC ou outra coisa?

https://github.com/vuejs/rfcs#what -the-process-is isso responde à sua pergunta?

Isso pode ser reaberto por favor? Uma diretiva personalizada pode funcionar em alguns casos, mas o comportamento pode ser engraçado, por exemplo:

Vue.directive('number', {
  update: function(el, binding, vnode) {
    el.value = el.value.replace(/[^\d.]/g, '');
  },
});

Se você adicionar esta diretiva (juntamente com um v-model) e digitar letras muito rápido a cada pressionamento de tecla, o v-model ficará fora de sincronia com el.value . E como você não pode modificar o objeto de ligação que recebe, não há como "reimplementar" o v-model dentro desta diretiva

@jeankvd Eu sei que parece um exagero, mas um componente wrapper será o mais confiável (veja o exemplo acima).

um componente wrapper permitirá que você "faça mais" também. Em seu exemplo de "número", idealmente, o v-model se torna um Number . Na sua abordagem, ainda é um String .

E se você quiser personalizar o valor vazio? Cadeia vazia? Nulo? Indefinido? -- você pode passar um prop por emptyValue e configurá-lo como tal.

Embora já tenha sido um defensor disso, percebi logo após os modificadores terem muitas limitações e apenas ter um componente é muito superior (pelo menos imo).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

bfis picture bfis  ·  3Comentários

bdedardel picture bdedardel  ·  3Comentários

franciscolourenco picture franciscolourenco  ·  3Comentários

Jokcy picture Jokcy  ·  3Comentários

loki0609 picture loki0609  ·  3Comentários