Vue + VueX + Typescript + Vue 路由器。组件未销毁

Posted

技术标签:

【中文标题】Vue + VueX + Typescript + Vue 路由器。组件未销毁【英文标题】:Vue + VUEX + Typescript + Vue Router. component not destroyed 【发布时间】:2017-10-26 11:55:14 【问题描述】:

Vue.js 版本 = 2.3.3

向大家提问。 我有一个包含数据列表的 json,基于我创建表单输入的 json。表单输入绑定了一个模型,它基本上通过提交更新应用程序状态。

我有一个呈现复选框列表的组件, 在一个页面上,我有 1 个实例,在下一个页面上,我有 3 个组件实例,每个实例都有自己的复选框列表和不同的名称。

当从第 1 页转到第 2 页时,第 1 页的 checkbox_list 组件不会触发被销毁的生命周期钩子(其他组件会触发此钩子)。

在第 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>

【问题讨论】:

【参考方案1】:

这是一个可变组件的好地方,允许您拥有可以在运行时根据数据更改形式的组件。

因此,您需要将复合类型添加到它们自己的组件中,而不是您刚刚使用的聚合组件 input-types

<component :is="field.type" :field="field"></component>

无论你在哪里使用

<input-types :field="field"></input-types>

您需要确保您的 field.type 与您的组件标签匹配。所以对于 text-input 组件 field.type 将需要为 text-input

如果您需要任何帮助,请告诉我。

【讨论】:

这确实是一个好建议,但这并不能真正解决我面临的问题:(【参考方案2】:

这是一个非常庞大的描述/一组代码,试图阅读/理解真正的问题是什么。我可能会建议将来尝试尽可能简单的描述/情况。

我相信您的问题的根源可能与 v-for 和 v-if 在同一元素上的交互有关。 v-if 语句将重新评估该 v-for 元素上的每个循环。最简单的答案是改为在您希望 v-for 运行的东西上方的 &lt;template&gt; 元素上执行 v-if。

https://vuejs.org/v2/guide/list.html#v-for-with-v-if

【讨论】:

【参考方案3】:

问题很容易解决。问题是我正在根据 url 更改视图,并渲染不同的组件,但其中一些在视图中是持久的,因此 Vue 认为这些组件与之前视图中需要的组件相同。为了解决这个问题,我只是将key 传递给 Page 组件,因此在这种情况下,它被视为不同的组件,并且在 Page 组件内部没有浅层比较。

结论:别忘了你们是男男女女的钥匙。

【讨论】:

以上是关于Vue + VueX + Typescript + Vue 路由器。组件未销毁的主要内容,如果未能解决你的问题,请参考以下文章

如何在单独的非 Vue 组件、JavaScript/TypeScript 文件中访问 Vuex 状态?

在 Vue 3 中使用 Vuex 4 模块和 TypeScript,以及如何修复循环依赖 linting 错误?

Vue3.x 从零开始—— Router + Vuex + TypeScript 实战演练(上)

问:使用 Vue 3 和 typescript(使用 cli 构建的项目)使 vuex 存储在全球范围内可用 +已解决

vue3不要再使用vuex

vue + ts Vuex篇