V-модель внутри компонента без рендера - PullRequest
0 голосов
/ 03 мая 2019

CodeSandbox: https://codesandbox.io/s/61my3w7xrw?fontsize=14

У меня есть этот компонент без рендеринга, который использует область видимости:

name: "BlockElement",
  props: {
    element: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      inputValue: this.element.value
    };
  },
  render() {
    return this.$scopedSlots.default({
      inputName: this.inputName,
      inputValue: this.inputValue
    });
  }

Используя это так:

<block-element :element="element" v-slot="{ inputName, inputValue }">
  <div>
    <input type="text" :name="inputName" v-model="inputValue">
    <p>inputValue: {{ inputValue }}</p>
  </div>
</block-element>

... поэтому значение не обновляется при изменении. Что я делаю не так?

1 Ответ

1 голос
/ 03 мая 2019

В следующей части шаблона

<input type="text" :name="inputName" v-model="inputValue">

inputValue - это переменная, полученная из v-slot, а не вычисляемое свойство inputValue для компонента <block-element>;поэтому, если вы присваиваете ему (что делает v-model), он не будет вызывать сеттер, он просто устанавливает значение локальной переменной в коде шаблона.

Вы можете «исправить» этокак это:

<block-element :element="element" v-slot="{ inputName }" ref="block">
  <div>
    <input type="text" :name="inputName" v-model="$refs.block.inputValue">
    <p>inputValue: {{ $refs.block.inputValue }}</p>
  </div>
</block-element>

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

Другой способ - иметь свойство сеттера inputValue для объекта области действия, которое будет правильноделегируйте обновление компоненту:

render() {
  const self = this;
  return this.$scopedSlots.default({
    inputName: this.inputName,
    get inputValue() { return self.inputValue },
    set inputValue(value) { self.inputValue = value; },
  });
}
<block-element :element="element" v-slot="scope">
  <div>
    <input type="text" :name="scope.inputName" v-model="scope.inputValue">
    <p>inputValue: {{ scope.inputValue }}</p>
  </div>
</block-element>

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

В такой ситуации, когда вы хотите, чтобы слот с областью действия передавал данные обратно в родительский компонент, вы могли бы реализовать это, передав функцию обратного вызова в слот.Вы можете предоставить функцию для установки inputValue, но тогда вы не сможете использовать v-model:

render() {
  return this.$scopedSlots.default({
    inputName: this.inputName,
    inputValue: this.inputValue,
    setInputValue: value => this.inputValue = value,
  });
}
<block-element :element="element" v-slot="{ inputName, inputValue, setInputValue }">
  <div>
    <input type="text" :name="inputName" :value="inputValue" @input="setInputValue($event.target.value)">
    <p>inputValue: {{ inputValue }}</p>
  </div>
</block-element>

Теперь нет никаких сомнений относительно того, что делать.

...