【问题标题】:Understanding components nesting in VueJS理解 VueJS 中的组件嵌套
【发布时间】:2018-10-09 23:02:21
【问题描述】:

学习 VueJS 并浏览一些在线教程,包括 vuejs.org 上的指南,我非常了解如何嵌套组件并让它们通过 props 进行通信。

简单的例子似乎没问题,但下面的代码(稍微调整但几乎超出了 VueJS 指南)给我带来了麻烦。

我似乎无法将 'blog-item' 嵌套在 'blog-items.

如果有人能解释如何使用 v-for 指令嵌套组件,我将不胜感激。

我已经阅读了许多教程,并且似乎一切正常,其中一个组件嵌套在提供数据的顶级“应用程序”组件中,但我似乎无法将其转换为下面的场景。

作为一个新手,我可能会错过一个关键概念,或者完全偏离了对 Vue 的理解 :)

希望你能帮忙。

谢谢

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Components Basics - from vuejs.org</title>
    <!-- development version, includes helpful console warnings -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">

      <!-- This works. I get it. -->
      <div id="components-demo">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
      </div>

      <hr>

      <!-- This works too and I get it. -->
      <div id="blog-post-demo-simple">
        <blog-post-simple title="My journey with Vue"></blog-post-simple>
        <blog-post-simple title="Blogging with Vue"></blog-post-simple>
        <blog-post-simple title="Why Vue is so fun"></blog-post-simple>
      </div>

      <hr>

      <!-- This is where I'm totally confused -->
      <!-- How do I structure this to make sure blog-items is binding the 'post'  -->
      <!-- correctly? What is not clear to me is where the directives should be placed -->
      <!-- Vue keeps complainig with the following: -->
      <!-- Property or method "posts" is not defined on the instance but referenced during render -->
      <blog-items>
        <blog-item
          v-for="post in posts"
          v-bind:key="post.id"
          v-bind:post="post">
        </blog-item>
      </blog-items>

      <hr>

    </div>

    <script>

      // Define a new component called button-counter. Cool. No problem here.
      Vue.component('button-counter', {
        data: function () {
          return {
            count: 0
          }
        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
      })

      // This is also clear.
      Vue.component('blog-post-simple', {
        template:
        '<h3>{{title}}</h3>',
        props: {
          title: {
            type: String,
            required: true
          }
        }
      })

      Vue.component('blog-items', {
        data() { return {
            posts: [
              { id: 1, title: '1. My journey with Vue' },
              { id: 2, title: '2. Blogging with Vue' },
              { id: 3, title: '3. Why Vue is so fun' }
            ]
          }
        }
      })

      Vue.component('blog-item', {
        template:
        '<h2>{{post.title}}</h2>',
        props: ['post']
      })

      var app = new Vue({
        el: '#app'
      })

    </script>
  </body>
</html>

【问题讨论】:

    标签: vue.js vue-component


    【解决方案1】:

    请记住,当您访问模板中的属性时,您是从使用该模板的组件中获取该属性。在这种情况下,它是您的根 #app 组件。由于该组件没有名称为 posts 的属性或方法,因此 Vue 会抱怨。您需要做的是在 blog-items 组件的模板中移动该部分,因为该组件正在保存您的帖子。

    所以你需要做的是这个..

        <!-- This is where I'm totally confused -->
        <!-- How do I structure this to make sure blog-items is binding the 'post'  -->
        <!-- correctly? What is not clear to me is where the directives should be placed -->
        <!-- Vue keeps complainig with the following: -->
        <!-- Property or method "posts" is not defined on the instance but referenced during render -->
        <blog-items></blog-items>
    

    Vue.component('blog-items', {
        template: `
        <div>
            <blog-item v-for="post in posts" v-bind:key="post.id" v-bind:post="post" />
        </div>
        `,
        data() {
            return {
                posts: [
                { id: 1, title: '1. My journey with Vue' },
                { id: 2, title: '2. Blogging with Vue' },
                { id: 3, title: '3. Why Vue is so fun' }
                ]
            }
        }
    })
    

    否则您将不得不使用Scoped Slots,它允许您将属性/方法从子组件的范围暴露给父组件..

    <blog-items>
        <template slot-scope="{ posts }">
            <blog-item v-for="post in posts" v-bind:key="post.id" v-bind:post="post">
            </blog-item>
        </template>
    </blog-items>
    

    Vue.component('blog-items', {
        template:`
        <div>
            <slot :posts="posts"></slot>
        </div>`,
        data() {
            return {
                posts: [
                { id: 1, title: '1. My journey with Vue' },
                { id: 2, title: '2. Blogging with Vue' },
                { id: 3, title: '3. Why Vue is so fun' }
                ]
            }
        }
    })
    

    我发现this 特别有助于理解作用域插槽的工作原理。

    【讨论】:

    • @djeetee 为此,你会想要插槽〜vuejs.org/v2/guide/components-slots.html
    • @djeetee 在&lt;div id="blog-post-demo-simple"&gt; 中,您只是静态分配title 属性,而不是像在后一种情况下那样尝试使用v-forv-bind 访问属性。由于您将根组件安装到 #app div,因此该 div 中的所有内容都被视为根组件的模板。由于根组件没有您尝试访问的属性,并且它们仅在子组件的范围内可用,因此您必须使用范围插槽将这些属性公开给父级。我已经更新了我的答案来证明这一点。
    • 关于你的最后一个问题。 Vue.component 是【全局注册组件】的方式。当您在全球范围内注册一个组件时,它在任何地方都可用。它可以用在根组件的模板中,也可以用在其他组件的模板中,甚至可以用在recursively within its own template。这适用于演示和小型应用程序,但通常建议不要在大型​​应用程序中使用。
    • 这是因为全局注册的组件在整个应用程序中都是可用的,所以如果你使用 webpack 之类的打包器来打包你的应用程序并删除未使用的代码,所有全局注册的组件都将在你的 final 中结束捆绑您是否最终使用它们。例如,如果您创建要在项目中使用的组件库并在全局范围内注册所有组件,这将成为一个问题。
    • new Vue 另一方面是creates a new Vue instance。如果您通过el 选项或mount 方法提供一个元素,则该实例将安装到该元素并成为它的根Vue 实例。
    猜你喜欢
    • 2016-08-13
    • 1970-01-01
    • 2017-08-06
    • 2023-04-04
    • 2016-04-18
    • 2017-08-10
    • 1970-01-01
    • 2018-08-12
    • 2017-12-12
    相关资源
    最近更新 更多