【问题标题】:How do I get a parent vue component and child vue component to use the same data object?如何让父 vue 组件和子 vue 组件使用相同的数据对象?
【发布时间】:2019-03-13 21:24:55
【问题描述】:

我有一个Guestbook 组件,我将其分为SignView 组件。 我想通过我的主要留言簿组件和我的子视图组件传递或更好地共享条目数据,但我不知道如何实现这一点。

我有以下代码:

/src/components/Guestbook.vue

<template>
<div>
    <h1>Guestbook</h1>

    <SignGuestbook />
    <ViewGuestbook :entries="v_entries" />
    <ViewGuestbook :p_entries="v_entries" />
    <!-- Error: '[Vue warn]: Property or method "store" is not defined on the instance but referenced during render.' -->
    <!-- <ViewGuestbook :entries="store" /> -->
    <!--   <ViewGuestbook :p_entries="store" /> -->
    <!-- Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.' -->
    <!-- <ViewGuestbook :entries="$store" /> -->
    <!-- <ViewGuestbook :p_entries="$store" /> -->
</div>
</template>

<script>
import SignGuestbook from './SignGuestbook.vue'
import ViewGuestbook from './ViewGuestbook.vue'
import Vue from 'vue'
import Vuex from 'vuex'
import guestbook from './guestbook.js'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    entries: [
      { id: 1, name: 'stored 1', comment: 'comment' },
      { id: 2, name: 'stored 2', comment: 'comment' }
    ]
  },
  getters: {
    entries: entries => {
      return entries
    }
  },
  mutations: {
    refreshList (state) {
      state.s_entries = guestbook.getItems()
    }
  }
})

export default {
  name: 'Guestbook',
  components: {
    SignGuestbook,
    ViewGuestbook
  },
  props: ['v_entries'],
  data () {
    return { comment: '', name: '', entries: ['test'] }
  },
  methods: {
    refreshList: async function () {
      this.entries = await guestbook.getItems()
      store.commit('refreshList')
      // this.$store = await guestbook.getItems()
      console.log('regular entries:', this.entries)
      console.log('stored entries:', this.store.getters.entries)
    }
  },
  async created () {
    await guestbook.authoriseAndConnect()
    await guestbook.createMutableData()
    await this.refreshList()
  }
}
</script>

/src/components/ViewGuestbook.vue

<template>
  <div>

    get entries attempt #1<br>
    <div v-for="entry in entries">
      an entry<br>
    </div>
    <br>
    get entries attempt #2<br>
    {{ entries }}
    <br>
    <!-- Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.' -->
    <!-- stored entries<br>
    {{ this.$store }}
    <br>-->
    <br>

    </div>
  </div>
</template>

<script>

export default {
  name: 'ViewGuestbook',
  props: ['p_entries'],
  data () {
    return { entries: [
      { id: 1, name: 'child 1', comment: 'comment' },
      { id: 2, name: 'child 2', comment: 'comment' }
    ]}
  },
  async created () {
    this.entries = this.p_entries
  }
}

</script>

/src/components/guestbook.js

let app
let md

async function authoriseAndConnect () {
  const opts = {
    forceUseMock: true
  }
  let appInfo = {
    name: 'SAFE Guestbook Application',
    id: 'net.maidsafe.tutorials.web-app',
    version: '0.1.0',
    vendor: 'MaidSafe.net Ltd.'
  }
  app = await window.safe.initialiseApp(appInfo, null, opts)
  console.log('Authorising SAFE application...')
  try {
    const authReqUri = await app.auth.genAuthUri()
    console.log('Generated authentication URI...', authReqUri)
    const authUri = await window.safe.authorise(authReqUri)
    console.log('SAFE application authorised...')
    await app.auth.loginFromUri(authUri)
  } catch (err) {
    console.warn('Application authorisation was rejected', err)
  }
  console.log('Application connected to the network')
}

async function createMutableData () {
  console.log('Creating MutableData with initial dataset...')
  const typeTag = 15000
  md = await app.mutableData.newRandomPublic(typeTag)
  const initialData = {
    'random_key_1': JSON.stringify({
      name: 'parent 1',
      comment: 'comment'
    }),
    'random_key_2': JSON.stringify({
      name: 'parent 2',
      comment: 'comment'
    })
  }
  await md.quickSetup(initialData)
}

async function getItems () {
  const entries = await md.getEntries()
  let entriesList = await entries.listEntries()
  let items = []
  entriesList.forEach((entry) => {
    const value = entry.value
    if (value.buf.length === 0) return
    const parsedValue = JSON.parse(value.buf)
    items.push({ key: entry.key, value: parsedValue, version: value.version })
  })
  return items
}

module.exports = {
  authoriseAndConnect,
  createMutableData,
  getItems
}

index.js

import Vue from 'vue'
import App from './App'
import router from './router'

export default new Vue({
  el: '#root',
  router,
  render: (h) => h(App)
})

// Error: unused variable
// let globalData = new Vue({
//   data: {
//     $store: {}
//   }
// })

// Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.'
// Vue.mixin({
//   computed: {
//     $store: {
//       get: function () { return globalData.$data.$store },
//       set: function (newData) { globalData.$data.$store = newData }
//     }
//   }
// })

预期(至少其中之一):

get entries attempt #1
an entry
an entry
get entries attempt #2
[{ id: 1, name: 'stored 1', comment: 'comment' },{ id: 2, name: 'stored 2', comment: 'comment' }]

结果:

get entries attempt #1

get entries attempt #2


get entries attempt #1

get entries attempt #2

【问题讨论】:

  • 这听起来像是 Vuex 的工作
  • 父子属性总是共享对象。孩子可以查看父母的变化。但是,孩子不应该直接修改它。子节点更改的调度事件,父节点可以将其保存到原始数据中。
  • 保守地使用全局数据...例如门户详细信息/用户详细信息和角色。其他数据可以由页面本身管理。无需为所有内容过度使用全局商店
  • 嗯,这是@matthias-s 的建议,所以我想我也会展示一下。不过,我不想使用全球商店。这最终应该是一个适合其他项目的模块。
  • @Teddy 如果父子属性始终是共享对象并且可以被孩子查看,那么我想知道如何。

标签: vue.js vuejs2 vue-component


【解决方案1】:

TL;DR: https://codesandbox.io/s/62wvro7083

我用自己的小数据存储解决了这个问题,这是一种非常简单的方法,但对我来说已经足够好了,无需深入研究 Vuex。

首先,在初始化其他任何内容之前,我会在某处创建我的数据存储。

window.globalData = new Vue({
    data: {
        $store: {
            shared: {}
        }
    },
});

之后,我添加了一个全局 Mixin,允许获取和设置数据到全局存储。

Vue.mixin({
    computed: {
        $store: {
            get: function () { return window.globalData.$data.$store },
            set: function (newData) { window.globalData.$data.$store = newData; }
        }
    }
});

然后,每个组件都可以通过this.$store 访问数据存储。在示例代码框中,我有一个保存内容的“共享”变量,请随意使用不同的方法:

https://codesandbox.io/s/62wvro7083

【讨论】:

  • 我在那里看到的有点多,不太清楚你把什么放在哪里,因为我没有说 Vuex。上面的解决方案将没有 Vuex。尝试改用window.globalData.....
  • 我编辑了我的答案并提供了一个 CodeSandbox 示例
【解决方案2】:

在 ViewGuestbook.vue 中,您必须将属性复制到主数据中。

created()mounted() 钩子中这样做:

this.entries = this.p_entries; //Just assign
this.entries = JSON.parse(JSON.stringify(this.p_entries)); //Or clone it.

【讨论】:

    【解决方案3】:

    要共享数据,请使用 v-bind 将父组件中的数据对象绑定到子组件的 props 对象。

    像这样:

    /src/components/Guestbook.vue

    ...
    <ViewGuestbook v-bind:entries="d_entries" />
    ...
    
    export default {
      name: 'Guestbook',
      components: {
        SignGuestbook,
        ViewGuestbook
      },
    data () {
      return { d_entries: [] }
    },
    methods: {
      refreshList: async function () {
        this.d_entries = [
          { id: 1, name: 'placeholder 1', comment: 'comment' },
          { id: 2, name: 'placeholder 2', comment: 'comment' }
        ]
      },
    },
    async created () {
      this.refreshList()
    }
    ...
    

    /src/components/ViewGuestbook.vue

    <template>
      <div>
    
        entries<br>
        <div v-for="entry in entries">
          {{ entry.name }}<br>
          {{ entry.comment }}<br>
        </div>
    
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'ViewGuestbook',
      props: {
        'entries': Array
      }
    }
    </script>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 2017-06-25
      • 2020-07-17
      相关资源
      最近更新 更多