Vue + VUEX + 打字稿 + Vue 路由器。组件未被销毁
Vue + VUEX + Typescript + Vue Router. component not destroyed
Vue.js版本=2.3.3
向大家提问。
我有 json,其中包含一个数据列表,基于我创建表单输入的 json。表单输入绑定了一个模型,它基本上通过提交更新应用程序状态。
我有一个呈现复选框列表的组件,
在一页上我有 1 个实例,在下一页上我有组件的 3 个实例,每个实例都有自己的复选框列表和不同的名称。
从第 1 页转到第 2 页时,第 1 页的 checkbox_list 组件不会触发 destroyed 生命周期挂钩(其他组件会触发此钩子)。
在第 2 页上,我还有其他 3 个 checkbox_list 类型的组件及其名称、型号和选项。 (data
被初始化为一个函数)。
不知何故,类型复选框列表的第三个组件没有触发 created
挂钩,既没有安装也没有 w/e。它被渲染但没有和事件并且模型在那里,并且从 vue 调试器模型数组是空的。
问题是,当我在第三个组件实例(没有触发创建的生命周期挂钩的那个)中更新复选框模型(通过单击列表中的一个复选框)时,该模型包含我在第一个检查过的所有内容checkbox_list 组件实例的页面。
组件基本上是在数据被解析后循环渲染的。
有人知道为什么会这样吗?
谢谢。
请查看我的组件的以下代码。
InputTypes.ts
import Vue from 'vue';
import Component from 'vue-class-component';
import TextInput from './text/TextInput.vue';
import EmailInput from './email/EmailInput.vue';
import RadioGroup from './radio/RadioGroup.vue';
import SelectInput from './select/SelectInput.vue';
import SelectAutocompleteInput from './select/SelectAutocompleteInput.vue';
import PasswordInput from './password/PasswordInput.vue';
import CheckboxGroup from './checkbox/CheckboxGroup.vue';
import AgreementSection from './custom/AgreementSection.vue';
import CvSection from './custom/CVSection.vue';
import SubmitSection from './custom/SubmitSection.vue';
@Component({
name: 'input-types',
props: ['field', 'lastPageIndex'],
components: {
TextInput,
EmailInput,
RadioGroup,
SelectInput,
SelectAutocompleteInput,
PasswordInput,
AgreementSection,
CheckboxGroup,
CvSection,
SubmitSection
},
watch: {
'$route'($to, $from) {
let clearFields = this['clearFields'];
clearFields();
}
}
})
export default class InputsTypes extends Vue {
conditionalFields: object = {fields: []};
clearFields(): void {
this.$set(this.conditionalFields, 'fields', []);
}
changeHandler(fields): void {
this.$set(this.conditionalFields, 'fields', fields);
}
updateModelValue(data): void {
console.log(data);
}
}
InputTypes.vue
<!-- InputTypesComponent -->
<template>
<div>
<text-input v-if="field.type == 'text'" :field="field"></text-input>
<email-input v-else-if="field.type == 'email'" :field="field"></email-input>
<checkbox-group v-else-if="field.type == 'checkbox_list'" :field="field"></checkbox-group>
<radio-group v-else-if="field.type == 'radio'" :field="field" :onChange="changeHandler"></radio-group>
<select-input v-else-if="field.type == 'select'" :field="field" :onChange="changeHandler"></select-input>
<select-autocomplete-input v-else-if="field.type == 'select_autocomplete'" :field="field" :onChange="changeHandler"></select-autocomplete-input>
<password-input v-else-if="field.type == 'password'" :field="field"></password-input>
<agreement-section v-else-if="field.type == 'agreement'" :field="field"></agreement-section>
<div v-else-if="field.type == 'complex_inputs'">
<label>{{field.label}}</label>
<div v-for="option, key in field.options" :key="key">
<input-types :field="option" :onChange="changeHandler"></input-types>
</div>
</div>
<cv-section v-else-if="field.type == 'cv_section'" :field="field"></cv-section>
<submit-section v-else-if="field.type == 'next_page'" :field="field" :lastPageIndex="lastPageIndex"></submit-section>
<div v-if="conditionalFields.fields" v-for="field, key in conditionalFields.fields" :key="key">
<input-types :field="field" :onChange="changeHandler"></input-types>
</div>
</div>
</template>
<script lang="ts">
import InputsTypes from './InputsTypes.ts'
export default InputsTypes
</script>
CheckboxGroup.ts
import Vue from 'vue';
import Component from 'vue-class-component';
@Component({
name: 'checkbox-group',
props: ['field'],
watch: {
selected: (e) => {
console.log(e);
}
},
created(): void {
let predefinedSelected: Array<string> = [];
let data: object = {
'name': this.$props.field.name,
'value': predefinedSelected
};
let updateState = this['updateState'];
updateState(data);
}
})
export default class CheckboxGroup extends Vue {
updateStore(): void {
let data: object = {
'name': this.$props.field.name,
'value': this['selected']
};
this.updateState(data);
}
updateState(data): void {
this.$store.commit('SIMPLE_FIELD_UPDATE', data);
}
data(): object {
let predefinedSelected: Array<string> = this.$props.field.selected || [];
return {
selected: []
}
}
created(): void {
console.log('created');
}
mounted(): void {
console.log('mounted');
}
destroyed(): void {
console.log('destroyed');
}
}
CheckboxGroup.vue
<template>
<div class="checkbox-group">
<div class="row" v-if="field.label">
<div class="col">
{{field.label}}
</div>
</div>
<div class="row">
<div class="form-check col-3" v-for="option, key in field.options" :key="key">
<label class="form-check-label">
<input class="form-check-input" v-model="selected" @change="updateStore" type="checkbox" :name="field.name" :value="option.label"/>
{{option.label}}
</label>
</div>
</div>
</div>
</template>
<script lang="ts">
import CheckboxGroup from './CheckboxGroup.ts'
export default CheckboxGroup
</script>
这是一个可变组件的好地方,允许您拥有可以根据数据在 运行 时间更改形式的组件。
因此您需要将复合类型添加到它们自己的组件中,然后您只需使用
而不是聚合组件 input-types
<component :is="field.type" :field="field"></component>
无论你在哪里使用
<input-types :field="field"></input-types>
您需要确保您的 field.type 与您的组件标签匹配。所以对于 text-input
组件 field.type 将需要 text-input
.
如果您需要任何帮助,请告诉我。
这是一个相当庞大的 description/set 代码,试图 read/understand 真正的问题是什么。我可能会建议将来尝试尽可能简单的 description/situation。
我认为您问题的根源可能与 v-for 和 v-if 在同一元素上的交互有关。 v-if 语句将重新评估该 v-for 元素上的每个循环。最简单的答案是改为在 <template>
元素上执行你的 v-if,就在你想要 v-for 到 运行 的元素之上。
问题轻松解决。问题是我正在根据 url 更改视图并呈现不同的组件,但其中一些组件在视图中持久存在,因此 Vue 认为这些组件与之前视图中所需的组件相同。为了解决这个问题,我只是将 key
传递给 Page 组件,因此在这种情况下,它被视为一个不同的组件,并且 Page 组件内部没有浅层比较。
结论:别忘了你们的钥匙男男女女。
Vue.js版本=2.3.3
向大家提问。 我有 json,其中包含一个数据列表,基于我创建表单输入的 json。表单输入绑定了一个模型,它基本上通过提交更新应用程序状态。
我有一个呈现复选框列表的组件, 在一页上我有 1 个实例,在下一页上我有组件的 3 个实例,每个实例都有自己的复选框列表和不同的名称。
从第 1 页转到第 2 页时,第 1 页的 checkbox_list 组件不会触发 destroyed 生命周期挂钩(其他组件会触发此钩子)。
在第 2 页上,我还有其他 3 个 checkbox_list 类型的组件及其名称、型号和选项。 (data
被初始化为一个函数)。
不知何故,类型复选框列表的第三个组件没有触发 created
挂钩,既没有安装也没有 w/e。它被渲染但没有和事件并且模型在那里,并且从 vue 调试器模型数组是空的。
问题是,当我在第三个组件实例(没有触发创建的生命周期挂钩的那个)中更新复选框模型(通过单击列表中的一个复选框)时,该模型包含我在第一个检查过的所有内容checkbox_list 组件实例的页面。
组件基本上是在数据被解析后循环渲染的。 有人知道为什么会这样吗? 谢谢。
请查看我的组件的以下代码。
InputTypes.ts
import Vue from 'vue';
import Component from 'vue-class-component';
import TextInput from './text/TextInput.vue';
import EmailInput from './email/EmailInput.vue';
import RadioGroup from './radio/RadioGroup.vue';
import SelectInput from './select/SelectInput.vue';
import SelectAutocompleteInput from './select/SelectAutocompleteInput.vue';
import PasswordInput from './password/PasswordInput.vue';
import CheckboxGroup from './checkbox/CheckboxGroup.vue';
import AgreementSection from './custom/AgreementSection.vue';
import CvSection from './custom/CVSection.vue';
import SubmitSection from './custom/SubmitSection.vue';
@Component({
name: 'input-types',
props: ['field', 'lastPageIndex'],
components: {
TextInput,
EmailInput,
RadioGroup,
SelectInput,
SelectAutocompleteInput,
PasswordInput,
AgreementSection,
CheckboxGroup,
CvSection,
SubmitSection
},
watch: {
'$route'($to, $from) {
let clearFields = this['clearFields'];
clearFields();
}
}
})
export default class InputsTypes extends Vue {
conditionalFields: object = {fields: []};
clearFields(): void {
this.$set(this.conditionalFields, 'fields', []);
}
changeHandler(fields): void {
this.$set(this.conditionalFields, 'fields', fields);
}
updateModelValue(data): void {
console.log(data);
}
}
InputTypes.vue
<!-- InputTypesComponent -->
<template>
<div>
<text-input v-if="field.type == 'text'" :field="field"></text-input>
<email-input v-else-if="field.type == 'email'" :field="field"></email-input>
<checkbox-group v-else-if="field.type == 'checkbox_list'" :field="field"></checkbox-group>
<radio-group v-else-if="field.type == 'radio'" :field="field" :onChange="changeHandler"></radio-group>
<select-input v-else-if="field.type == 'select'" :field="field" :onChange="changeHandler"></select-input>
<select-autocomplete-input v-else-if="field.type == 'select_autocomplete'" :field="field" :onChange="changeHandler"></select-autocomplete-input>
<password-input v-else-if="field.type == 'password'" :field="field"></password-input>
<agreement-section v-else-if="field.type == 'agreement'" :field="field"></agreement-section>
<div v-else-if="field.type == 'complex_inputs'">
<label>{{field.label}}</label>
<div v-for="option, key in field.options" :key="key">
<input-types :field="option" :onChange="changeHandler"></input-types>
</div>
</div>
<cv-section v-else-if="field.type == 'cv_section'" :field="field"></cv-section>
<submit-section v-else-if="field.type == 'next_page'" :field="field" :lastPageIndex="lastPageIndex"></submit-section>
<div v-if="conditionalFields.fields" v-for="field, key in conditionalFields.fields" :key="key">
<input-types :field="field" :onChange="changeHandler"></input-types>
</div>
</div>
</template>
<script lang="ts">
import InputsTypes from './InputsTypes.ts'
export default InputsTypes
</script>
CheckboxGroup.ts
import Vue from 'vue';
import Component from 'vue-class-component';
@Component({
name: 'checkbox-group',
props: ['field'],
watch: {
selected: (e) => {
console.log(e);
}
},
created(): void {
let predefinedSelected: Array<string> = [];
let data: object = {
'name': this.$props.field.name,
'value': predefinedSelected
};
let updateState = this['updateState'];
updateState(data);
}
})
export default class CheckboxGroup extends Vue {
updateStore(): void {
let data: object = {
'name': this.$props.field.name,
'value': this['selected']
};
this.updateState(data);
}
updateState(data): void {
this.$store.commit('SIMPLE_FIELD_UPDATE', data);
}
data(): object {
let predefinedSelected: Array<string> = this.$props.field.selected || [];
return {
selected: []
}
}
created(): void {
console.log('created');
}
mounted(): void {
console.log('mounted');
}
destroyed(): void {
console.log('destroyed');
}
}
CheckboxGroup.vue
<template>
<div class="checkbox-group">
<div class="row" v-if="field.label">
<div class="col">
{{field.label}}
</div>
</div>
<div class="row">
<div class="form-check col-3" v-for="option, key in field.options" :key="key">
<label class="form-check-label">
<input class="form-check-input" v-model="selected" @change="updateStore" type="checkbox" :name="field.name" :value="option.label"/>
{{option.label}}
</label>
</div>
</div>
</div>
</template>
<script lang="ts">
import CheckboxGroup from './CheckboxGroup.ts'
export default CheckboxGroup
</script>
这是一个可变组件的好地方,允许您拥有可以根据数据在 运行 时间更改形式的组件。
因此您需要将复合类型添加到它们自己的组件中,然后您只需使用
而不是聚合组件input-types
<component :is="field.type" :field="field"></component>
无论你在哪里使用
<input-types :field="field"></input-types>
您需要确保您的 field.type 与您的组件标签匹配。所以对于 text-input
组件 field.type 将需要 text-input
.
如果您需要任何帮助,请告诉我。
这是一个相当庞大的 description/set 代码,试图 read/understand 真正的问题是什么。我可能会建议将来尝试尽可能简单的 description/situation。
我认为您问题的根源可能与 v-for 和 v-if 在同一元素上的交互有关。 v-if 语句将重新评估该 v-for 元素上的每个循环。最简单的答案是改为在 <template>
元素上执行你的 v-if,就在你想要 v-for 到 运行 的元素之上。
问题轻松解决。问题是我正在根据 url 更改视图并呈现不同的组件,但其中一些组件在视图中持久存在,因此 Vue 认为这些组件与之前视图中所需的组件相同。为了解决这个问题,我只是将 key
传递给 Page 组件,因此在这种情况下,它被视为一个不同的组件,并且 Page 组件内部没有浅层比较。
结论:别忘了你们的钥匙男男女女。