使用 v-model 的值作为 if 语句的条件是否正确?

Is it correct to use a v-model's value as the condition of an if-statement?

如何把v-model="item.checked"作为下面validations()if的条件?

<table>
    <tr v-for="(item, i) of $v.timesheet.items.$each.$iter" >
        <div>
            <td>
                <input 
                    type="checkbox" 
                    v-model="item.checked" 
                    v-on:click="disable(i)"
                />
            </td>
            <td>
                <input 
                    type="text" 
                    :id="'total_hour-' + i"
                />
            </td>
        </div>
    </tr>
    <tr>
        <div>
            <td>
                <button 
                    type="button" 
                    class="btn btn-sm btn-primary" 
                    @click="itemCount++"
                >Add Row
                </button>
            </td>
        </div>
    </tr>
</table>

<script>
    import { required, minLength } from "vuelidate/lib/validators";
    export default {
        data() {
            return {
                itemCount: 1,
                timesheet: { items: [{ total_hour: "", checked: false }] },
            }
        },
        methods: {            
            disable(index){
                const check = 
                        document.getElementById('total_hour-' + index).disabled
                $('#total_hour-' + index).attr('disabled', !check);
            }
        },
        watch: {
            itemCount(value, oldValue) {
                if (value > oldValue) {
                    for (let i = 0; i < value - oldValue; i++) {
                        this.timesheet.items.push({
                            total_hour: "",
                            checked: false,
                        })
                    }
                } else {
                    this.timesheet.items.splice(value);
                }
            }
        },
        validations() {
            if (  ?  ) {
                return {
                    timesheet: {
                        items: {
                            required,
                            minLength: minLength(1),
                            $each: { total_hour: {required} }
                        }
                    }
                }
            } else {
                return {
                    timesheet: {
                        items: {
                            required,
                            minLength: minLength(1),
                            $each: { total_hour: {} }
                        }
                    }
                }
            }
        }
    }
</script>

所以,有几件事可以改进您的代码。

用方法替换 watcher

Watcher 很难调试并且可能会产生副作用。它们应该只在真正需要的时候使用。 相反,创建一个方法,添加一行:

addRow() {
  this.timesheet.items.push({
    total_hour: "",
    checked: false,
  })
}

要删除一行,请执行相同的操作。只需创建一个方法。

为每个条目创建一个组件

通过为时间表项目创建子组件,您可以更轻松地处理验证,并且可以更好地对单个条目的更改做出反应。

<table>
  <TimesheetItemRow
    v-for="(item) of $v.timesheet.items.$each.$iter"
    :item="item"
  />
  <tr>
    ...
  </tr>
</table>

要跟踪父组件中的所有时间表项目,您可能希望从子组件向父组件发出一个事件,其中包含新条目数据。

不要使用jQuery或JavaScript代码来操纵DOM

和以前一样,这种东西应该只在超级、超级边缘的情况下使用。像 Vue.js 这样的前端框架的好处之一是,您不需要这样做。

现在,每个条目都有一个组件,直接在模板中禁用输入就很容易了

这是时间表项目组件的一些(未经测试的)代码:

<template>
  <tr>
    <td>
      <input 
        type="checkbox" 
        value="item.checked
        @click="onClickCheckbox"
      />
    </td>

    <td>
      <input 
        type="text" 
        @input="onUpdateTotalHour"
        :disabled="!item.checked
      />
    </td>
  </tr>
</template>

<script>
  import { required } from "vuelidate/lib/validators";

  export default {
    props: {
      item: {
        type: Object
      }
    },

    methods: {
      onClickCheckbox (value) {
        this.$emit('on-click-checkbox', value)
      },

      onUpdateTotalHour (value) {
        this.$emit('on-update-total-hour', value)
      }
    },

    validations () {
      if (this.item.checked) {
        return {
          item: {
            total_hour: { required }
          }
        }
      }

      return {
        item: {
          total_hour: {}
        }
      }
    }
  }
</script>

父组件需要跟踪所有项目,并且需要对发出的事件做出反应。

据我了解,只有当 checked 为真时,您才希望 total_hour 成为必填字段。 Vuelidate 为此提供了一个很好的内置验证器 requiredIf。它是 contextified validator,因此您可以引用同级 属性。

import { required, requiredIf, minLength } from 'vuelidate/lib/validators';

export default {
  ...
  validations: {
    timesheet: {
      items: {
        required,
        minLength: minLength(1),
        $each: {
          total_hour: {
            required: requiredIf('checked'),
          },
        },
      },
    },
  },
}

我在您的代码中看到的另一个问题是您试图遍历 $v 字段。 $v 字段用于获取字段的验证状态,您不应该设置 $v 字段。将它们用作组件的 v-model 将使 vue 设置 $v 字段。试试这个:

<tr v-for="(item, i) in timesheet.items">