简体   繁体   English

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

[英]Vue + VUEX + Typescript + Vue Router. component not destroyed

Vue.js version = 2.3.3 Vue.js 版本 = 2.3.3

Question to everybody.向大家提问。 I have json which contains a list of data, based on the json I create form inputs.我有一个包含数据列表的 json,基于我创建表单输入的 json。 The form inputs have a model binded, which basically updates app state trough commits.表单输入绑定了一个模型,它基本上通过提交更新应用程序状态。

I have a component which renders a list of checkboxes, On one page I have 1 instance and on the next one I have 3 instances of the component, each of them have their list of checkboxes, and a different name.我有一个呈现复选框列表的组件,在一个页面上我有 1 个实例,在下一个页面上我有 3 个组件实例,每个实例都有其复选框列表和不同的名称。

When going from page 1 to page 2, the checkbox_list component from page 1 doesn't fire the destroyed lifecycle hook (other components do fire this).从第 1 页转到第 2 页时,第 1 页的 checkbox_list 组件不会触发被销毁的生命周期挂钩(其他组件会触发此挂钩)。

On page 2 I have 3 other components of type checkbox_list with their name, model and options.在第 2 页上,我还有 3 个 checkbox_list 类型的其他组件及其名称、型号和选项。 ( data is initialized as a function). data被初始化为一个函数)。 Somehow the third component of type checkbox list doesn't fire the created hook, neither mounted or w/e.不知何故,复选框列表类型的第三个组件不会触发created的钩子,既没有安装也没有 w/e。 It is rendered but doesn't and events and the model is there, and from vue debugger the model array is empty.它被渲染但没有事件和模型在那里,并且从 vue 调试器中模型数组是空的。 The problem is that when I update checkbox model (by clicking on one of the checkboxes from the list) in the 3rd component instance (the one which didn't fire the created lifecycle hook) the model contains everything I've checked on the first page of the checkbox_list component instance.问题是,当我在第三个组件实例(未触发创建的生命周期挂钩的那个)中更新复选框模型(通过单击列表中的一个复选框)时,模型包含我在第一个检查过的所有内容checkbox_list 组件实例的页面。

The components are basically rendered in a loop as of the data is parsed.在解析数据时,组件基本上在循环中呈现。 Anybody any ideas why does this happen?有人知道为什么会这样吗? Thanks.谢谢。

Please see bellow code of my components.请参阅我的组件的以下代码。 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>

This is a great spot for a mutable component, allowing you to have components that can change form at run time based on data.这是可变组件的好地方,允许您拥有可以在运行时根据数据更改形式的组件。

So you'll want to add your composite types to their own components and then instead of the conglomeration component input-types you just use因此,您需要将复合类型添加到它们自己的组件中,而不是您刚刚使用的聚合组件input-types

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

wherever you'd use无论您在哪里使用

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

You will need to make sure that your field.type matches your component labels.您需要确保您的 field.type 与您的组件标签匹配。 so for a text-input component field.type will need to be text-input .所以对于text-input组件 field.type 将需要是text-input

If you need any help let me know.如果您需要任何帮助,请告诉我。

That is a pretty huge description/set of code to try to read/understand what the real problem is.这是一个非常庞大的描述/代码集,试图阅读/理解真正的问题是什么。 I might suggest trying as simple of a description/situation as possible in the future.我可能会建议将来尝试尽可能简单的描述/情况。

I believe what the source of your issue may be has to do with the interaction of v-for and v-if on the same element.我相信您的问题的根源可能与 v-for 和 v-if 在同一元素上的交互有关。 The v-if statement is going to re-evaluate for each loop on that v-for element. v-if 语句将重新评估该 v-for 元素上的每个循环。 Simplest answer is to instead do your v-if on a <template> element just above the thing you want the v-for to run on.最简单的答案是改为在<template>元素上执行您的 v-if,就在您希望 v-for 运行的东西上方。

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

The problem was solved easily.问题很容易解决。 The problem was that I was changing the views based on an url, and rendering different components, but some of them were persistent in the view so Vue considered those are the same components that were needed in previous view.问题是我正在根据 url 更改视图,并渲染不同的组件,但其中一些在视图中是持久的,因此 Vue 认为这些组件与之前视图中需要的组件相同。 To solve this I just passed a key to the Page component, so in this situation it is treated as a different component and there is no shallow comparison inside the Page component.为了解决这个问题,我只是将一个key传递给 Page 组件,因此在这种情况下,它被视为不同的组件,并且在 Page 组件内部没有浅层比较。

Conclusion : Don't forget you keys guys and girls.结论:不要忘记你的关键男孩和女孩。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM