Vue.js 教程

Vue.js 组件传递数据

假如我们需要开发一个文章列表页面,该页面通过 v-for 指定动态渲染列表项,为了复用,决定将列表项封装成一个组件。但是,列表项中显示的数据需要动态传递,不然 v-for 将迭代渲染多个一样的组件,这不符合需求。Vue 为了解决向组件传输数据,提供了 props 属性。

Prop 是你可以在组件上注册的一些自定义属性。当一个值传递给一个 prop 属性的时候,它就变成了那个组件实例的一个属性。为了给列表项组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中,例如:

// 创建一个组件
Vue.component('article-item', {
    // 给组件定义一些 prop,用于调用组件的时候传值
    props: ['title'],
    // 组件模板
    template: '<div>{{ title }}</div>'
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值(即访问 title),就像访问 data 中的值一样。

完整示例

该示例将演示文章列表页,自定义文章项组件以及动态传值,如下:

<html>
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Vue</title>
   <!-- 使用 CDN 引入 Vue 库 -->
   <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>

   <div id="app">
       <!-- v-bind:title="article.title" 表示将当前迭代的文章标题绑定到组件的title属性,传递给组件 -->
       <article-item v-for="article in articles"
           v-bind:key="article.id"
           v-bind:title="article.title"></article-item>
   </div>

   <script type="text/javascript">
       // 定义文章相组件
       Vue.component('article-item', {
           // 自定义 prop
           props: [ "title" ],
           template: '<div>{{title}}</div>'
       });

       var app = new Vue({
           el: "#app",
           data: {
               articles: [
                   { id:1, title:"Vue 入门" },
                   { id:2, title:"Vue 生命周期" },
                   { id:3, title:"Vue 内部实现原理" }
               ]
           }
       });
   </script>

</body>
</html>

运行效果如下图:

Prop 传递对象

了解了怎样传递字符串到自定义组件,当构建一个 <article-item> 组件时,你的模板最终会包含的东西远不止一个标题:

<div>{{title}}</div>

最起码,你会包含这篇文章的标题、文章浏览数量、发布时间等信息。例如:

<div>{{title}}</div>
<div>
   <label>发布日期:{{date}}</label>
   <label>浏览量:{{count}}</label>
</div>

然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:

<div class="article_item">
   <div>{{title}}</div>
   <div>
       <label>发布日期:{{date}}</label>
       <label>浏览量:{{count}}</label>
   </div>
</div>

看起来当组件变得越来越复杂的时候,我们的文章项组件不只需要标题、发布日期、浏览量,还需要点赞票、反对票等等。如果为每个相关的信息都定义一个 prop 属性会变得很麻烦,就像这样:

<article-item v-for="article in articles"
   v-bind:key="article.id"
   v-bind:title="article.title"
   v-bind:date="article.date"
   v-bind:count="article.count"></article-item>

所以是时候重构一下 <article-item> 组件了,让它变成接受一个单独的 article 对象 prop 属性,例如:

<html>
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Vue</title>
   <!-- 使用 CDN 引入 Vue 库 -->
   <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>

   <div id="app">
       <article-item v-for="article in articles"
           v-bind:key="article.id"
           v-bind:article="article"></article-item>
   </div>

   <script type="text/javascript">
       // 定义文章相组件
       Vue.component('article-item', {
           // 自定义 prop
           props: [ "article" ],
           template: `
               <div style="background:#F0F0F0;margin-bottom:10px;padding:10px;">
                   <div>{{article.title}}</div>
                   <div style="font-size:14px;color:#555;">
                       <label>发布日期:{{article.date}}</label>
                       <label>浏览量:{{article.count}}</label>
                   </div>
               </div>
           `
       });

       var app = new Vue({
           el: "#app",
           data: {
               articles: [
                   { id:1, title:"Vue 入门", date:"昨日", count:189 },
                   { id:2, title:"Vue 生命周期", date:"上周", count:320 },
                   { id:3, title:"Vue 内部实现原理", date:"2023年6月9日", count:102 }
               ]
           }
       });
   </script>

</body>
</html>

运行效果如下:

注意:

(1)现在不论何时为 <article-item> 组件的 article 对象添加一个新的属性,它都会自动地在 <article-item> 内可用。

(2)上面 <article-item> 组件的模板使用了模板字符串来支持多行文本。但是,在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。

说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号