Posso passar parâmetros nas propriedades calculadas no Vue.Js

199

é possível passar parâmetro nas propriedades calculadas no Vue.Js. Eu posso ver quando tendo getters / setter usando computados, eles podem pegar um parâmetro e atribuí-lo a uma variável. como aqui da documentação :

// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

Isso também é possível:

// ...
computed: {
  fullName: function (salut) {
      return salut + ' ' + this.firstName + ' ' + this.lastName    
  }
}
// ...

Onde a propriedade computada pega um argumento e retorna a saída desejada. No entanto, quando tento isso, estou recebendo este erro:

vue.common.js: 2250 TypeError não capturado: fullName não é uma função (…)

Devo usar métodos para esses casos?

Saurabh
fonte
5
Não, você não pode passar parâmetros para propriedades calculadas. Sim, usar métodos é a maneira mais fácil de fazer isso.
Nils

Respostas:

266

Provavelmente você deseja usar um método

<span>{{ fullName('Hi') }}</span>

methods: {
  fullName(salut) {
      return `${salut} ${this.firstName} ${this.lastName}`
  }
}

Explicação mais longa

Tecnicamente, você pode usar uma propriedade computada com um parâmetro como este:

computed: {
   fullName() {
      return salut => `${salut} ${this.firstName} ${this.lastName}`
   }
}

(Obrigado Unirgypelo código base para isso.)

A diferença entre uma propriedade calculada e um método é que as propriedades calculadas são armazenadas em cache e mudam apenas quando suas dependências mudam. Um método avaliará toda vez que for chamado .

Se você precisar de parâmetros, geralmente não há benefícios em usar uma função de propriedade computada sobre um método nesse caso. Embora ele permita que você tenha a função getter parametrizada vinculada à instância do Vue, você perde o cache, portanto não há realmente nenhum ganho lá; na verdade, você pode interromper a reatividade (AFAIU). Você pode ler mais sobre isso na documentação do Vue https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

A única situação útil é quando você precisa usar um getter e precisa parametrizá-lo. Essa situação ocorre, por exemplo, no Vuex . no Vuex, é a única maneira de obter resultados parametrizados de forma síncrona da loja (as ações são assíncronas). Portanto, essa abordagem é listada na documentação oficial da Vuex para seus getters https://vuex.vuejs.org/guide/getters.html#method-style-access

damienix
fonte
1
Usando em <span v-text="fullName('Hi')"></span>vez disso, também funciona.
SalchiPapa
2
A questão era que <span :text="message"></span>, já não trabalha para Vue 2.0, tem de se usar em vez disso: <span v-text="message"></span>ou <span>{{ message }}</span>como mostrado neste codepen: codepen.io/Ismael-VC/pen/dzGzJa
salchipapa
1
Você está certo. Não notei que isso foi alterado no 2.0. Obrigado pela correção!
Damienix 7/08
4
As propriedades computadas usam a sintaxe getter ES5, que não suporta a chamada com nenhum parâmetro (não há parênteses). Portanto, é uma limitação no nível do idioma e é assim que é incorporada ao Vue.js.
21418 damienix
1
Desculpe por uma resposta muito tardia @PedroMoreira, encontrei um tempo para analisar isso. Na verdade, você está certo de que o que eu escrevi não era claro e confuso :) Corrigi a resposta e fiz o possível para reformulá-la para torná-la mais clara e precisa. Você pode me avisar se estiver claro agora. Obrigado.
damienix
27

Você pode usar métodos, mas eu prefiro ainda usar propriedades computadas em vez de métodos, se eles não estiverem alterando dados ou não tiverem efeitos externos.

Você pode passar argumentos para propriedades computadas dessa maneira (não documentada, mas sugerida pelos mantenedores, não se lembra onde):

computed: {
   fullName: function () {
      var vm = this;
      return function (salut) {
          return salut + ' ' + vm.firstName + ' ' + vm.lastName;  
      };
   }
}

EDIT: Por favor, não use esta solução, ela apenas complica o código sem nenhum benefício.

Unirgy
fonte
Será realmente útil se você puder fornecer uma referência. Isso deve funcionar.
precisa saber é
@saurabh triste, isso foi uma solução para um problema não muito descritivo em github, e eu não posso encontrá-lo agora ...
Unirgy
Isso funciona para mim, mas a única coisa de que não sou fã é o fato de que ela retorna uma função e não a propriedade real, portanto, as devtools do VueJS não mostram os resultados em nenhum lugar. Não tenho certeza se isso é típico para propriedades calculadas, mas torna a solução de problemas um pouco mais difícil.
Node Ritter #
4
Como ele lida com o cache? Funcionará corretamente quando o parâmetro for alterado?
damienix
Eu não acredito que ele armazenaria em cache qualquer coisa dentro da função de retorno. A diferença de métodos seria puramente de convenção (métodos têm efeito, calculado são apenas para recuperação)
Unirgy
8

Bem, tecnicamente falando, podemos passar um parâmetro para uma função computada, da mesma forma que podemos passar um parâmetro para uma função getter no vuex. Essa função é uma função que retorna uma função.

Por exemplo, nos getters de uma loja:

{
  itemById: function(state) {
    return (id) => state.itemPool[id];
  }
}

Esse getter pode ser mapeado para as funções computadas de um componente:

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ])
}

E podemos usar essa função computada em nosso modelo da seguinte maneira:

<div v-for="id in ids" :key="id">{{itemById(id).description}}</div>

Podemos aplicar a mesma abordagem para criar um método calculado que aceita um parâmetro.

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ]),
  descriptionById: function() {
    return (id) => this.itemById(id).description;
  }
}

E use-o em nosso modelo:

<div v-for="id in ids" :key="id">{{descriptionById(id)}}</div>

Dito isto, não estou dizendo aqui que é a maneira certa de fazer as coisas com o Vue.

No entanto, pude observar que, quando o item com o ID especificado é modificado na loja, a exibição atualiza seu conteúdo automaticamente com as novas propriedades desse item (a ligação parece estar funcionando perfeitamente).

Stéphane Appercel
fonte
uau, então isso funcionou para mim, não usando vuex. também gostaria de saber se essa é uma maneira legítima de executar propriedades calculadas.
yeahdixon
1
Enquanto isso funciona, trata essencialmente a propriedade calculada da mesma forma que um método. isto é, perde os benefícios de cache de uma propriedade computada. Portanto, não há ganho real usando isso sobre um método. "Observe que os getters acessados ​​por métodos serão executados toda vez que você os chamar, e o resultado não será armazenado em cache." Veja vuex.vuejs.org/en/getters.html
James
@ james.brndwgn, mas tenho certeza de que os métodos não serão executados novamente quando os dados subjacentes forem alterados. É tudo o que estou procurando.
24418 Alex
@ Alex, você deve usar um observador. vuejs.org/v2/guide/computed.html#Watchers
James
@ james.brndwgn Eu prefiro usar uma propriedade computada do que um observador, se possível. Eu estava apenas contestando sua afirmação: "Portanto, não há ganho real usando isso em um método". pois há uma diferença significativa mesmo sem o armazenamento em cache.
26618 Alex
4

Filtros são uma funcionalidade fornecida pelos componentes do Vue que permitem aplicar formatação e transformações a qualquer parte dos dados dinâmicos do modelo.

Eles não alteram os dados de um componente nem nada, mas afetam apenas a saída.

Digamos que você esteja imprimindo um nome:

new Vue({
  el: '#container',
  data() {
    return {
      name: 'Maria',
      lastname: 'Silva'
    }
  },
  filters: {
    prepend: (name, lastname, prefix) => {
      return `${prefix} ${name} ${lastname}`
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="container">
  <p>{{ name, lastname | prepend('Hello') }}!</p>
</div>

Observe a sintaxe para aplicar um filtro, que é | filterName. Se você conhece o Unix, esse é o operador de canal Unix, usado para passar a saída de uma operação como entrada para a próxima.

A propriedade de filtros do componente é um objeto. Um único filtro é uma função que aceita um valor e retorna outro valor.

O valor retornado é o que realmente é impresso no modelo Vue.js.

Diego Pereira
fonte
3

Você também pode passar argumentos para getters retornando uma função. Isso é particularmente útil quando você deseja consultar uma matriz na loja:

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

Observe que os getters acessados ​​por métodos serão executados toda vez que você os chamar, e o resultado não será armazenado em cache.

Isso é chamado de Método-Style acesso e está documentado nos docs Vue.js .

Vinicius Brasil
fonte
2

Você pode passar parâmetros, mas não é o caminho do vue.js ou está errado.

No entanto, há casos em que você precisa fazer isso. Vou mostrar um exemplo simples de passagem de valor para a propriedade computada usando getter e setter.

<template>
    <div>
        Your name is {{get_name}} <!-- John Doe at the beginning -->
        <button @click="name = 'Roland'">Change it</button>
    </div>
</template>

E o roteiro

export default {
    data: () => ({
        name: 'John Doe'
    }),
    computed:{
        get_name: {
            get () {
                return this.name
            },
            set (new_name) {
                this.name = new_name
            }
        },
    }    
}

Quando o botão clicou, estamos passando para a propriedade computada o nome 'Roland' e em set() alterando o nome de 'John Doe' para 'Roland'.

Abaixo, há um caso de uso comum quando calculado é usado com getter e setter. Digamos que você tenha a seguinte loja vuex:

export default new Vuex.Store({
  state: {
    name: 'John Doe'
  },
  getters: {
    get_name: state => state.name
  },
  mutations: {
    set_name: (state, payload) => state.name = payload
  },
})

E no seu componente você deseja adicionar v-modela uma entrada, mas usando a loja vuex.

<template>
    <div>
        <input type="text" v-model="get_name">
        {{get_name}}
    </div>
</template>
<script>
export default {
    computed:{
        get_name: {
            get () {
                return this.$store.getters.get_name
            },
            set (new_name) {
                this.$store.commit('set_name', new_name)
            }
        },
    }    
}
</script>
roli roli
fonte
1

Não tenho certeza do que você está tentando alcançar, mas parece que você ficará perfeitamente bem usando o método, em vez de computado!

Marek Urbanowicz
fonte
1
computed: {
  fullName: (app)=> (salut)=> {
      return salut + ' ' + this.firstName + ' ' + this.lastName    
  }
}

quando você quer usar

<p>{{fullName('your salut')}}</p>
Khalid Hasan
fonte
1

Computado pode ser considerado tem uma função. Portanto, para um exemplo de validação, você poderia claramente fazer algo como:

    methods: {
        validation(attr){
            switch(attr) {
                case 'email':
                    const re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
                    return re.test(this.form.email);
                case 'password':
                    return this.form.password.length > 4
            }
        },
        ...
    }

Que você usará como:

  <b-form-input
            id="email"
            v-model="form.email"
            type="email"
            :state="validation('email')"
            required
            placeholder="Enter email"
    ></b-form-input>

Lembre-se de que você ainda perderá o cache específico do computado.

Baldráni
fonte
0

Sim, existem métodos para usar parâmetros. Como as respostas acima, no seu exemplo, é melhor usar métodos, pois a execução é muito leve.

Apenas para referência, em uma situação em que o método é complexo e o custo é alto, você pode armazenar em cache os resultados da seguinte forma:

data() {
    return {
        fullNameCache:{}
    };
}

methods: {
    fullName(salut) {
        if (!this.fullNameCache[salut]) {
            this.fullNameCache[salut] = salut + ' ' + this.firstName + ' ' + this.lastName;
        }
        return this.fullNameCache[salut];
    }
}

nota: ao usar isso, observe a memória se estiver lidando com milhares

Isometriq
fonte