¿Puedo pasar parámetros en propiedades calculadas en Vue.Js

199

¿Es posible pasar parámetros en propiedades calculadas en Vue.Js. Puedo ver que cuando tienen getters / setter usando computed, pueden tomar un parámetro y asignarlo a una variable. como aquí de la documentación :

// ...
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]
    }
  }
}
// ...

¿Esto también es posible?

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

Donde la propiedad calculada toma un argumento y devuelve la salida deseada. Sin embargo, cuando intento esto, recibo este error:

vue.common.js: 2250 Tipo de error no capturado: fullName no es una función (...)

¿Debo usar métodos para tales casos?

Saurabh
fuente
55
No, no puede pasar parámetros a propiedades calculadas. Sí, usar métodos es la forma más fácil de hacerlo.
nils

Respuestas:

266

Lo más probable es que quieras usar un método

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

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

Explicación más larga

Técnicamente, puede usar una propiedad calculada con un parámetro como este:

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

(Gracias Unirgypor el código base para esto).

La diferencia entre una propiedad calculada y un método es que las propiedades calculadas se almacenan en caché y cambian solo cuando cambian sus dependencias. Un método evaluará cada vez que se llame .

Si necesita parámetros, generalmente no hay beneficios de usar una función de propiedad calculada sobre un método en tal caso. Aunque le permite tener la función getter parametrizada vinculada a la instancia de Vue, pierde el almacenamiento en caché, por lo que no hay ninguna ganancia allí, de hecho, puede romper la reactividad (AFAIU). Puede leer más sobre esto en la documentación de Vue https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

La única situación útil es cuando tienes que usar un getter y necesitas tenerlo parametrizado. Esta situación ocurre, por ejemplo, en Vuex . en Vuex es la única forma de obtener sincrónicamente resultados parametrizados de la tienda (las acciones son asíncronas). Por lo tanto, este enfoque figura en la documentación oficial de Vuex para sus captadores https://vuex.vuejs.org/guide/getters.html#method-style-access

damienix
fuente
1
Usar en su <span v-text="fullName('Hi')"></span>lugar, también funciona.
SalchiPapa
2
El problema era que <span :text="message"></span>, ya no funciona para Vue 2.0, uno tiene que usar en su lugar: <span v-text="message"></span>o <span>{{ message }}</span>como se muestra en este codepen: codepen.io/Ismael-VC/pen/dzGzJa
SalchiPapa
1
Tienes razón. No me di cuenta de que esto ha cambiado en 2.0. ¡Gracias por la corrección!
damienix
44
Las propiedades calculadas usan la sintaxis del getter ES5 que no admite la llamada con ningún parámetro (no hay paréntesis). Entonces, es una limitación de nivel de idioma y así es como se incorpora a Vue.js.
damienix
1
Perdón por una respuesta muy tardía @PedroMoreira, acabo de encontrar tiempo para analizar esto. De hecho, tiene razón en que lo que escribí no fue claro y confuso :) Arreglé la respuesta e hice todo lo posible para reformularla para que fuera más clara y precisa. Puedes decirme si está claro ahora. Gracias.
damienix
27

Puede usar métodos, pero prefiero seguir usando propiedades calculadas en lugar de métodos, si no están mutando datos o no tienen efectos externos.

Puede pasar argumentos a propiedades calculadas de esta manera (no documentado, pero sugerido por los mantenedores, no recuerdo dónde):

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

EDITAR: no utilice esta solución, solo complica el código sin ningún beneficio.

Unirgy
fuente
Será realmente útil si puede proporcionar una referencia. Esto debería funcionar.
Saurabh
@saurabh siento que era una solución para un problema no muy descriptiva en GitHub, y yo no lo encuentra en este momento ...
Unirgy
Esto funciona para mí, pero lo único de lo que no soy fanático es del hecho de que devuelve una función en lugar de la propiedad real, por lo que las herramientas de desarrollo de VueJS no muestran los resultados en ninguna parte. No estoy seguro de si eso es típico para las propiedades calculadas, pero hace que la solución de problemas sea un poco más difícil.
Nate Ritter
44
¿Cómo maneja el almacenamiento en caché? ¿Funcionará correctamente cuando cambie el parámetro?
damienix
No creo que guarde en caché nada dentro de la función de retorno. La diferencia con los métodos sería puramente convencional (los métodos tienen efecto, los
cálculos
8

Bueno, técnicamente hablando podemos pasar un parámetro a una función calculada, de la misma manera que podemos pasar un parámetro a una función getter en vuex. Tal función es una función que devuelve una función.

Por ejemplo, en los captadores de una tienda:

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

Este captador se puede asignar a las funciones calculadas de un componente:

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

Y podemos usar esta función calculada en nuestra plantilla de la siguiente manera:

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

Podemos aplicar el mismo enfoque para crear un método calculado que tome un parámetro.

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

Y úsalo en nuestra plantilla:

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

Dicho esto, no digo aquí que sea la forma correcta de hacer las cosas con Vue.

Sin embargo, pude observar que cuando el elemento con el ID especificado se muta en la tienda, la vista actualiza su contenido automáticamente con las nuevas propiedades de este elemento (el enlace parece estar funcionando bien).

Stéphane Appercel
fuente
woah así que esto funcionó para mí, no usando vuex. También me gustaría saber si esta es una forma legítima de hacer propiedades calculadas.
yeahdixon
1
Si bien esto funciona, esencialmente trata la propiedad calculada de la misma manera que un método. es decir, pierde los beneficios de almacenamiento en caché de una propiedad calculada. Por lo tanto, no hay una ganancia real al usar esto sobre un método. "Tenga en cuenta que los captadores a los que se accede mediante métodos se ejecutarán cada vez que los llame, y el resultado no se almacena en caché". Ver vuex.vuejs.org/en/getters.html
James
@ james.brndwgn, pero estoy bastante seguro de que los métodos no se volverán a ejecutar cuando se modifiquen los datos subyacentes. Eso es todo lo que realmente estoy buscando.
Alex
@Alex, entonces deberías estar usando un observador. vuejs.org/v2/guide/computed.html#Watchers
James
@ james.brndwgn Prefiero usar una propiedad calculada que un observador si es posible. Solo estaba en desacuerdo con su declaración: "Entonces, no hay una ganancia real al usar esto sobre un método". ya que hay una diferencia significativa incluso sin almacenamiento en caché.
Alex
4

Los filtros son una funcionalidad proporcionada por los componentes Vue que le permiten aplicar formato y transformaciones a cualquier parte de los datos dinámicos de su plantilla.

No cambian los datos de un componente ni nada, pero solo afectan la salida.

Digamos que está imprimiendo un nombre:

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 la sintaxis para aplicar un filtro, que es | filterName. Si está familiarizado con Unix, ese es el operador de tubería Unix, que se utiliza para pasar la salida de una operación como entrada a la siguiente.

La propiedad de filtros del componente es un objeto. Un filtro único es una función que acepta un valor y devuelve otro valor.

El valor devuelto es el que se imprime realmente en la plantilla Vue.js.

Diego Pereira
fuente
3

También puede pasar argumentos a los captadores devolviendo una función. Esto es particularmente útil cuando desea consultar una matriz en la tienda:

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

Tenga en cuenta que los captadores a los que se accede mediante métodos se ejecutarán cada vez que los llame, y el resultado no se almacena en caché.

Eso se llama Método-Estilo de acceso y se documenta en la documentación Vue.js .

Vinicius Brasil
fuente
2

Puede pasar parámetros, pero no es una forma vue.js o la forma en que lo está haciendo es incorrecta.

Sin embargo, hay casos en los que necesita hacerlo. Le mostraré un ejemplo simple de pasar el valor a la propiedad calculada usando getter y setter.

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

Y el guión

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

Cuando se hace clic en el botón, pasamos a la propiedad calculada el nombre 'Roland' y en set() estamos cambiando el nombre de 'John Doe' a 'Roland'.

A continuación hay un caso de uso común cuando se calcula con getter y setter. Digamos que tiene la siguiente tienda vuex:

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

Y en su componente desea agregar v-modela una entrada pero usando la tienda 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
fuente
1

¡No estoy completamente seguro de lo que estás tratando de lograr, pero parece que estarás perfectamente bien usando el método en lugar de calcularlo!

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

cuando quieras usar

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

Computado podría considerarse tiene una función. Entonces, para un ejemplo de valdiación, claramente podría hacer 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 usarás como:

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

Solo tenga en cuenta que aún extrañará el almacenamiento en caché específico de lo calculado.

Baldráni
fuente
0

Sí, existen métodos para usar params. Al igual que las respuestas indicadas anteriormente, en su ejemplo es mejor usar métodos ya que la ejecución es muy ligera.

Solo como referencia, en una situación en la que el método es complejo y el costo es alto, puede almacenar en caché los resultados de la siguiente manera:

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

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

nota: Al usar esto, tenga cuidado con la memoria si se trata de miles

Isometriq
fuente