0

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

I have this renderless component that uses a scoped slot:

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
    });
  }

Using it like so:

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

... so the value is not updated on change. What am I doing wrong?

4

1 回答 1

1

在模板的以下部分

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

inputValuev-slot是从组件上的而不是inputValue计算属性获得的变量<block-element>;所以如果你分配给它(这是什么v-model)它不会调用setter,它只是在模板代码中设置局部变量的值。

你可以像这样“修复”它:

<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在范围对象上有一个 setter 属性,它将正确地将更新委托给组件:

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>

现在没有关于做什么的困惑。

于 2019-05-03T00:17:21.987 回答