无渲染组件内部的v模型

时间:2019-05-02 23:58:23

标签: vue.js v-model renderless-component scoped-slot

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 个答案:

答案 0 :(得分:1)

在模板的以下部分

<androidx.cardview.widget.CardView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:id="@+id/staggered_feed_image_card"
        app:cardCornerRadius="16dp"
        app:cardElevation="0dp">
    <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:srcCompat="@drawable/no_dread"
            android:id="@+id/staggered_feed_image"
            android:scaleType="centerCrop"/>
    </RelativeLayout>
</androidx.cardview.widget.CardView>

<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> setter属性,该属性会将更新正确地委派给组件:

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

现在对做什么没有任何困惑。