博客列表 >Vue组件注册及其参数传递

Vue组件注册及其参数传递

longlong
longlong原创
2020年09月10日 13:39:371305浏览

Vue组件

  • 组件是可复用的实例,比如:一个网页中某一个部分需要在多场景中使用,可以抽成一个组件进行复用,提高代码复用性
  • 组件化开发能大幅度的提高应用开效率、测试性、复用性

1. 组件注册

组件分类:全局组件、局部组件

  • 全局组件:全局可用,可以用在所有新创建的Vue根实例(new Vue)的模板中
  • 局部组件:只能在自己的根实例模板中
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>Vue组件</title>
  7. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8. </head>
  9. <body>
  10. <div class="app1">
  11. <!-- 将全局组件加载到页面挂载点中 -->
  12. <global-component-1></global-component-1>
  13. <!-- 将局部组件加载到页面挂载点中 -->
  14. <local-component-1></local-component-1>
  15. <local-component-2></local-component-2>
  16. </div>
  17. <hr />
  18. <div class="app2">
  19. <global-component-1></global-component-1>
  20. <!-- 局部组件不能用在其他根实例的挂载点中 -->
  21. <local-component-1></local-component-1>
  22. </div>
  23. <script>
  24. // 1. 全局组件
  25. // Vue.component(组件名,组件模板内容)
  26. // 组件名又叫组件标签,模板内容是一个对象
  27. Vue.component("global-component-1", {
  28. template: "<p>我是一个全局组件</p>",
  29. });
  30. const vm1 = new Vue({
  31. el: ".app1",
  32. // 2. 局部组件:仅限当前根实例使用
  33. components: {
  34. "local-component-1": {
  35. template: "<p>这是局部组件一</p>",
  36. },
  37. "local-component-2": {
  38. template: "<p>这是局部组件二</p>",
  39. },
  40. },
  41. });
  42. const vm2 = new Vue({
  43. el: ".app2",
  44. });
  45. </script>
  46. </body>
  47. </html>

小总结:组件注册的注意点:

1. 全局组件注册以后,要加载到页面中,需要一个挂载点,这个挂载点就是Vue实例的挂载点,所有也必须要创建Vue实例

2. 在当前根实例中注册的局部组件,可以一次性注册多个,但是仅限使用在当前根实例的模板中或挂载点中

3. template,其字面意思就是模板,里面写用户自定义的组件模板内容


小问题:在实际开发中,肯定不可能像上述案例中,组件模板只有这样一条语句,所以通常会将组件模板进行优化,可以创建多条语句

2. 组件模板优化

关于组件模板优化的方式有很多,比如:在template中使用ES6的模板语法,也可以书写多行语句,如下:

  1. <body>
  2. <div class="app">
  3. <local-component-1></local-component-1>
  4. </div>
  5. <script>
  6. const vm = new Vue({
  7. el: ".app",
  8. components: {
  9. "local-component-1": {
  10. template: `
  11. <ul>
  12. <li>文本一</li>
  13. <li>文本二</li>
  14. <li>文本三</li>
  15. </ul>
  16. `,
  17. },
  18. },
  19. });
  20. </script>
  21. </body>

另外,也可以在HTML中借助<script>标签来绑定模板内容,如下:

  1. <div class="app">
  2. <local-component-2></local-component-2>
  3. </div>
  4. <script type="x-template" id="local-com-2">
  5. <div>
  6. <h3>我的列表</h3>
  7. <ul>
  8. <li>列表一</li>
  9. <li>列表二</li>
  10. <li>列表三</li>
  11. </ul>
  12. </div>
  13. </script>
  14. <script>
  15. const vm = new Vue({
  16. el: ".app",
  17. components: {
  18. "local-component-2": {
  19. template: "#local-com-2",
  20. },
  21. },
  22. });
  23. </script>

注意点:组件模板中的内容,必须是一个容器包裹的,如上述中,我用了一个div将h3和ul包裹了起来,如果没有这个div,那么页面只会显示h3的内容


上面的方式显然比第一种要好些,但是使用的是script标签,始终感觉怪怪的,所以在实际开发中,采用得最多的方式就是下面这一种:

使用<template>标签编写模板内容,再结合id属性将模板内容与组件模板template绑定,如下:

  1. <div class="app">
  2. <local-component-3></local-component-3>
  3. </div>
  4. <template id="local-com-3">
  5. <div>
  6. <h3>我的列表</h3>
  7. <ul>
  8. <li>列表一</li>
  9. <li>列表二</li>
  10. <li>列表三</li>
  11. </ul>
  12. </div>
  13. </template>
  14. <script>
  15. const vm = new Vue({
  16. el: ".app",
  17. components: {
  18. "local-component-3": {
  19. template: "#local-com-3",
  20. },
  21. },
  22. });
  23. </script>

以上三种方式渲染出来的页面效果如下:

3. 组件的参数传递

先总结一下组件的参数传递有如下几种方式

  • 通过自定义属性传参(自定义属性写在挂载点中,如:div)
  • 通过data()方法传参,(data()方法写在组件中,返回一个对象,键名就是参数名,键值就是参数值)
  • 自定义属性和data()方法两者结合传参
  • 父组件向子组件传参(父组件即Vue根实例(new Vue),其实也是通过对象传参,只不过此时的对象被写在了Vue实例的数据对象data中)
  • 子组件向父组件传参(通过事件来呼叫父组件响应,其响应过程其实也是通过自定义属性去调用父组件中的方法)

3.1 使用自定义属性向组件传参

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>使用自定义属性向组件传参</title>
  7. <link
  8. href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. rel="stylesheet"
  10. />
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <div class="app">
  17. <!-- 将自定义属性写在组件标签中 -->
  18. <g-component id="1001" username="Jack" email="jack@qq.com"></g-component>
  19. </div>
  20. <template id="g-com">
  21. <div class="container">
  22. <div class="row">
  23. <div class="col-sm-4 col-md-offset-4">
  24. <table class="table table-bordered">
  25. <tr>
  26. <th>ID</th>
  27. <th>Username</th>
  28. <th>Email</th>
  29. </tr>
  30. <tr>
  31. <!-- 使用插值语法,将变量插入 -->
  32. <td>{{id}}</td>
  33. <td>{{username}}</td>
  34. <td>{{email}}</td>
  35. </tr>
  36. </table>
  37. </div>
  38. </div>
  39. </div>
  40. </template>
  41. <script>
  42. Vue.component("g-component", {
  43. template: "#g-com",
  44. // 在组件中,使用 props 来接收组件标签传过来的参数
  45. props: ["id", "username", "email"],
  46. });
  47. const vm = new Vue({
  48. el: ".app",
  49. });
  50. </script>
  51. </body>
  52. </html>

3.2 使用data()向组件传参

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>使用data()向组件传参</title>
  7. <link
  8. href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. rel="stylesheet"
  10. />
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <div class="app">
  17. <g-component></g-component>
  18. </div>
  19. <template id="g-com">
  20. <div class="container">
  21. <br /><br /><br />
  22. <div class="row">
  23. <div class="col-sm-8 col-md-offset-2">
  24. <table class="table table-bordered">
  25. <tr>
  26. <th>ID</th>
  27. <th>Username</th>
  28. <th>Email</th>
  29. </tr>
  30. <tr>
  31. <td>{{id}}</td>
  32. <td>{{username}}</td>
  33. <td>{{email}}</td>
  34. </tr>
  35. </table>
  36. </div>
  37. </div>
  38. </div>
  39. </template>
  40. <script>
  41. // data()应该写在组件中
  42. Vue.component("g-component", {
  43. template: "#g-com",
  44. props: [],
  45. data() {
  46. return {
  47. id: 1002,
  48. username: "Tom",
  49. email: "tom@qq.com",
  50. };
  51. },
  52. });
  53. const vm = new Vue({
  54. el: ".app",
  55. });
  56. </script>
  57. </body>
  58. </html>

3.3 使用data()和属性向组件传参

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>使用data()和属性向组件传参</title>
  7. <link
  8. href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. rel="stylesheet"
  10. />
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <div class="app">
  17. <!-- 使用自定义属性传参 -->
  18. <g-component blog="https://www.myblog.com"></g-component>
  19. </div>
  20. <template id="g-com">
  21. <div class="container">
  22. <br /><br /><br />
  23. <div class="row">
  24. <div class="col-sm-8 col-md-offset-2">
  25. <table class="table table-bordered">
  26. <tr>
  27. <th>ID</th>
  28. <th>Username</th>
  29. <th>Email</th>
  30. <th>Blog</th>
  31. </tr>
  32. <tr>
  33. <td>{{id}}</td>
  34. <td>{{username}}</td>
  35. <td>{{email}}</td>
  36. <td><a :href="blog">{{blog}}</a></td>
  37. </tr>
  38. </table>
  39. </div>
  40. </div>
  41. </div>
  42. </template>
  43. <script>
  44. // data()应该写在组件中
  45. Vue.component("g-component", {
  46. template: "#g-com",
  47. // 这里要接收组件标签中自定义属性传来的参数
  48. props: ["blog"],
  49. // 使用data()传参
  50. data() {
  51. return {
  52. id: 1002,
  53. username: "Tom",
  54. email: "tom@qq.com",
  55. };
  56. },
  57. });
  58. const vm = new Vue({
  59. el: ".app",
  60. });
  61. </script>
  62. </body>
  63. </html>

3.4 父组件向子组件传参

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>父组件向子组件传参</title>
  7. <link
  8. href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. rel="stylesheet"
  10. />
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <!-- 父组件:就是根实例 new Vue , 它是唯一的 -->
  17. <div class="app">
  18. <!-- 子组件:它可以有多个,可以由全局组件和局部组件共同组成 -->
  19. <!-- 使用自定义属性来实现父组件向子组件传参 -->
  20. <!-- 可以理解为使用一个自定义属性绑定了父组件中的参数,这个参数可以是对象,也可以是数组 -->
  21. <g-component :data="users"></g-component>
  22. </div>
  23. <template id="g-com">
  24. <div class="container">
  25. <br /><br /><br />
  26. <div class="row">
  27. <div class="col-sm-8 col-md-offset-2">
  28. <table class="table table-bordered">
  29. <tr>
  30. <th>ID</th>
  31. <th>Username</th>
  32. <th>Email</th>
  33. </tr>
  34. <!-- 这里就不能遍历users了,因为已经使用自定义属性data接管这个数据对象了 -->
  35. <!-- 当然通常情况下,可以将自定义属性和数据对象命名一致,这里只是为了方便理解 -->
  36. <tr v-for="item of data">
  37. <td>{{item.id}}</td>
  38. <td>{{item.username}}</td>
  39. <td>{{item.email}}</td>
  40. </tr>
  41. </table>
  42. </div>
  43. </div>
  44. </div>
  45. </template>
  46. <script>
  47. Vue.component("g-component", {
  48. template: "#g-com",
  49. // 接收从父组件传过来的数据
  50. props: ["data"],
  51. });
  52. // 父组件传给子组件的参数应该在数据对象中
  53. const vm = new Vue({
  54. el: ".app",
  55. data: {
  56. users: [
  57. { id: 1001, username: "alice", email: "alice@qq.com" },
  58. { id: 1002, username: "mike", email: "mike@qq.com" },
  59. { id: 1003, username: "lose", email: "lose@qq.com" },
  60. ],
  61. },
  62. });
  63. </script>
  64. </body>
  65. </html>

3.5 子组件向父组件传参

通过一个购物车案例来演示这个传参过程

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>子组件向父组件传参:购物车案例</title>
  7. <link
  8. href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. rel="stylesheet"
  10. />
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <!-- Vue实例挂载点 -->
  17. <div class="app">
  18. <!-- 子组件通过事件呼叫父组件,使用自定义属性来完成这个交互 -->
  19. <g-component :products="products" @total='cal' :cal='cal'></g-component>
  20. <div class="container">
  21. <div class="row">
  22. <div class="col-md-4 col-md-offset-8">
  23. <p>总数量:{{counts}} 件</p>
  24. <p>总金额:{{totalPrice}} 元</p>
  25. </div>
  26. </div>
  27. </div>
  28. </div>
  29. <!-- 组件模板 -->
  30. <template id="g-com">
  31. <div class="container">
  32. <br><br>
  33. <div class="row">
  34. <div class="col-md-8 col-md-offset-2">
  35. <table class="table table-bordered table-hover">
  36. <thead >
  37. <tr class="info" >
  38. <th>商品ID</th>
  39. <th>商品名称</th>
  40. <th>商品价格</th>
  41. <th>商品数量</th>
  42. </tr>
  43. <tbody>
  44. <tr v-for='item of products'>
  45. <td>{{item.id}}</td>
  46. <td>{{item.name}}</td>
  47. <td>{{item.price}}</td>
  48. <td><input type="number" v-model='item.count' @change='resetCal'></td>
  49. </tr>
  50. </tbody>
  51. </thead>
  52. </table>
  53. </div>
  54. </div>
  55. </div>
  56. </template>
  57. <script>
  58. // 全局组件
  59. Vue.component('g-component',{
  60. template:'#g-com',
  61. props:['products'],
  62. methods:{
  63. resetCal(){
  64. // 子组件向父组件呼叫,用来调用父组件中的cal()方法计算总数量和总金额
  65. this.$emit('total');
  66. }
  67. },
  68. });
  69. // Vue实例
  70. const vm = new Vue({
  71. el: ".app",
  72. data: {
  73. products:[
  74. {id:1001,name:'商品一',price:100,count:1},
  75. {id:1002,name:'商品二',price:200,count:1},
  76. {id:1003,name:'商品三',price:300,count:1},
  77. ],
  78. totalPrice:0,
  79. counts:0,
  80. },
  81. // 计算总数量与总金额的方法
  82. methods: {
  83. cal(){
  84. this.totalPrice = 0;
  85. this.counts = 0 ;
  86. this.products.forEach((item)=>{
  87. // 禁止输入框数量低于0
  88. if(item.count<=0){item.count=0}
  89. this.totalPrice += item.price * item.count;
  90. this.counts += item.count*1;
  91. });
  92. },
  93. },
  94. // 挂载成功,立即执行这个函数
  95. mounted() {
  96. this.cal();
  97. },
  98. });
  99. </script>
  100. </body>
  101. </html>

4. 小总结

1. 组件模板的优化首选采用<template>标签,添加id 属性与组件模板 template绑定

2. 使用 props 来接收组件的参数

3. 自定义属性传参是在组件标签中进行

4. data() 传参是在组件中进行

5. 父组件传参子组件,是通过子组件的自定义属性,绑定父组件数据对象 data 中的数据,然后通过 props 来接收这个数据对象

6. 子组件传参父组件,是通过事件呼叫父组件响应,而这个交互也是通过组件标签的自定义属性来实现的,记住$emit,还有组件标签中的属性设置

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议
Dan、2021-02-06 16:26:441楼
另类的前端组件传参方式,或许这篇文章对您有帮助 https://markdowner.net/article/143392883591163904