Измените значение данных корневого экземпляра Vue по нажатию кнопки компонента, затем измените v-show / v-if другого компонента

1

Так что я весь день борюсь с этой проблемой. В основном у меня есть корневой компонент с свойством data dbEnabled, который должен решить, отображать ли еще один дочерний компонент с именем Database.

Это должно быть достигнуто нажатием кнопки на еще одном дочернем компоненте с именем Навигация. Мне удалось отправить это свойство от root к компоненту, указав его как опору на принимающем компоненте и передав v-show или v-if из базы данных. К сожалению, он реагирует только на создание экземпляра (не реагирует на изменение).

До сих пор мне удалось достичь этого другим путем, используя document.getElementByID(#db) и добавив класс, который устанавливает отображение: none! Important ; для этого элемента, но можно ли это сделать с Vue изначально?

Это файл main.js:

import Vue from 'vue'
import App from './App'
import Title from './Components/Title.vue'
import Navigation from './Components/Navigation.vue'
import AddProduct from './Components/AddProduct.vue'
import Database from './Components/Database.vue'

Vue.config.productionTip = false

Vue.component('app-title', Title)
Vue.component('nav-buttons', Navigation)
Vue.component('add-product', AddProduct)
Vue.component('db', Database)

/* eslint-disable no-new */
window.App = new Vue({
  el: '#app',
  components: { App, Title, Navigation, AddProduct, Database },
  template: '<App/>',
  data: {
    dbEnabled: false // <-- this should decide whether to show/hide #db element
  }
})

Это компонент навигации, который содержит кнопку переключения:

<template>
  <div id="nav-div">
    <button> {{ planBtn }}</button>
    <button> {{ addBtn }}</button>
    <button> {{ editBtn }}</button>
    <button @click="hideDb()"> {{ dbBtn }}</button> //<--here I tried openDb() function    
  </div>
</template>

<script>
  export default {
    name: 'Navigation',
    props: ['dbEnabled'],
    data() {
      return {
        dbBtn: 'Open database',
        addBtn: 'Add product',
        planBtn: 'Plan meal',
        editBtn: 'Edit product'
      }
    },

    methods: {
      openDb() {
        App.dbEnabled = !App.dbEnabled //<--This function changes the root instance 
                                       //value but the v-show/v-if doesn't react to the 
                                       //change. Nor does changing this value in Chrome
                                       //console make it react
      },

      hideDb() {
        let d = document.getElementById("db")
        d.className = (d.className === '') ? db.className='db-hidden' : db.className=''
        }
      }
    }

</script>

Это компонент базы данных:

<template>
  <div id="db"> //<--Tried v-show/v-if here, but works only initially
    <table>
      <thead>
        <tr>
          <th
            v-for="prAttr in gridColumns"
          >{{ prAttr }}</th>
        </tr>
      </thead>
      <tbody>
        <tr
          :weight="weight"
          v-for="product in products">
          <td> {{ product.name }}  </td>
          <td> {{ carbs(product, weight) }} </td>
          <td> {{ sugar(product, weight) }} </td>
          <td> {{ fiber(product, weight) }} </td>
          <td> {{ fat(product, weight) }} </td>
          <td> {{ protein(product, weight) }} </td>
          <td> {{ unknwn(product, weight) }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
  export default {
    name: 'Database',

    data() {
      return {
        weight: 100,
        gridColumns: ['Product name', 'Carbs (%)', 'Sugar (%)', 'Fiber (%)',
        'Fat (%)', 'Protein (%)', 'Unknwn(%)'],
        products: [
          {name: 'Rimi piens pasterizets 2,5%', carbs: 4.8, sugar: 4.8,
        fiber: 0, fat: 2.5, protein: 3.2, unknwn: 'unknwn_ingredients'},
          {name: 'Santini Ksylitol', carbs: 99.8, sugar: 0.2,
        fiber: 0, fat: 0, protein: 0}
        ]
      }
    },

    props: ['dbEnabled'],

    methods: {
      unknwn(cp, weight) {
        let unknwn_ingredients = (100 - cp.carbs
         - cp.fiber - cp.fat - cp.protein) / weight * 100
        return unknwn_ingredients.toFixed(2)
        },

      carbs(cp, weight) {
        let carbs = cp.carbs / weight * 100
        return carbs
      },

      sugar(cp, weight) {
        let sugar = cp.carbs / weight * 100
        return sugar
      },

      fiber(cp, weight) {
        let fiber = cp.carbs / weight * 100
        return fiber
      },

      fat(cp, weight) {
        let fat = cp.carbs / weight * 100
        return fat
      },

      protein(cp, weight) {
        let protein = cp.carbs / weight * 100
        return protein
      }
    }
  }
</script>
Теги:
vue.js
vuejs2
vue-reactivity

1 ответ

1
Лучший ответ

Вы ориентируетесь не на то место. Вы хотите настроить целевой компонент, а не фактический экземпляр vue (приложение)

Самый простой способ исправить это - изменить App.dbEnabled = !App.dbEnabled this.$root.dbEnabled = !this.$root.dbEnabled

У вас установлен vue-devtools? Это помогает узнать, что вы на самом деле нацеливаете.

Я также советую вам посмотреть на vm. $ Emit(). Лично я использовал бы emit, чтобы подтолкнуть детские изменения вверх по цепочке. Однако в вашем примере это может быть немного избыточным.

  • 0
    Да, у меня установлена программа vue-devtools. В нем показано, что корневым компонентом является $ vm0. Забавно то, что когда я обновляю приложение и набираю $ vm0 в консоли - он показывает Uncaught ReferenceError: $vm0 is not defined. this. $ root` выводит как undefined . Я попытался заменить App.dbEnabled this.$root.dbEnabled и он действительно меняет значение свойства, однако v-shot и v-if прежнему не реагируют на изменение логического значения. Чего мне не хватает?
  • 0
    Да, это нормально :) vue-devtools устанавливает $ vm0 при щелчке, и он не запоминает при перезагрузке: /
Показать ещё 8 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню