vue.js入门(3)——vue.js组件学习and组件间通信

男娘i 2021-09-14 20:46 543阅读 0赞
  1. 组件 (Component) Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。(摘自官网,说的挺好直接抄了)
  2. 下一章开始,会封装几个具体的常用组件(alert/model/search)。
  3. 关于组件学习的知识点:
  4. 1.利用template参数替换自定义标签内容
  5. 2.利用props传递数据(父传子)
  6. 3.props验证(补充内容)
  7. 4.data字段详解
  8. 5.this.$emit传递数据(子传父)
  9. 6.单项数据流(补充内容)
  10. 7.利用slot分发数据,创建自定义dom
  11. 8.作用域问题

1.利用template参数替换自定义标签内容

  1. 在学习组件之前,首先需要用Vue.component(tagName, options)方法注册一个全局组件(当然你也可以在Vue实例里的Compnent对象里放组件,个人觉得这个功能有点鸡肋,因为组件本身的意义就是公用的,放到全局里方便使用)。

第一个参数TagName是组件的名称,可以理解为H5新增的自定义标签。(当然你也可以称为声明式标签,因为他的命名一般都是有意义的,如sel-tmp,指的是选项卡)。

第二个参数是选项,跟Vue实例里的参数差不多,具体会一个一个说明,下面的demo里用到了template,是最基本的参数之一,他会替换自定义标签里的内容。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>vue.js学习--组件and组件间通信</title>
  6. <link rel="stylesheet" type="text/css" href="/static/css/common.css">
  7. <link rel="stylesheet" type="text/css" href="/static/css/tmp.css">
  8. </head>
  9. <body>
  10. <div id="app">
  11. <div style="margin: 20px">
  12. <sel-tmp></sel-tmp>
  13. </div>
  14. </div>
  15. </body>
  16. <script src="/static/js/vue.js"></script>
  17. <script src="/static/js/jquery-1.11.1.js"></script>
  18. <script>
  19. //全局注册
  20. //Vue.component(tagName, options)
  21. Vue.component('sel-tmp', {
  22. //模板
  23. template:
  24. '<div class="tmp-drag-wrap">'+
  25. '<div class="tmp-drag-search">' +
  26. '<input type="text" class="tmp-drag-input" />'+
  27. '</div>'+
  28. '<ul class="tmp-drag-ul">' +
  29. '<li class="tmp-drag-li" >北京</li>'+
  30. '<li class="tmp-drag-li" >上海</li>'+
  31. '<li class="tmp-drag-li" >广州</li>'+
  32. '</ul>'+
  33. '</div>',
  34. })
  35. var vm = new Vue({
  36. delimiters:['${','}'],
  37. el:"#app",
  38. data:{
  39. }
  40. })
  41. </script>
  42. </html>

20180225151029201

可以看到自定义标签整个被替换成了template里的内容,该自定义标签不会存在于dom文档流。

2.利用props传递数据(父传子)

上面的demo里,Vue实例包含了,所以Vue实例相对于模板即为父级,如果父级需要向子级(也就是模板)传递一个数据应该在子级里使用props参数接受数据。下面我将,【北京,上海,广州】作为一个数组,从父级向子级传递。并在子级里用props接收。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>vue.js学习--组件and组件间通信</title>
  6. <link rel="stylesheet" type="text/css" href="/static/css/common.css">
  7. <link rel="stylesheet" type="text/css" href="/static/css/tmp.css">
  8. </head>
  9. <body>
  10. <div id="app">
  11. <div style="margin: 20px">
  12. <sel-tmp v-bind:receive-list="postList"></sel-tmp>
  13. </div>
  14. </div>
  15. </body>
  16. <script src="/static/js/vue.js"></script>
  17. <script src="/static/js/jquery-1.11.1.js"></script>
  18. <script>
  19. //全局注册
  20. //Vue.component(tagName, options)
  21. Vue.component('sel-tmp', {
  22. //利用props接收父级数据
  23. props:["receiveList"],
  24. //模板
  25. template:
  26. '<div class="tmp-drag-wrap">'+
  27. '<div class="tmp-drag-search">' +
  28. '<input type="text" class="tmp-drag-input" />'+
  29. '</div>'+
  30. '<ul class="tmp-drag-ul">' +
  31. '<li class="tmp-drag-li" v-for="item in receiveList" v-text="item"></li>'+
  32. '</ul>'+
  33. '</div>',
  34. })
  35. var vm = new Vue({
  36. delimiters:['${','}'],
  37. el:"#app",
  38. data:{
  39. postList:["北京","上海","杭州"],
  40. }
  41. })
  42. </script>
  43. </html>

效果跟1中的相同。关于数据传递,有一个不知是bug还是我不懂的地方:

dom里绑定数据的时候请用烤串命名法 v-bind:receive-list

函数内请用驼峰命名法 props:[“receiveList”]

3.props验证(补充内容)

关于props参数:props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义校验和设置默认值。

为什么要有props验证?

可以将props理解为子级提供给父级的一个输入口,如果父级输入的内容有误,比如在输入金额的输入框里,输入了中文,这个时候,子级就应该报错。然而父级并不一定知道子级需要什么内容(很有可能是某程序员负责写某一个组件,另一个程序员在某个模块中加一个这个组件,双方没有说明沟通),所以vue.js提供了props验证来防止这种情况发生。

  1. props:{
  2. "receiveList":{
  3. //type:Number, //验证类型
  4. //default:"",//默认值,如年龄可默认为一岁,性别默认为男等
  5. //required:true or false,//传参是否必填
  6. validator:function(value){
  7. console.log(value);//value = 父级传过来的值
  8. //return true or false;
  9. //比如来验证一下父级传过来的arr.lenght是否大于0,最好先判断传过来的是不是数组
  10. return value.length>=4?true:false;
  11. }
  12. }
  13. },

20180225155227442

事实上,如果传过来的数据有误,vue只会在控制台报错,并不会阻塞程序执行。所以验不验证对不看控制台的人来说是没啥意义的。(暗示某些测试测不出来的bug)

4.data字段详解

上一章对于vue实例里的data字段埋了一个坑,这里来填一下。

首先作为组件,可能会在一个页面多次用到,下面我通过实现一个功能来讲一下data里的坑。

功能:鼠标点击输入框,实现下拉框的显示和隐藏

实现:需要在data里添加一个ifShow字段来控制模板

  1. template:
  2. '<div class="tmp-drag-wrap">'+
  3. '<div class="tmp-drag-search">' +
  4. '<input type="text" class="tmp-drag-input" @click="ifShow=!ifShow" />'+
  5. '</div>'+
  6. '<ul class="tmp-drag-ul" v-show="ifShow">' +
  7. '<li class="tmp-drag-li" v-for="item in receiveList" v-text="item"></li>'+
  8. '</ul>'+
  9. '</div>',
  10. //data需要用函数返回值,避免多个组件公用一个data对象
  11. data:function(){
  12. return {
  13. ifShow:false,
  14. }
  15. },

在vue.component里,data不能是对象的形式,会直接报错。

可以用函数返回值的形式,避免组件间公用同一数据而相互影响。

5.用this.$emit传递数据(子传父)

刚才的组件再划分一下,将输入框和下拉框分开,让下拉框单独出来作为一个组件(纯粹为了方便讲解)

现在,下拉框变成了子级,父级则是由下拉框组件+输入框,要把下拉框的内容传递给父级,使用了实例中的$emit触发自定义事件,并将参数传给父级。看代码注释:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>vue.js学习--组件学习</title>
  6. <link rel="stylesheet" type="text/css" href="/static/css/common.css">
  7. <link rel="stylesheet" type="text/css" href="/static/css/tmp.css">
  8. </head>
  9. <body>
  10. <div id="app">
  11. <div style="margin: 20px">
  12. <sel-tmp v-bind:name-arr="list"></sel-tmp>
  13. </div>
  14. </div>
  15. </body>
  16. <script src="/static/js/vue.js"></script>
  17. <script src="/static/js/jquery-1.11.1.js"></script>
  18. <script>
  19. //全局注册
  20. Vue.component('sel-tmp', {
  21. // 声明 props
  22. props: ['nameArr'],
  23. template:
  24. '<div class="tmp-drag-wrap">'+
  25. '<div class="tmp-drag-search">' +
  26. '<input type="text" class="tmp-drag-input" @click="ifShow=!ifShow" v-model="content"/>'+
  27. '</div>'+
  28. '<ul-tmp :nameArr="nameArr" :ifShow="ifShow" @receive="receiveData"></ul-tmp>'+ //自定义事件触发父级函数
  29. '</div>',
  30. data:function(){
  31. return {
  32. ifShow:false,
  33. content:"",
  34. }
  35. },
  36. methods:{
  37. receiveData:function(args){
  38. this.content = args; //父级接收自定义函数参数
  39. }
  40. }
  41. })
  42. Vue.component("ul-tmp",{
  43. props:["nameArr","ifShow"],
  44. template:
  45. '<ul class="tmp-drag-ul" v-show="ifShow">' +
  46. '<li class="tmp-drag-li" v-for="item in nameArr" v-text="item" @click="postData(item)"></li>'+
  47. '</ul>',
  48. methods:{
  49. postData:function(item){
  50. this.$emit("receive",item); //子级触发自定义事件,并把想传的参数传出去
  51. }
  52. }
  53. })
  54. var vm = new Vue({
  55. delimiters:['${','}'],
  56. el:"#app",
  57. data:{
  58. list:["北京","上海","杭州"],
  59. }
  60. })
  61. </script>
  62. </html>

20180225162453883

如此,完成了子级向父级传递数据。

6.单项数据流(补充内容)

单项数据流是个神马东西?官网里并没有有关于这项东西的说明,我个人也还没完全摸透这块东西。

首先来解释一下这个名词(用自己语言组织一下)

在组件中,利用props父级向子级传递数据后,子级内部对数据进行了处理,如改变数据的某个值,这时候控制台就会报错(又是一个只报错不影响结果的破玩意儿)。

解决方案:在子级作用域中,将接收的值存入私有的data 或者 computed里,就可以操作(他只是不报错而已)。

来说一下我没搞明白的地方,就是已经标出来的“改变数据”四个字。如,我对上面父级传过来的地名数组进行处理,会发生以下两种情况,

  1. methods:{
  2. postData:function(item){
  3. //this.nameArr=["北京","上海","杭州","广州"];//如果这样写,会报错,因为修改了整个数组
  4. //this.nameArr.push("广州");//这样写就不会报错,而且能push数据进去
  5. this.$emit("receive",item);
  6. }
  7. }

两种修改数据的方法都能执行,只是前者会报错,后者不报错,有兴趣的自己试试。

7和8的内容放到下一章讲吧,在研究研究…

发表评论

表情:
评论列表 (有 0 条评论,543人围观)

还没有评论,来说两句吧...

相关阅读