【问题标题】:How Do I Pass Props Using Single File Components?如何使用单个文件组件传递道具?
【发布时间】:2017-03-06 19:51:36
【问题描述】:

从 React 来到 Vue。大多数情况下有很多相似之处,但通过props 似乎有点不同。我找不到太多关于如何使用单个文件组件执行此操作的文档。我将应用程序的所有数据导入main.js。我想知道如何将我的部分数据(例如currentUser)发送到ResourceInfo.vue?再次假设这些都是单个文件组件。我是否需要通过main.js 模板选项下的<App/> 部分将其传递给App.vue 中的<resource-info></resource-info>,然后以某种方式传递给ResourceInfo.vue?我也不想学习 Vuex,因为我才刚刚开始。谢谢!

main.js

import Vue from 'vue'
import App from './App'
import ResourceInfo from '../src/components/ResourceInfo'
var db = firebase.database();
var auth = firebase.auth();

/* eslint-disable no-new */
var vm = new Vue({
  el: '#app',
  data: function() {
    return {
        users: {},
        currentUser: {},
        quizzes: {},
        resources: []
    }
  },
  template: '<App/>',
  components: { App, ResourceInfo },
})

App.vue

<template>
  <div id="app">
    <navbar></navbar>
    <resource-info></resource-info>
  </div>
</template>

<script>
import Navbar from './components/Navbar'
import ResourceInfo from './components/ResourceInfo'

export default {
  name: 'app',
  components: {
    Navbar,
    ResourceInfo
  }
}
</script>

<style>
</style>

ResourceInfo.vue

<template>
</template>

<script>
var resourcesRef = firebase.database().ref('resources');

module.exports = {
  name: 'resource-info',
  data: function() {
    return {
      header: 'Before you build your quiz we just need some quick info.',
      resource: {
        type: '',
        title: '',
        url: '',
        desc: '',
        timesPassed: 0
      },
    }
  },
  firebase: {
    resources: resourcesRef
  },
  methods: {
    saveToFirebase: function() {
      resources.push({
        resource: this.resource
      })

      // Clear inputs  

      this.resource.title = '',
      this.resource.type = '',
      this.resource.desc = '',
      this.resource.url = ''

      console.log("Saving resource data...")

    }
  }
}
</script>

<style>
</style>

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    @DanM。已经给出了答案,希望你能按照他的指导修复你的props

    我正在写这个答案,以便我可以在我的应用程序中分享我处理currentUser 的方法(仅适用于登录用户)。这是我的项目结构(此答案高度简化):

    模板:webpack,使用vue init webpack my-project 使用vue-cli 安装

    我的应用文件:

    • ./main.js:应用入口文件
    • ./App.vue:负责页面布局,如页眉、页脚、路由内容使用router-view
    • ./components/:导航栏、页脚等常用组件。
    • ./routes/:路由组件。我更喜欢把它放在这里,而不是把我的组件文件夹弄得乱七八糟。
    • 还有更多...

    main.js 中的代码:只是定义路由和引导应用程序的标准代码。这里没什么特别的。

    App.vue 中的代码 - 这里是获取 currentUser 的地方。导航栏也被插入,我通过props传递currentUser

    <template>
        <div class="app-container">
            <app-navbar :currentUser="currentUserInfo"></app-navbar>
            <router-view></router-view>
            <app-footer></app-footer>
        </div>
    </template>
    
    <script>
    import AppNavbar from "./components/app-navbar.vue"
    import AppFooter from "./components/app-footer.vue"
    
    export default {
        components: {
            "app-navbar": AppNavbar
        },
        data: function() {
            return {
                currentUserInfo: {
                    loading: true
                } // start with an empty object and modify later
            }
        },
        // ... all other code ...
        created: function() {
            // Ensure that this is a logged-in user. Or else redirect to login page
            this.$http.get("/api/currentUser").then(response => {
                // process response
                this.currentUserInfo = response
                this.currentUserInfo.loading = false
            }, error => {
                // user not found. exit the Vue app and go to login page (directly from server)
                // Refer to my other answer: http://stackoverflow.com/a/40194152/654825
    
                // Or alternatively, you can serve your App's index.html only for logged-in users. Then you will never reach here.
            })
        },
        // ... more code ...
    }
    </script>
    

    现在在您的组件./components/navbar.vue中接收currentUser,如下所示:

    <template>
        <div class="navbar">
            <!-- some code - branding, etc.. -->
            <div>{{currentUser.loading ? "Loading..." : currentUser.name}}</div>
            <!-- some more code - logout link, etc.. -->
        </div>
    </template>
    
    <script>
    export default {
        props: ["currentUser"],
        // and more ...
    }
    </script>
    

    要消化的东西太多了。我还广泛使用vuex,因为您不想要vuex,所以我没有在上面的示例中显示。

    我希望它有助于构建您的应用程序。

    【讨论】:

    • 我将大部分逻辑放在App.vue 中,然后进行了重构,因为看起来他们在 Hacker News 示例中就是这样做的,但我认为他们也在使用 Vuex。将它放在App.vue 中而不是main.js 有什么好处?还有什么是“路由器组件”而不是“通用组件”?非常感谢您花时间写这个!正确构建应用程序对我来说很重要!
    • Vue 没有像 Ember 或 Angular2 这样的严格约定。就我而言,我决定使用 main.js 仅用于初始化应用程序,因为它不能包含模板。我的 App.vue 有根模板,负责页面布局——它有页眉、路由器出口和页脚。我的组件有两个不同的文件夹 - 1. 常见的文件夹,如页脚、标题、使用 vuex 的数据存储等,以及 2. 可路由组件(路由定义内的组件)。得益于 Vue 的灵活性,这只是个人选择!
    • 随着应用的增长,您可以不断更改这些文件夹约定。当您决定创建一个新类别的组件时,您只需返回 .vue 文件中的导入语句并修复路径。不到 5 分钟。
    • 一旦您克服了最初的麻烦,例如通过props 传递数据并弄清楚如何使用vuex 集中存储数据并提供给其他组件,您的应用程序将开始快速增长。之后,您可以开发自己的结构,最适合您的应用。
    • 是的,但是一旦您开始使用,您会非常喜欢vuex。它和 vue-router 一样有用。它集中管理您的所有数据,因此您的组件可以有一个共享区域。当您的应用运行时,它是您在浏览器端的数据存储。
    【解决方案2】:

    有几种方法可以实现这一目标。

    方法 #1 - 使用“模板”

    如果你想从main.js向下传递props,你需要在那里编辑模板并将数据先向下传递给App

    ma​​in.js

    new Vue({
      ...
      template: '<App :current-user="currentUser"/>'
      ...
    })
    

    ...在 App.vue

    <template>
      <div id="app">
        <navbar></navbar>
        <resource-info :current-user="currentUser"></resource-info>
      </div>
    </template>
    
    <script>
    module.exports = {
      ...
      props: ['current-user']
      ...
    }
    </script>
    ...
    

    然后,currentUser 将在ResourceInfo.vue 中可用(记得添加props: ['current-user'])。

    方法 #2 - 通过“渲染”属性向下传递

    渲染块允许在您正在渲染的组件上定义属性。

    在您的情况下,currentUser 可以像这样传递:

    var vm = new Vue({ 
        el: '#app', 
        data: function() { 
            return { 
                users: {}, 
                currentUser: {}, 
                quizzes: {}, 
                resources: [] 
            }
        }, 
        render (h) { 
            return ( 
                '<App />', 
                { attrs: { currentUser } } 
            ) 
        }, 
        components: { App, ResourceInfo } 
    })
    

    那么在App.vue你就可以通过props访问currentUser

    import Navbar from './components/Navbar'
    import ResourceInfo from './components/ResourceInfo'
    
    export default {
      name: 'app',
      props: ['current-user']
      components: {
        Navbar,
        ResourceInfo
      }
    }
    

    现在您可以像往常一样将其进一步向下传递给ResourceInfo.vue(见下文)。


    一般的传递道具

    App.vue

    <template>
      <div id="app">
        <navbar></navbar>
        <resource-info :current-user="currentUser"></resource-info>
      </div>
    </template>
    ...
    

    并在 ResourceInfo.vue 中添加props,如下所示:

    <template>
      <pre>{{currentUser}} <!-- dumb example --></pre>
    </template>
    
    <script>
    var resourcesRef = firebase.database().ref('resources');
    
    module.exports = {
      name: 'resource-info',
      props: ['current-user'], // You can also do prop validation here
        ...
      }
    }
    </script>
    
    ...
    

    你可以阅读更多关于道具here :-)


    【讨论】:

    • prop 必须从 main.js 传递到 App.vue?当我执行上述操作时,我在控制台中收到Property or method "currentUser" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. 警告。当我给App.vue 一个props: ['current-user'] 选项以及错误消失。
    • 我也可以在ResourceInfo.vue 方法中使用currentUser 数据吗?还是只能在&lt;template&gt;&lt;/template&gt;中使用
    • 是的,你可以。它的行为类似于data 属性。所以你可以通过this来访问它,例如在ResourceInfo.vue中:methods: { foo () { console.log(this.currentUser} }
    • 嗯,我在控制台中获取了一个用户对象,但是当我尝试在 console.log 中使用 ResourceInfo 时,它给了我未定义的信息。虽然没有抛出任何错误。
    • 再次通读您的代码并更新了答案。实际上,如果 currentUsermain.js 中,您需要先将其传递给 App,然后再将其进一步传递给 ResourceInfo .
    猜你喜欢
    • 2018-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多