如何在用户单击提交按钮之前推迟表单输入绑定?

时间:2017-07-12 13:03:33

标签: vue.js vuejs2

我想在Vue.js 2.3中对我的表单输入进行双向数据绑定。但是,我不能使用v-model指令,因为我希望仅在单击提交按钮时才更新数据。同时,输入值可以从另一个Vue方法更新,因此它应该绑定到数据属性text。我编造了类似jsFiddle的内容:

<div id="demo">
  <input :value="text" ref="input">
  <button @click="update">OK</button>
  <p id="result">{{text}}</p>
</div>
new Vue({
  el: '#demo',
  data: function() {
    return {
      text: ''
    };
  },
  methods: {
    update: function () {
        this.text = this.$refs.input.value;
    }
  }
});

它有效,但当有更多输入时它不能很好地扩展。有没有更简单的方法来实现这一点,而不使用$ refs?

3 个答案:

答案 0 :(得分:2)

您可以使用对象并将其属性绑定到输入。然后,在update方法中,您可以将属性复制到另一个对象以进行显示。然后,您可以设置深度观察器,以便在对象更改时更新输入的值。复制属性时,您需要使用this.$set,以便更改将在Vue中注册。

&#13;
&#13;
new Vue({
  el: '#demo',
  data: function() {
    return {
      inputVals: {
        text: '',
        number: 0
      },
      displayVals: {}
    };
  },
  methods: {
    update() {
      this.copyObject(this.displayVals, this.inputVals);
    },
    copyObject(toSet, toGet) {
      Object.keys(toGet).forEach((key) => {
        this.$set(toSet, key, toGet[key]);
      });
    }
  },
  watch: {
    displayVals: {
      deep: true,
      handler() {
        this.copyObject(this.inputVals, this.displayVals);
      }
    }
  }
})
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="demo">
  <input v-model="inputVals.text">
  <input v-model="inputVals.number">
  <button @click="update">OK</button>
  <input v-for="val, key in displayVals" v-model="displayVals[key]">
</div>
&#13;
&#13;
&#13;

如果你正在使用ES2015,你可以直接复制对象,所以这不是详细的:

&#13;
&#13;
new Vue({
  el: '#demo',
  data() {
    return {
      inputVals: { text: '', number: 0 },
      displayVals: {}
    };
  },
  methods: {
    update() {
      this.displayVals = {...this.inputVals};
    },
  },
  watch: {
    displayVals: {
      deep: true,
      handler() {
        this.inputVals = {...this.displayVals};
      }
    }
  }
})
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="demo">
  <input v-model="inputVals.text">
  <input v-model="inputVals.number">
  <button @click="update">OK</button>
  <input v-for="val, key in displayVals" v-model="displayVals[key]">
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以使用两个单独的数据属性,一个用于<input>的值,另一个用于单击“确定”按钮后提交的值。

<div id="demo">
  <input v-model="editText">
  <button @click="update">OK</button>
  <p id="result">{{text}}</p>
</div>
new Vue({
  el: '#demo',
  data: function() {
    return {
      editText: '',
      text: ''
    };
  },
  methods: {
    update: function () {
      this.text = this.editText;
    }
  }
});

Updated fiddle

答案 2 :(得分:1)

与其他答案略有不同,我认为你可以实现轻松扩展的方法。

这是第一次传递,但是使用组件,您可以构建自己的输入元素,并在需要时精确提交。下面是一个输入元素的示例,当它位于t-form组件之外时,它就像常规输入元素一样工作,但只在v-modelsubmit上更新t-form

Vue.component("t-input", {
  props:["value"],
  template:`
    <input type="text" v-model="internalValue" @input="onInput">
  `,
  data(){
    return {
      internalValue: this.value,
      wrapped: false
    }
  },
  watch:{
    value(newVal){
      this.internalValue = newVal
    }
  },
  methods:{
    update(){
      this.$emit('input', this.internalValue)
    },
    onInput(){
      if (!this.wrapped)
        this.$emit('input', this.internalValue)
    }
  },
  mounted(){
    if(this.$parent.isTriggeredForm){
      this.$parent.register(this)
      this.wrapped = true      
    }
  }
})

以下是t-form

的示例
Vue.component("t-form",{
  template:`
    <form @submit.prevent="submit">
      <slot></slot>
    </form>
  `,
  data(){
    return {
      isTriggeredForm: true,
      inputs:[]
    }
  },
  methods:{
    submit(){
      for(let input of this.inputs)
        input.update()
    },
    register(input){
      this.inputs.push(input)
    }
  }
})

有了这些,你的工作变得非常简单。

<t-form>
  <t-input v-model="text"></t-input><br>
  <t-input v-model="text2"></t-input><br>
  <t-input v-model="text3"></t-input><br>
  <t-input v-model="text4"></t-input><br>
  <button>Submit</button>
</t-form>

此模板仅在单击按钮时更新绑定的表达式。您可以拥有任意数量的t-inputs

这是一个工作示例。我在表单内部和外部都包含了t-input元素,因此您可以在表单内部看到模型仅在提交时更新,而在表单外部,元素的工作方式与典型输入相同。

&#13;
&#13;
console.clear()
//
Vue.component("t-input", {
  props: ["value"],
  template: `
    <input type="text" v-model="internalValue" @input="onInput">
  `,
  data() {
    return {
      internalValue: this.value,
      wrapped: false
    }
  },
  watch: {
    value(newVal) {
      this.internalValue = newVal
    }
  },
  methods: {
    update() {
      this.$emit('input', this.internalValue)
    },
    onInput() {
      if (!this.wrapped)
        this.$emit('input', this.internalValue)
    }
  },
  mounted() {
    if (this.$parent.isTriggeredForm) {
      this.$parent.register(this)
      this.wrapped = true
    }
  }
})

Vue.component("t-form", {
  template: `
    <form @submit.prevent="submit">
      <slot></slot>
    </form>
  `,
  data() {
    return {
      isTriggeredForm: true,
      inputs: []
    }
  },
  methods: {
    submit() {
      for (let input of this.inputs)
        input.update()
    },
    register(input) {
      this.inputs.push(input)
    }
  }
})


new Vue({
  el: "#app",
  data: {
    text: "bob",
    text2: "mary",
    text3: "jane",
    text4: "billy"
  },
})
&#13;
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <t-form>
    <t-input v-model="text"></t-input><br>
    <t-input v-model="text2"></t-input><br>
    <t-input v-model="text3"></t-input><br>
    <t-input v-model="text4"></t-input><br>
    <button>Submit</button>
  </t-form>
  Non-wrapped:
  <t-input v-model="text"></t-input>
  <h4>Data</h4>
  {{$data}}
  <h4>Update Data</h4>
  <button type="button" @click="text='jerome'">Change Text</button>
</div>
&#13;
&#13;
&#13;