使用v-model不良做法来改变道具的属性吗?

时间:2019-01-09 09:45:21

标签: vue.js vuejs2 vuex

vue.js docs相当严格,说对组件内部的props进行突变是不好的做法。此外,还描述了两种情况,在这种情况下,开发人员可能会想违反此规则:

  • 设置默认值时
  • 应更改给定的prop值。

自从vue.js开始以来,我发现自己很想使用v-model更新props属性。在网上搜索时,我发现了一些讨论,其中包括解决方法或使用vuex。

我的问题是:正在使用v-model更新道具的属性,还是不好,因为它会更改父状态。 我想改变父母的状态,考虑这个例子

Crud组件,可加载特定的“表单”组件:

<template>
    <awesome-form @formSubmit="onFormSubmit" :entity="entity"></awesome-form>
</template>

<script>
import AwesomeForm from 'SomeForm'
export default {
  data () {
    return {
      entity: {}
    }
  },
  components: {
    AwesomeForm
  },
  methods: {
    onFormSubmit () {
      axios.post('/backend', this.entity)
    }
  }
}
</script>

特定表单组件:

<template>
    <form @submit.prevent="submit">
        <input type="text" name="username" v-model="entity.username" />
        ...
    </form>
</template>
<script>
  export default {
    props: {
      entity: {
        type: Object
      }
    },
    methods: {
      submit () {
        this.$emit('formSubmit')
      }
    }
  }
</script>

这与预期的工作原理相同,并且使数据绑定超级容易。但是我猜这被认为是不好的,因为它会更新父状态。但是最终,这正是我想要的。

这真的很糟糕吗?还有哪些替代方案?

  • 每个更新和单个属性具有事件(超级冗余)
  • 始终使用vuex ...(真的吗?)

2 个答案:

答案 0 :(得分:2)

我发现您的最佳做法是使用official docs中提到的// ignore the following two lines, they just disable warnings in "Run code snippet" Vue.config.devtools = false; Vue.config.productionTip = false; Vue.component('awesome-form', { props: ['entity'], template: ` <div> <form @submit.prevent="submit"> <input type="text" class="form-control" name="username" v-model="entity.username"> <input type="email" class="form-control" name="email" v-model="entity.email"> <input type="submit" class="btn btn-primary" value="submit"/> </form> </div>`, methods: { submit() { this.$emit('form-submit') } } }) new Vue({ el: "#app", data() { return { entity: { username: '', email: '' } } }, methods: { onFormSubmit() { console.log(this.entity) } } });修饰符:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

<div id="app">
  <awesome-form @form-submit="onFormSubmit" :entity.sync="entity"></awesome-form>
  <p> {{entity}}</p>
</div>
data.table

答案 1 :(得分:2)

  

正在使用v-model OK更新道具的属性,或者因为它会更改父状态而为错误

绝对不好,因为表单道具以props的形式在顶级父级上传递。因此,即使尝试使用v-model更改子级中的值,也应该从Vue看到警告。

因此,当我看到某个表单组件时,我希望它需要一些v-model值,因为表单是关于编辑某些内容的。这是基于v-model的动态形式的示例示例:

Vue.component('awesome-form', {
  props: ['value'],
  template: `#awesome-form-template`,
  methods: {
    update(key, val) {
      // we should create new object on each change
      let updatedCopy = Object.assign({}, this.value, { [key]: val });
      this.$emit('input', updatedCopy)
    }
  },
  watch: {
    value(val) {
      console.log('value updated: ' + JSON.stringify(val))
    }
  }
})

var vm = new Vue({
  el: '#app',
  data: {
    form: {
      text1: '123',
      text2: '345'
    }
  },
  methods: {
      submit() {
         console.log('submitted!');
      }
  }
})
<script src="https://unpkg.com/vue"></script>


<div id="app">
  <awesome-form @form-submit="submit" v-model="form"></awesome-form>
</div>


<script type="text/x-template" id='awesome-form-template'>
  <form @submit.prevent="$emit('form-submit')">
	    <div v-for="(val, key) in value" :key="key">
          <input 
          type="text" 
          :value="value[key]" 
          @input="update(key, $event.target.value)"
          :name="key">
      </div>
      <button type='submit'>Submit</button>
   </form>
</script>

  

对于每个更新和单个属性都具有事件(超级冗余)

但是,如果您需要添加一些特定于每个输入的验证逻辑,则必须为每次更新或类似操作定义事件。

您还可以使用自定义mixin jsfiddle从问题评论(@BoussadjraBrahim)中基于sync修饰符检查解决方案,它可以根据您的情况进行灵活调整。