传递 Props

Vue.js 上下文中的 props 是在子组件中定义的字段,可以在该组件的实例 (this) 和组件的模板(template)中访问它们。

prop 的值取决于父组件在渲染时在模板(template)中传递给子组件的内容。

定义一个需要 props 的简单组件

让我们看一个简单的 Hello 单文件组件。这可以在 ./src/components/Hello.vue 文件(在 Vue CLI 生成的项目中)中找到。请注意 who 值是如何在 props 数组中设置的,以及如何使用 {{ who }} 将其插值为值。Vue.js 组件的 props 属性可以是字符串数组或对象字面值。

当在 props 中定义一个值时,它就可以作为 Vue.js 组件模板(template)部分中的实例变量进行访问:

<template>
    <div>
        <h1>Hello {{ who }}</h1>
    </div>
</template>
<script>
    export default {
        props: ['who']
    }
</script>

我们现在将学习如何使用 props 渲染组件。

使用 Props 渲染组件

下面演示了如何在我们的 Vue.js 应用程序中使用 Hello 组件。

首先,我们需要导入它,然后在要渲染此导入组件的 Vue.js 组件的 Components 属性中设置它。

然后,在模板(template)部分,我们需要渲染 <Hello> 并将 who 属性设置为 "Vue.js",如下所示:

<template>
    <div id="app">
        <Hello who="Vue.js"/>
    </div>
</template>

<script>
import Hello from './components/Hello.vue'

export default {
    components: {
        Hello
    }
}
</script>

这将在页面上呈现以下内容:

Hello Vue.js

我们现在已经了解了如何在 Vue.js 应用程序中使用组件并通过 props 传递它。这对于代码重用以及将应用程序行为抽象为组件大小的块非常有用。

接下来,我们将学习如何使用注册的组件。

组件注册技巧

关于组件(components)属性有一些需要注意的事项。

注册的组件可以以 CamelCaseName 和 kebab-case-name 的形式使用,因此,如果我们将上一个示例中显示的模板部分更改为使用 <hello /> 而不是 <Hello />,它将可以正常工作,不会出现任何问题:

<template>
    <div id="app">
        <hello who="Vue.js"/>
    </div>
</template>

更新后的模板在浏览器中呈现相同的效果,如以下输出所示:

Hello Vue.js

Components 属性倾向于利用 ES6 速记属性语法。 简写属性语法意味着我们可以编写 { Hello },而不是 { Hello: Hello }。 我们可以在下面的示例中看到它的实际操作,该示例注册了 Hello 组件:

import Hello from './components/Hello.vue'
export default {
    components: {
        Hello
    }
}

Vue 的组件声明不知道组件名称。它使用组件对象中的键根据驼峰命名法和短横线命名法进行注册:

<template>
    <div id="app">
        <Hey who="Vue.js"/>
    </div>
</template>

<script>
import Hello from './components/Hello.vue'

export default {
    components: {
        Hey: Hello
    }
}
</script>

前面的代码将生成以下输出:

Hello Vue.js

我们现在已经学习了如何使用 Components 属性和 ES6 简写对象属性语法在 Vue.js 中注册组件。

接下来,我们将看一个 Greeting 组件的实际示例。

练习 4.01:实现 GREETING 组件

利用我们对如何将 props 从父组件传递到子组件的知识,我们将创建一个组件,让您可以自定义 greeting(例如,HelloHeyHola)以及收件人(例如,World、Vue.js 或 JavaScript developers)。

要访问本练习的代码文件,请参阅 https://packt.live/35jGd7B 。请按照以下步骤完成本练习:

请按照以下步骤完成本练习:

  1. 在 ./src/components 目录中创建一个名为 Greeting.vue 的新文件。这将是我们的单文件组件。

  2. 首先使用空模板(template)和脚本(script)标签搭建组件:

    <template>
        <div>Empty</div>
    </template>
    <script>
        export default {}
    </script>
  3. 接下来,我们需要告诉 Vue.js 我们的组件需要 props。为此,我们将在组件定义中添加一个 props 属性(在 script 部分中设置为 export default 的对象),并向其添加 greeting 和 who 属性:

    export default {
        props: ['greeting', 'who']
    }
  4. 现在,我们要渲染 greeting 和 who。正如我们所看到的,当在 props 中定义值时,它们在模板(template)的顶层可用:

    <template>
        <div>{{ greeting }} {{ who }}</div>
    </template>

    我们现在可以从 App.vue 渲染 Greeting 组件。

  5. 打开 src/App.vue 文件并将 Greeting 组件从 ./src/components/Greeting.vue 导入到脚本(script)部分:

    <script>
    import Greeting from './components/Greeting.vue'
    </script>
  6. 接下来,在组件中注册 Greeting 组件:

    <script>
    export default {
        components: {
            Greeting
        }
    }
    </script>
  7. 现在组件已经注册了,我们可以在模板(template)中渲染它:

    <template>
        <div id="app">
            <Greeting greeting="Hey" who="JavaScript"/>
        </div>
    </template>

    您将在浏览器中看到以下内容(确保您已在 Exercise4.01 目录中运行 npm install 和 npm run serve):

    Hey JavaScript
  8. 使用模板(template)中的属性值修改 greeting 和 who 属性:

    <template>
        <div id="app">
            <Greeting greeting="Hi" who="Everyone"/>
        </div>
    </template>

    运行上述代码后,您应该在浏览器中看到类似于以下内容的输出(确保您已在 Exerce4.01 目录中运行 npm install,然后运行 npm run serve):

    Yarn 包含与 Yarn 下的 npm run 命令等效的命令。 例如,我们可以分别使用 yarn install 和 yarn serve 命令,而不是 npm install 和 npm run serve。

    Hi Everyone

在本练习中,我们了解了如何使用 prop 和 prop 传递来通过泛化组件来增加组件的重用场景。其父组件不是渲染静态数据,而是向其传递要渲染的数据。

在下一节中,我们将学习如何动态设置 prop 值。

具有数据绑定的动态 Props

到目前为止,我们看到的示例都使用硬编码的属性值作为 props。但是如果我们想将父实例数据从父级传递给子级怎么办?

这就是绑定的用武之地。Vue.js 中的 prop/attribute 绑定语法是 v-bind:,但您可以使用 : 来简写;它们是等价的。

Greeting 的 who 属性绑定到 appWho 应用组件的实例属性:

<template>
    <div id="app">
        <Hello v-bind:who="appWho"/>
    </div>
</template>

<script>
import Hello from './components/Hello.vue'
export default {
    components: {
        Hello
    },
    data() {
        return {
            appWho: 'Vue.js'
        }
    }
}
</script>

简而言之,模板(template)如下所示:

<template>
    <div id="app">
        <Hello :who="appWho"/>
    </div>
</template>

两个版本都会向浏览器输出以下视图:

Hello Vue.js

v-bind:prop-name 和 :prop-name 具有惊人的相似性,因为 v-bind 和 prop-name 之间的分隔符是 :(分号)。在 Vue.js 单文件组件中,由于模板是在构建时编译的,因此它们在功能上是等效的。

下面的示例展示了值已从父组件 (App) 同步(传播)到子组件 (Hello),其中有两个按钮可更改 Hello 消息的受众。

按钮使用 JavaScript 或 Everyone 调用名为 setWho 的组件方法,具体取决于按钮。此 setWho 函数更新 appWho 实例属性:

<template>
    <div id="app">
        <Hello :who="appWho"/>
        <button @click="setWho('JavaScript')">JavaScript</button>
        <button @click="setWho('Everyone')">Everyone</button>
    </div>
</template>

<script>
import Hello from './components/Hello.vue'

export default {
    components: {
        Hello
    },
    data() {
        return {
            appWho: 'Vue.js'
        }
    },
    methods: {
        setWho(newWho) {
            this.appWho = newWho
        }
    }
}
</script>
image 2023 10 12 22 34 30 308
Figure 1. Figure 4.1: Initial Hello Vue.js output in the browser

单击 JavaScript 按钮时,appWho 变量会更新,绑定的 Hello 组件的 who 属性也会更新。这样就会显示 Hello JavaScript,如下:

image 2023 10 12 22 35 55 216
Figure 2. Figure 4.2: Hello JavaScript after clicking the JavaScript button

单击 Everyone 按钮时,appWho 变量会更新,绑定的 Hello 组件的 who 属性也会更新。这样就显示 Hello Everyone,如下:

image 2023 10 12 22 36 53 928
Figure 3. Figure 4.3: Hello Everyone after clicking the Everyone button

我们现在已经了解了如何将 props 绑定到值,以便它们保持同步。

大多数 Vue.js 应用程序除了模块化渲染组件之外,还利用组件(就像我们对 Greeting 和 Hello 组件所做的那样)。

正如我们所看到的,我们能够绑定 props,以便对父组件中的值进行的任何更新都会导致子组件中的更新。

练习 4.02:传递随时间变化的 Pros

要知道使用哪种问候语,我们将实现一个问候语应用程序,该应用程序具有多个问候语并循环播放它们。

要访问本练习的代码文件,请参阅 https://packt.live/3kovKfo

请按照以下步骤完成本练习:

  1. 创建一个 ./src/components/Greeting.vue 组件并使用我们之前实现的 Greeting 组件对其进行初始化。这是我们显示问候语的方式:

    <template>
        <div>{{ greeting }} {{ who }}</div>
    </template>
    <script>
    export default {
        props: ['greeting', 'who']
    }
    </script>
  2. 在 ./src/App.vue 组件中,导入 ./src/components/Greeting.vue 作为 Greeting 并将其注册为组件,以便您可以渲染它:

    <script>
    import Greeting from './components/Greeting.vue'
    
    export default {
        components: {
            Greeting
        }
    }
    </script>
  3. 在脚本(script)部分中,创建一个数据(data)顶级方法,该方法返回初始 greeting 和 who:

    export default {
        data() {
            return {
                greeting: 'Hello',
                who: 'Vue.js'
            }
        }
    }
  4. 使用 Greeting 组件渲染当前 greeting 和 who:

    <template>
        <div id="app">
            <!--绑定计算属性-->
            <Greeting :greeting="greeting" :who="who"/>
        </div>
    </template>

    您的浏览器将显示一条消息,如下所示(确保您已在 Exercise4.02 目录中运行 npm install 和 npm run serve):

    以下代码要求您了解计算属性,我们在第 2 章 “使用数据” 中介绍了这些知识。 如果您需要复习,请现在返回该章。

  5. 现在,我们将一些 greeting/who 配对作为数组添加到脚本(script)部分:

    <script>
    // imports
    const possibleGreetings = [
        { greeting: 'Hello', who: 'Vue.js' },
        { greeting: 'Hey', who: 'Everyone' },
        { greeting: 'Hi', who: 'JavaScript' }
    ]
    // components export
    </script>
  6. 让我们重构 data 方法,使其仅存储默认索引并创建计算属性,这些属性查找索引以生成 greeting 以及基于当前索引的 who(使用中间的 currentGreeting 计算属性):

    <script>
    // imports and greetings
    export default {
        // components definition
        data() {
            return {
                currentIndex: 0
            }
        },
        computed: {
            currentGreeting() {
                return possibleGreetings[this.currentIndex]
            },
            greeting() {
                return this.currentGreeting.greeting
            },
            who() {
                return this.currentGreeting.who
            }
        }
    }
    </script>

    此时,应用程序仍应在浏览器中显示相同的问候语,如以下输出所示:

    Hello Vue.js

    由于计算属性清理了代码,我们不需要更新模板。相反,我们用同名的计算属性替换了 greeting 和 who 实例属性。这里绑定的是计算属性而不是 data 数据属性。

  7. 让我们添加一种方法来循环显示这些 greetings。这将涉及一个按钮,单击该按钮将调用模板(template)中的 newGreeting 函数:

    <template>
        <div id="app">
            <Greeting :greeting="greeting" :who="who"/>
            <button @click="newGreeting()">New Greeting</button>
        </div>
    </template>
  8. 接下来,我们需要在脚本中实现 newGreeting。newGreeting 应移动到下一个问候语(通过增加 currentIndex)。或者,如果我们已经到达 possibleGreetings 数组的末尾,它应该重置 currentIndex:

    <script>
    // imports and greetings
    export default {
        // other component properties
        methods: {
            newGreeting() {
                this.currentIndex = this.currentIndex ===
                possibleGreetings.length – 1
                ? 0
                : this.currentIndex + 1
            }
        }
    }
    </script>

    初始加载时,单击 New Greeting 按钮 3n 次后,应用程序将显示 Hello Vue.js,如以下屏幕截图所示:

    image 2023 10 12 23 03 04 068
    Figure 4. Figure 4.4: Hello Vue.js after 3n button clicks

    第一次单击 New Greeting 按钮并连续单击 3n + 1 次后,应用程序将显示 Hey Everyone,如下所示:

    image 2023 10 12 23 06 27 956
    Figure 5. Figure 4.5: Hey Everyone after 3n + 1 button clicks

    第二次单击以及 3n + 2 次单击 New Greeting 按钮后,应用程序将显示 Hi JavaScript,如下所示:

    image 2023 10 12 23 07 03 582
    Figure 6. Figure 4.6: Hi JavaScript after 3n + 2 button clicks

    这段代码还可以进一步改进; 例如,possibleGreetings. length - 1 是常量,因为我们从不添加或删除问候语。我们可以在 newGreeting 方法之外计算一次,而不是对每个 newGreeting 调用进行计算。读取数组的长度和简单算术 (-1) 的成本并不太高,但这是对可变值与常量值的思考的一个很好的回顾。

至此,我们已经了解了如何使用 props 和 prop 绑定来将数据从父组件更改为它们渲染的子组件进行通信。为了扩展代码库或广泛共享代码,当代码使用者错误使用代码时向他们提供提示会很有帮助。

接下来,我们将学习如何向组件的 props 添加类型提示,以确保它们被正确使用。