Могу ли я передать параметры в вычисляемых свойствах в Vue.Js


199

Возможно ли передать параметр в вычисляемых свойствах в Vue.Js. Я вижу, что, используя getters / setter с помощью computed, они могут взять параметр и присвоить его переменной. как здесь из документации :

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

Это также возможно:

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

Где свойство computed принимает аргумент и возвращает желаемый результат. Однако, когда я пытаюсь это сделать, я получаю эту ошибку:

vue.common.js: 2250 Uncaught TypeError: fullName не является функцией (…)

Должен ли я использовать методы для таких случаев?


5
Нет, вы не можете передавать параметры в вычисляемые свойства. Да, использование методов - самый простой способ сделать это.
ноль

Ответы:


267

Скорее всего, вы хотите использовать метод

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

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

Более длинное объяснение

Технически вы можете использовать вычисляемое свойство с таким параметром:

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

(Спасибо Unirgyза базовый код для этого.)

Разница между вычисляемым свойством и методом заключается в том, что вычисляемые свойства кэшируются и изменяются только при изменении их зависимостей. Метод будет оценивать каждый раз , когда это называется .

Если вам нужны параметры, то в таком случае обычно нет преимуществ использования вычисляемой функции свойства по сравнению с методом. Хотя это позволяет вам связать параметризованную функцию-получатель с экземпляром Vue, вы теряете кеширование, поэтому не получаете никакого усиления, фактически вы можете нарушить реактивность (AFAIU). Вы можете прочитать больше об этом в документации Vue https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

Единственная полезная ситуация - когда вам нужно использовать геттер и нужно его параметризовать. Такая ситуация происходит, например, в Vuex . в Vuex это единственный способ синхронно получить параметризованный результат из хранилища (действия асинхронные). Таким образом, этот подход указан в официальной документации Vuex для его получателей https://vuex.vuejs.org/guide/getters.html#method-style-access


1
Использование <span v-text="fullName('Hi')"></span>вместо этого также работает.
SalchiPapa

2
Проблема заключалась в том <span :text="message"></span>, что больше не работает с Vue 2.0, вместо этого нужно использовать: <span v-text="message"></span>или <span>{{ message }}</span>как показано в этом коде: codepen.io/Ismael-VC/pen/dzGzJa
SalchiPapa

1
Ты прав. Я не заметил, что это было изменено в 2.0. Спасибо за исправление!
damienix

4
Вычисляемые свойства используют синтаксис геттера ES5, который не поддерживает вызов его с какими-либо параметрами (без скобок). Так что это ограничение на уровне языка, и вот как оно включено в Vue.js.
damienix

1
Извините за очень поздний ответ @PedroMoreira, я просто нашел время, чтобы проанализировать это. На самом деле вы правы в том, что то, что я написал, было непонятным и запутанным :) Я исправил ответ и сделал все возможное, чтобы перефразировать его, чтобы сделать его более четким и точным. Вы можете дать мне знать, если теперь все ясно. Спасибо.
damienix

27

Вы можете использовать методы, но я предпочитаю по-прежнему использовать вычисляемые свойства вместо методов, если они не изменяют данные или не имеют внешних эффектов.

Вы можете передать аргументы вычисляемым свойствам следующим образом (не задокументировано, но предложено сопровождающими, не помню где):

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

РЕДАКТИРОВАТЬ: Пожалуйста, не используйте это решение, оно только усложняет код без каких-либо преимуществ.


Будет очень полезно, если вы сможете предоставить ссылку. Это должно работать.
Саурабй

@saurabh извините, это было решением не совсем описательной проблемы в github, и я не могу найти его прямо сейчас ...
Unirgy

Это работает для меня, но единственной вещью, которой я не являюсь поклонником, является тот факт, что он возвращает функцию, а не фактическое свойство, поэтому devtools VueJS нигде не показывает результаты. Я не уверен, что это типично для вычисляемых свойств, но это делает поиск неисправностей немного сложнее.
Нейт Риттер

4
Как это обрабатывает кэширование? Будет ли он работать правильно при изменении параметра?
damienix

Я не верю, что это будет что-то кэшировать внутри функции возврата. Отличие от методов будет чисто условным (методы имеют эффект, вычисляются только для извлечения)
Unirgy

8

Ну, технически говоря, мы можем передать параметр в вычисляемую функцию, точно так же, как мы можем передать параметр в функцию-получатель в vuex. Такая функция является функцией, которая возвращает функцию.

Например, в получателях магазина:

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

Этот метод получения может быть сопоставлен с вычисляемыми функциями компонента:

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

И мы можем использовать эту вычисляемую функцию в нашем шаблоне следующим образом:

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

Мы можем применить тот же подход для создания вычисляемого метода, который принимает параметр.

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

И используйте это в нашем шаблоне:

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

При этом, я не говорю здесь, что это правильный способ делать вещи с Vue.

Тем не менее, я мог заметить, что когда элемент с указанным идентификатором видоизменяется в хранилище, представление автоматически обновляет его содержимое с новыми свойствами этого элемента (привязка, кажется, работает просто отлично).


ууу, так что это сработало для меня, не используя Vuex. также хотел бы знать, если это законный способ сделать вычисляемые свойства.
yeahdixon

1
Хотя это работает, по сути, оно обрабатывает вычисляемое свойство так же, как метод. то есть он теряет преимущества кэширования вычисляемого свойства. Таким образом, нет фактического усиления, используя это по сравнению с методом. «Обратите внимание, что геттеры, к которым получают доступ через методы, будут запускаться каждый раз, когда вы их вызываете, и результат не кэшируется». См. Vuex.vuejs.org/en/getters.html
Джеймс

@ james.brndwgn, но я уверен, что методы не будут перезапущены при изменении базовых данных. Это все, что я действительно ищу.
Алекс

@ Алекс, тогда ты должен использовать наблюдателя. vuejs.org/v2/guide/computed.html#Watchers
Джеймс

@ james.brndwgn Я бы предпочел использовать вычисляемое свойство, а не наблюдателя, если это возможно. Я только оспаривал ваше утверждение: «Таким образом, при использовании этого метода нет никакой реальной выгоды». так как есть существенная разница даже без кеширования.
Алекс

4

Фильтры - это функциональность, предоставляемая компонентами Vue, которая позволяет применять форматирование и преобразования к любой части динамических данных шаблона.

Они не изменяют данные компонента или что-либо еще, но влияют только на вывод.

Скажем, вы печатаете имя:

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>

Обратите внимание на синтаксис для применения фильтра, который является | FILTERNAME. Если вы знакомы с Unix, это оператор канала Unix, который используется для передачи вывода операции в качестве ввода следующей.

Свойство filters компонента является объектом. Один фильтр - это функция, которая принимает значение и возвращает другое значение.

Возвращаемое значение - это то, которое фактически напечатано в шаблоне Vue.js.


3

Вы также можете передавать аргументы получателям, возвращая функцию. Это особенно полезно, когда вы хотите запросить массив в магазине:

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

Обратите внимание, что геттеры, к которым получают доступ через методы, будут запускаться каждый раз, когда вы их вызываете, и результат не кэшируется.

Это называется метод-Style доступ и документировано на документах Vue.js .


2

Вы можете передавать параметры, но это либо не путь vue.js, либо неправильные действия.

Однако есть случаи, когда вам нужно это сделать. Я собираюсь показать вам простой пример передачи значения в вычисляемое свойство с использованием getter и setter.

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

И сценарий

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

Когда кнопка нажата, мы передаем вычисляемому свойству имя «Роланд» и set()изменяем имя с «Джон Доу» на «Роланд».

Ниже приведен наиболее распространенный случай использования computed с getter и setter. Скажем, у вас есть следующий магазин Vuex:

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

И в вашем компоненте вы хотите добавить v-modelк входу, но с помощью магазина 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>

1

Я не совсем уверен, чего вы пытаетесь достичь, но похоже, что вы будете прекрасно использовать метод вместо вычислений!


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

когда вы хотите использовать

<p>{{fullName('your salut')}}</p>

1

Вычисляемый можно считать имеет функцию. Таким образом, для примера на valdiation вы можете сделать что-то вроде:

    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
            }
        },
        ...
    }

Что вы будете использовать, как:

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

Просто имейте в виду, что вы все равно пропустите кэширование, специфичное для computed.


0

Да, существуют методы для использования params. Как и ответы, приведенные выше, в вашем примере лучше использовать методы, так как выполнение очень легкое.

Только для справки, в ситуации, когда метод сложен и стоимость высока, вы можете кэшировать результаты следующим образом:

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

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

примечание: при использовании этого, следите за памятью, если имеете дело с тысячами

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.