【问题标题】:v-model inside a renderless component无渲染组件中的 v-model
【发布时间】:2019-09-21 12:27:39
【问题描述】:

代码沙盒: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>

...所以值不会在更改时更新。我做错了什么?

【问题讨论】:

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


    【解决方案1】:

    在模板的以下部分

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

    inputValue 是从v-slot 获得的变量,而不是&lt;block-element&gt; 组件上的inputValue 计算属性;所以如果你给它赋值(这是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>
    

    现在对做什么没有困惑。

    【讨论】:

    • 哦,好的,所以问题是输入在template 内?如果它直接在block-element 内,v-model 会起作用吗?
    • 是的,因为它将直接引用inputValue 计算属性。
    猜你喜欢
    • 2021-04-05
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2019-02-14
    • 2018-08-25
    • 2018-12-03
    • 2018-02-08
    • 2019-12-28
    相关资源
    最近更新 更多