VueJS 从根 Vue 实例中的组件访问数据

Posted

技术标签:

【中文标题】VueJS 从根 Vue 实例中的组件访问数据【英文标题】:VueJS accessing data from component in root Vue instance 【发布时间】:2017-09-15 23:33:21 【问题描述】:

我正在尝试访问我的根 Vue 实例中的组件数据。我想要完成的是,您单击一个按钮并出现一组输入。每组输入都是 localStorage 中自己的对象,具有键 id、bags 和 amount。当我更新一组输入时,它们的值应该在 localStorage 中更新。我无法弄清楚如何访问我的组件的袋子和数量数据。我认为我应该使用的是道具,因为那是我在 React 中使用的。但是,我还不太习惯在 Vue 中使用它们。

这是我目前所拥有的:

var STORAGE_KEY = "orders";

var orderStorage = 
  fetch: function() 
    var orders = JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
    orders.forEach(function(order, index) 
      order.id = index;
    );
    orderStorage.uid = orders.length;
    return orders;
  ,
  save: function(orders) 
    localStorage.setItem(STORAGE_KEY, JSON.stringify(orders));
  
;

组件

Vue.component('order', 
  template: `
    <div>
      <select v-model="selected">
        <option v-for="option in options" v-bind:value="option.value">
           option.text 
        </option>
      </select>
      <input class="input" id="bags" v-model="bags" type="number" placeholder="Bags">
      <input class="input" id="amount" v-model="amount" type="number" placeholder="Amount">
      <button @click="$emit('remove')">Remove</button>
    </div>
  `,
  props: 
    bags: this.bags, // I must be doing this wrong
    amount: this.amount
  ,
  data() 
    return 
      bags: null,
      amount: null,
      selected: null,
      options: [
        text: "Product (25kg)",
        value: 25
      , 
        text: "Product (50kg)",
        value: 50
      , 
        text: "Product (75kg)",
        value: 75
      ]
    
  ,
  watch: 
    bags(newValue) 
      this.amount = newValue * this.selected;
    ,
    amount(newValue) 
      this.bags = newValue / this.selected;
    
  
);

根 Vue 实例

new Vue(
  el: '#app',
  data: 
    orders: orderStorage.fetch(),
    bags: null,
    amount: null,
  ,
  watch: 
    orders: 
      handler: function(orders) 
        orderStorage.save(orders);
      ,
      deep: true
    
  ,
  methods: 
    addProduct: function() 
      this.orders.push(
        id: orderStorage.uid++,
        bags: this.bags, // component.bags ?
        amount: this.amount// component.amount?
      );
      console.log(localStorage);
    
  
);

html

<div id="app">
  <button @click="addProduct">Add</button>

  <div class="orders">
    <order v-for="(order, index) in orders" :id="index" :key="order" @remove="orders.splice(index, 1)" :bags="bags" :amount="amount"></order>
  </div>
</div>

示例:https://codepen.io/anon/pen/YVwxpz?editors=1010

【问题讨论】:

【参考方案1】:

通常,您不希望进入组件以获取其数据。你希望组件$emit 它。 Vue 通常是props down, events up。

我已修改您的订单组件以支持v-model。这允许对组件的更改自动反映在父级中。

Vue.component('order', 
  props:["value"],
  template: `
    <div>
      <select v-model="order.value">
        <option v-for="option in options" v-bind:value="option.value">
           option.text 
        </option>
      </select>
      <input class="input" id="bags" v-model="order.bags" type="number" @input="onBags" placeholder="Bags">
      <input class="input" id="amount" v-model="order.volume" type="number" @input="onVolume" placeholder="Amount">
      <button @click="$emit('remove')">Remove</button>
    </div>
  `,
  data() 
    return 
      options: [
        text: "Product (25kg)",
        value: 25
      , 
        text: "Product (50kg)",
        value: 50
      , 
        text: "Product (75kg)",
        value: 75
      ],
      order: this.value
    
  ,
  methods: 
    onBags() 
      this.order.volume = this.order.bags * this.order.value;
      this.$emit("input", this.order)
    ,
    onVolume() 
      this.order.bags = this.order.volume / this.order.value;
      this.$emit("input", this.order)
    
  
)

new Vue(
  el: '#app',
  data: 
    orders: orderStorage.fetch(),
  ,
  watch: 
    orders: 
      handler: orders => orderStorage.save(orders),
      deep: true
    
  ,
  methods: 
    addProduct: function(order) 
      this.orders.push(
        id: orderStorage.uid++,
        bags: 0,
        volume: 0,
        value: 25
      );
    
  
);

这样做,您不必传递bagsamount,只需传递命令即可。然后,当订单发生变化时,会发出修改后的订单。

一个工作示例是here。

此外,我将value 属性添加到您的order 对象中。如果不保存,则无法正确计算袋子和体积的变化。

【讨论】:

【参考方案2】:

如果 props 让您感到困惑,请务必阅读 Composing Components,其中谈到了“props down, events up”的约定。

道具是从组件外部控制的数据。组件不应修改其 props(就像您在 watch 中所做的那样,以及您在 v-model 中使用它们时隐式所做的那样)。

您可能希望从道具中初始化组件data项目(给它们起与道具名称不同的名称!)然后您可以操纵这些值。

由于您希望父级知道值的更改,因此您应该在发生更改时emit events。父级可以捕获这些事件并采取适当的措施,例如将它们保存到订单对象和 localStorage。

【讨论】:

以上是关于VueJS 从根 Vue 实例中的组件访问数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 VueJS 中的插槽访问其他组件中的组件数据

如何使用 Vue 类组件访问 VueJS 3 和 Typescript 中的 HTML 引用?

从方法访问 vue 组件中的数据

使用 JQuery 在 PHP 中访问 Vue JS 组件数据

向 VueJS + Vue Router 中的组件发送数据

访问 Vue JS 实例监视对象中的 $refs 数组