知识点梗概
组件化开发思想 组建注册方式components 组件之间的数据交互 组建插槽 Vue调试工具 组件化开发实践
组件化开发思想
-
组件化开发思想总结起来有以下四点:
- 标准化
- 功能分区
- 循环利用
- 自由组合
组件化开发在发展过程中直到现在已经逐渐形成了一套标准化规范来帮助开发者更便利地开展工作,这套规范称之为Web Components,但目前并不是所有浏览器都支持这套规范。
在这套规范出现之前,我们对于组件化开发有以下几个期待:第一,代码可以尽量多地被重复利用;第二,组件可自定义,包括html标签,css样式和js逻辑;第三,各组重复利用的代码之间没有冲突。
Web Component通过创建封装好功能的定制元素实现了以上的需求。这里的定制元素可以理解为自定义标签。在Web Components规范下我们可以自定义标签来实现一些特定的功能并且该功能是封装在标签内部的,不会与其他标签产生冲突。
Vue组件化开发部分参考了Web Components的规则。
组件注册
全局组件
组件注册 Vue.component(组件名称, {data: 组件数据, template: 组件模板内容})
下面自定义个全局组件来举个栗子:
组件使用 像这样定义的全局组件不需要在App.vue中components注册就可以直接上树。
还可以这样写。
这个组件是可以重复使用的,并且重复使用的组件之间是相互独立的。
【注意】 ①data必须是个函数; 使用函数是为了给数据形成一个闭包的环境保证每个组件的数据都是独立的。
②组件模板内容必须是单个根元素; 下面图示一下如果模板内容不是单个根元素会出现什么问题。
也有办法让以上两个btn变成一个单独的根元素,就是在它们的外层包一个div标签。
之前在建立Vue项目基础框架时提过,所有的模板内容都应该在el指定的容器中,这个容器就是一个项目的最外层,相当于一个项目的根元素,以上所说的组件化开发原理与此同理。
③组件模板内容可以是模板字符串; 但需要注意的是这是在ES6语法规则的前提下才可以的,需要浏览器的兼容性支持。后续学到前端工程化后这个问题可以忽略。下面举个栗子看看通过模板字符串如何处理模板内容。 我们之所以需要用到模板字符串是在这样一个情境下的,我们定义组件时是用template属性来定义模板内容的,如果内容量很大就会让代码挤成一长串降低可读性,而利用模板字符串来编辑模板内容则可以让代码更加规整和直观。
将单引号(或者双引号)替换成反引号就可以在其中规整地编辑模板内容,这就是模板字符串。
④组建的命名方式有两种; 短横线命名法 Vue.components('my-component', {/*...*/}) 驼峰命名法 Vue.components('MyComponent', {/*...*/})
全局组件不仅可以应用在根组件,还可以应用于其他组件中。
使用驼峰命名法的组件也可以以短横线命名法的方式上树根组件。
局部组件
组件注册
局部组件就是通过components属性注册的组件,组件的内容可以写在一个对象里,在对象中编辑组件模板内容的方法与全局组件相似,也是利用data和tamplate等属性。
- var ComponentA = {/*...*/}
- var ComponentB = {/*...*/}
- var ComponentC = {/*...*/}
- new Vue({
- components:{
- 'component-a': ComponentA,
- 'component-b': ComponentB,
- 'component-c': ComponentC,
- }
- })
- 字符串String
- 数值Number
- 布尔值Boolean
- 数组Array
- 对象Object
- 子组件自定义事件语法规则:
- <button v-on:click='$emit("enlarge-text")'>扩大字体</button>
- 父组件监听子组件自定义事件语法规则:
- <div v-on:enlarge-text='fontSize += 5'>扩大此处字体</div>
- 子组件传递数据语法规则:
- <button v-on:click='$emit("enlarge-text", 5)'>扩大字体</button>
- 父组件接收子组件数据语法规则:
- <div v-on:enlarge-text='fontSize += $event'>扩大此处字体</div>
- 建立事件中心:
- var eventHub = new Vue()
- 监听事件:
- eventHub.$on('add-todo', addTodo)
- 这里面的第一个参数是自定义事件的名称,第二个参数是事件函数。
- 销毁事件:
- eventHub.$off('add-todo')
- 触发事件:
- eventHub.$emit('add-todo', id)
- 触发事件时可以携带参数。
按照以上方法注册好的局部组件只能在注册它的父组件(根组件 )使用而不能在任何其它全局组件使用。
而在webpack打包项目的情况下,注册局部组件也就是子组件有另外的套路,在主页有一篇专门的笔记(https://juejin.cn/post/6844904061766991879),此处不再作讲解。
Vue调试工具
Vue组件最终对会渲染成原生的DOM,如果在浏览器调试工具中查看就只能看到最终渲染的结果,如此我们就很难区分这些DOM元素各自是归属于哪个组件的。 为了更直观地展现组件之间的层次关系,Vue有一套专门的调试工具来更方便开发者的调试工作。
Vue调试工具的安装和使用
如图点开生态系统菜单下的Devtools来到下载页面下拉到下面会有下载说明,跟着步骤下载安装即可。
安装好之后Chrome浏览器右上角就会出现这个工具的图标,如果没有出现就去“更多工具”→“扩展程序”里面设置一下。
在调试工具中我们可以看到每个组件的内容并且可以进行编辑调试。
组件之间的数据交互
webpack打包项目的组件间数据交互请看这两篇: https://juejin.cn/post/6844904061766991879 https://juejin.cn/post/6844904089520701453
这里拿之前写好的组件再简单讲一下。
父组件→子组件数据传递——props属性
props的用法
我这里的项目是用webpack打过包的所以我这里图一这个挂出来的App.vue就是根组件(父组件)跟直接在html写没有挂出来的根组件(图二红框)是一样东西。
图一
图二
如图一所示之前写的子组件都已经上树到父组件上面了,用webpack打包的项目子组件是放在components文件夹里然后在父组件App.vue里import并在components属性里注册然后上树(具体看上面贴出的笔记)。
这里就拿button-counter这个子组件来举个栗子,重点分清数据传递的点和线以及父子组件之间的层次关系,有点绕,不懂多看几遍。
其实父子组件之间不像是上面图示这样的里外包含关系而是上下树状关系,但在这个点的讲解上我认为这样标识或许更好理解,上面我直接将要传递的数据写在自定义属性里了,这个数据应该写在父组件的data里再插值表达式引上去会表达的更清楚些,同时,这个自定义属性可以是像上面这样静态的也可以写成动态,动态自定义属性在上面贴出的笔记中有讲解这里就不说了。
关于如何利用props传递数据的举栗讲解到此结束。
自定义属性命名规则
在模板中自定义属性只能使用短横线命名法,因为DOM元素的属性不区分大小写,但在props中可以用驼峰的方式来接收模板中用短横线方式命名的数据,字符串形式模板则不受此命名规则限制。
props属性值类型及动静态传值对数据类型的影响
自定义属性传值时有一个细节需要注意,就是这个属性动态与否会直接影响所传递数据的类型,当自定义属性为静态时,传达到子组件的数据将会是字符串形式的数据。下面举个栗~
当数值型属性动态传值时,子组件所接收到的数据也是数值型,是可参加运算的;当数值型属性静态传值时,子组件所接收到的数据会变成字符串,是不可参加运算的。
同理,布尔值在动态传值下,子组件接收到的数据就是布尔值,在静态传值下子组件接收到的数据就会变成字符串。
下面再看看数组的传值。
接着是对象的传值。
子组件→父组件数据传递——$emit( )
基于以上的props属性传值,父组件传递给子组件的数据是可以被子组件直接操作的。但由于props传递数据的原则是但向数据流,因而只能用于父组件向子组件传递数据,而子组件是无法通过props向父组件传递数据的。 原因是如果允许子组件通过props操作父组件中的数据的话容易导致逻辑混乱,就好像两个方向的车流都挤在了一条车道上,像现在这样单向的处理逻辑能更好地保持操作逻辑的清晰。
Vue为子组件想父组件传递数据提供了特定的方法$emit( ),子组件是通过自定义事件向父组件传递数据的。
以上的按钮是假设是子组件中的一个按钮,当遇到点击事件时就会触发一个特定的方法$emit,这个方法名是固定的,方法中需要携带一个参数,这个参数就是接下来要说的自定义事件,当然这个自定义事件的名称就是自定义的。父组件通过事件绑定来监听子组件传递的数据。
下面具体实现一下。
下面看一下效果。
上面关于子组件向父组件传递数据的演示并没有真实地携带数据,而仅仅是在子组件触发了一个事件,这个事件被传递到父组件,父组件监听到这个事件以后触发了在父组件中的一些操作行为。
下面具体说一下数据的传递。
子组件在触发事件时,通过如上$emit()中的第二个参数来携带数据传递到父组件。
子组件通过$emit()携带的数据会传递到父组件中对应的绑定事件里,父组件可以通过$event接收到这个值并再传参给对应的事件,也就是以上演示实例中的handle,如此父组件便可以获取并操作这个从子组件传递过来的值。
具体的运行效果不再展示。
兄弟组件之间的数据传递——事件中心管理模式
实际的做法是new一个Vue实例对象来扮演事件中心的角色,在事件中心中可以进行事件监听即事件销毁的操作。
下面演示一下。
首先另起一个js文件来建立这个事件中心,这个事件中心是需要对外暴露的,这样App.vue和main.js就可以同时与这个事件中心连接。
事件中心建立完成以后就可以在子组件中通过事件中心来进行事件监听,这里事件监听利用到的是钩子函数mounted,组件生命周期走到mounted时代表模板内容已经就绪并可以被操作。这里自定义事件对应的函数使用的是箭头函数,因为这里要用到this。
这里自定义事件的任务是,当事件被触发时,获取对方组件的参数并让对方组件中的num加上这个参数。
在对方组件重复以上步骤。
运行效果自行测试~
组建插槽
这个点另外开一篇笔记。