代码之家  ›  专栏  ›  技术社区  ›  eozzy

无渲染组件中的v模型

  •  0
  • eozzy  · 技术社区  · 6 年前

    代码沙盒: 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 回复  |  直到 6 年前
        1
  •  1
  •   Decade Moon    6 年前

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

    inputValue 是从 v-slot 而不是 上的计算属性 <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>
    

    但这只是混乱和打破抽象你试图创建。

    另一种方法是有一个 作用域对象上的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>
    

    但这也不理想,因为scope对象通常是不可写的,并且需要记录这个特定的实现细节。

    在这样的情况下,如果希望一个作用域插槽将数据传递回父组件,可以通过向该插槽传递回调函数来实现这一点。您可以提供一个函数来设置 输入值 但是你不能用 V-模型

    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>
    

    现在不必再为该做什么而困惑了。