当我在 Vue JS 中按下父组件上的按钮时如何刷新子组件?

Posted

技术标签:

【中文标题】当我在 Vue JS 中按下父组件上的按钮时如何刷新子组件?【英文标题】:How to refresh Child component when i pressed a button on Parent Component in Vue JS? 【发布时间】:2018-03-06 04:46:13 【问题描述】:

我有一个设置选项,它将从父组件更新。我将这些设置数据保存在 localStorage 中,这三个子组件正在使用设置数据。

<P>
  <c1> </c1>
  <c2> </c2>
  <c3> </c3>
</P>

我想要一种方式,当我更新我的设置数据时,三个组件将刷新或更新以获得新值。 就像,我将按下父组件上的一个按钮,三个子组件将被更新。

------------ 已更新 ---------- --------

模板部分:

<template>
  <div class="main-content">
   <div class="main">

<!-- COMPONENT -->
<div class="row">
   <div class="padpad">
      <div class="col-md-6">
         <app-colma></app-colma>
      </div>
      <div class="col-md-3">
         <app-colmb></app-colmb>
      </div>
 
   </div>
</div>

<!-- SAVE BUTTON -->

          <button type="submit" class="btn btn-success" data-dismiss="modal" aria-label="Close" v-on:click="onSubmit()"><span>Save</span></button>
          
          
              
<!-- DATA FORM ( SELECT, OPTION) -->
               <div class="container modal-body">

                  <div class="col-xs-12 col-md-3">
                     <h4>Sortierung</h4>

                     <div class="radio">
                       <label><input value="theropeut" type="radio" name="filterop">Theropeut</label>
                     </div>
                     <div class="radio">
                       <label><input value="ausl_perf" type="radio" name="filterop">Ausl Perf</label>
                     </div>
                     <div class="radio">
                       <label><input value="ausl_bud" type="radio" name="filterop">Ausl Bud</label>
                     </div>
                     <div class="radio">
                       <label><input value="umsatz" type="radio" name="filterop">Umsatz</label>
                     </div>

                     <div class="order-select">
                        <select id="orderid" class="form-control">
                           <option value="ascending">Ascending</option>
                           <option value="descending">Descending</option>
                        </select>
                     </div>
                  </div>
   </div>
</div>
</template>

脚本代码:

<script>
import ColmA from './ColmA.vue';
import ColmB from './ColmB.vue';
import ColmTotal from './ColmTotal.vue';
export default 
  components: 
    'app-colma': ColmA,
    'app-colmb': ColmB,
    'app-colmtotal': ColmTotal
  ,
	name: 'main-content',
	data() 
		return 
			users: [],
      filtr:'',
			order:''
		
	,
	methods: 
    onSubmit: function()
      // console.log("onsubmit");

      //filter
      var filterop = document.getElementsByName('filterop');

      for (var i = 0, length = filterop.length; i < length; i++) 
          if (filterop[i].checked) 
              // do whatever you want with the checked radio
              // alert(filterop[i].value);
              this.filtr = filterop[i].value;
              // only one radio can be logically checked, don't check the rest
              break;
          
      
      //order
      var e = document.getElementById("orderid");
      this.order = e.options[e.selectedIndex].value;

      var homesetting = 
          filter: this.filtr,
          order:this.order,
      ;



      if (localStorage.getItem('homesetting') === null) 
        var  homesettings = [];

        // homesettings.push(homesetting);
        localStorage.setItem('homesetting', JSON.stringify(homesetting));
       else 
        localStorage.removeItem('homesetting');
        localStorage.setItem('homesetting', JSON.stringify(homesetting));

      ;
    

	,

	created: function () 
		this.fetchData();
	



</script>

组件代码:

<script>
export default 
  name: 'colma',
  data () 
    return 
      title: 'A Area',
      colmAdata:[]
    
  ,
  methods: 
    fetchData: function () 
      var self = this;
      var homeObject = JSON.parse(localStorage.getItem('homesetting'));

      // console.log('retrievedObject: ', retrievedObject.filter);
      var filter= homeObject.filter;
      var order= homeObject.order;

      // HERE I NEED MY TWO UPDATED VARIABLES
      var a = 'http://localhost:3000/'+'_'+filter+'_'+order;
      console.log('A',a);


      $.get(apiURL, function (data) 
        self.colmAdata = data;
        // self.$store.state.storeGdata = ' store data from content';
        // console.log(data.people[0].name);

      );

    

  ,
	created: function () 
		this.fetchData();
	

</script>

【问题讨论】:

你试过什么?你在哪里研究过? 【参考方案1】:

解决此问题的一种方法是从子组件发出自定义事件(如果更改源自子组件),然后在调用方法的父组件中捕获/侦听此事件。然后可以使用此方法调用将更新值的子方法。

真正的问题是,为什么需要这样做?假设父组件是事实的来源(即将数据作为 props 传递给子组件),那么您只需要观察这些 props 的变化,或者使用计算的 props 来获取更新的值。根本不需要使用事件来调用方法。

基本上,你的作案手法可以是:

    将父值(存储在父数据中)作为道具传递给子组件。子组件将响应式更新其继承的属性。

    家长的设置也可以同时存储到localStorage。这可以通过简单地使用watch 监视父数据的变化来完成。在这种情况下,您可以在重新挂载父级时(例如重新加载页面时)再次从localStorage 中读取—使用mounted lifecycle hook。根据第 1 点,这些更改将再次传播到子组件。

一个概念验证示例(要使 localStorage 功能正常工作,please check this fiddle,因为代码 sn-ps 是沙盒化的):

Vue.component('child-component-a', 
  template: '<div><h2>Child component A</h2><p>I multiply inherited parent value by 2: <strong> computedNumber </strong></p></div>',
  props: 
    number: 
      type: Number
    
  ,
  computed: 
    computedNumber() 
      return this.number * 2;
    
  
);

Vue.component('child-component-b', 
  template: '<div><h2>Child component B</h2><p>I divide inherited parent value by 16: <strong> computedNumber </strong></p></div>',
  props: 
    number: 
      type: Number
    
  ,
  computed: 
    computedNumber() 
      return this.number / 16;
    
  
);

var app = new Vue(
  el: '#app',
  data: 
    parentNumber: 1024
  ,
  watch: 
    parentNumber() 
      // Store parent number in localStorage when updated
      // *NOTE: Disabled in this code snippet since it is sandboxed
      // localStorage.setItem('parentNumber', this.parentNumber);
    
  ,
  mounted() 
    // Overwrite parent data if localStorage is found
    // *NOTE: Disabled in this code snippet since it is sandboxed
    // if (localStorage.getItem('parentNumber') !== null) 
    //   this.parentNumber = localStorage.getItem('parentNumber');
    // 
  
);
html 
  font-family: Arial, sans-serif;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
  <div>
    <h1>Parent component</h1>
    <p>I have a value of <strong> parentNumber </strong>.</p>
    <p>But wait, you can change my number!</p>
    <input v-model="parentNumber" type="number" />
  </div>
  <child-component-a v-bind:number="parentNumber"></child-component-a>
  <child-component-b v-bind:number="parentNumber"></child-component-b>
</div>

【讨论】:

我同意。存储在本地存储和从本地存储读取不是传播更改的方式。 我需要将这些设置数据保存在本地存储中。所以我认为这个程序行不通。 @Terry 知道了,让我试试这个。 @Sharat 我添加了一个概念验证代码 sn-p。请注意,localStorage 功能将无法使用,因为它已被沙盒化。 @Terry,我无法将您的代码 sn-p 用于我的项目。你能检查我更新的问题吗?现在根据我的项目结构给我一些建议。 :)【参考方案2】:

如果你使用 Vue.JS,你应该真的只使用 Vue.JS - 父级应该有一个模型,其中包含你的设置作为反应数据。然后你把这个属性作为 properties 传递给你的组件,组件只在属性上定义一个 watcher

var localStore =  reason: 'Fake, because no localStorage in Sandbox' ;

Vue.component('rows', 
  props: ["order"],
  data: function() return  values: []  ,
  template: `<ul><li v-for="v in values">v</li></ul>`,
  created: function()  this.fetchValues() ,
  watch:  order: function()  this.fetchValues()  ,
  methods:  fetchValues: function() 
    /* Placeholder for an ajax-call with order as a parameter */
    this.values = ( this.order == 'ascending' ) ? [1,2,3] : [3,2,1]
   
)

new Vue(
  el: '#main',
  data:  order: 'ascending' ,
  created: function() 
    if ( localStore.order ) 
      this.order = localStore.order;
    
  ,
  watch:  order: function() 
    /* Save any change on order in the local storage */
    localStore.order = this.order;
   
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>

<div id="main">
  <select v-model="order">
    <option value="ascending">Sort Ascending</option>
    <option value="descending">Sort Descending</option>
  </select>

  <rows :order="order"></rows>
</div>

【讨论】:

以上是关于当我在 Vue JS 中按下父组件上的按钮时如何刷新子组件?的主要内容,如果未能解决你的问题,请参考以下文章

当我在模拟器中按下 Apple TV 游戏手柄按钮时,它们不会触发

当我在颤动中按下按钮时,如何将 Card 小部件替换为 TextField? [关闭]

当我在我的应用程序中按下按钮时,我如何能够打开谷歌地图?

当我在 Motionbuilder 中按下录制按钮时,它会显示“没有可录制的内容”。

如何在vuejs中按下按钮后打开Web套接字?

如何在输入文本区域中创建 Enter 事件以使用 Vue.js 和 Electron 按下按钮