使用 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">
如何把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">