谈谈Vue两大核心之一:组件如何应用如何通信
在使用Vue技术栈开发项目时,必不可少的会用到组件,不得不说,Vue的组件功能特别强大,使整个项目功能模块及各种view页面分类井井有条,对于我这种看到大堆代码就急躁的人很是友好了。
本文目录
- 1.Vue组件
- 2.组件注册(全局和局部)
- 3.动手创建一个组件
- 4.实现父子通信
props
(静态动态和传值类型) - 5.实现父子通信
$ref
- 6.实现子组件向父组件通信
$emit
- 7.实现子向子组件的通信
1.Vue组件
-
组件是可复用的 Vue 实例,是一段可重用的UI,它封装了其中的所有行为和功能。
例如:Chrome的日期输入框()就是浏览器提供的一个组件,只需要在使用的地方添加一个类型(type)为date的输入框(input),即:,就可以得到出现日期的功能。 -
组件使代码具有模块化、可重用性、易于维护。
-
可以使用独立可复用的小组件来构建大型应用,很多款应用的页面都可以抽象成一棵组件树。如下图
一个项目中通常只有一个根组件,比如App(<App>)
组件。对于上图,根组件引用了layout组件,layout组件可以引用它的header、footer、content等组件。一些公共组件用于页面不同部分及不同页面的引用。一个项目中只有一个实例化对象,就是new Vue的实例。如下代码:
new Vue({ el: document.getElementById('app'), components: { // 声明要用的组件们 // key 是组件名,value 是组件对象,es6写法可省略key ComA, ComB, }, template: ` <div> <ComA> <ComA/> <ComB> <ComB/> </div> ` })
2.组件注册
子组件注册成功以后才可以在父组件中引用。
-
全局注册
注册组件的时候,我们要给它一个组件名称,如注册一个全局组件语法格式如下:Vue.component(componentName, options)
componentName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
<componentName></componentName>
全局组件在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。
-
局部注册
在实例选项中注册局部组件,这样组件只能在这个实例中使用。称为局部组件。<div id="app"> <ComponentA ></ComponentA > </div> <script> var ComponentA= { template: '<h1>局部注册组件!</h1>' } // 创建根实例 new Vue({ el: '#app', components: { ComponentA, } }) </script>
在 ES2015+ 中,在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写。
局部注册的组件在其子组件中不可用。
例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, }
3.创建一个组件
-
我在Vue中创建一个button组件,button.vue组件部分代码如下:
<template lang="html"> <div class="btn"> <div class="btn-header">   btn title</div> <div class="btn-body">  btn body</div> <div class="btn-content">  btn content</div> </div> </template> <script> export default { } </script> <style> .btn{ width: 500px; margin: 0 auto; } .btn-header{ height: 50px; background-color: blue; } .btn-body{ height: 50px; } .btn-content{ height: 50px; background-color: red; } </style>
在App.vue中使用组件,使用方式如下:
<template> <div id="app" class="container"> //引用组件<Button/> <Button/> </div> </template> <script> //通过webpack 使用 ES2015 import模块导入组件 import Button from "./components/button.vue" export default { name: 'App', //components中定义想要使用的组件 components: { Button, } } </script>
一个简单的组件需要一个名称(name,比如上例中的Button )作为元素的标签和由该标签渲染的模板(
<template>
)。
效果如下:
4.父子通信props
组件通信:父组件向子组件传递数据使用props。
-
介绍属性
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 。
在Vue中,组件通过props接收外部数据。
-
在button组件上添加了
Props
,在模板template
中使用{{title1}}、{{title2}}、{{title3}}
给html元素动态的传值,从而取代了之前的静态文本。如下代码:button.vue文件
<!--button.vue文件--> <template lang="html"> <div class="btn"> <div class="btn-header">{{title1}}</div> <div class="btn-body">{{title2}}</div> <div class="btn-content">{{title3}}</div> </div> </template> <script> export default { name: "button", props: ["title1","title2","title3"], //data()必须是函数 data() { return {}; } } </script>
App.vue文件:
<template> <div id="app" class="container"> <Button v-for="(item, index) in titleList" :title1="item.title1" :title2="item.title2" :title3="item.title3" :key="index"/> </div> </template> <script> import Button from "./components/button.vue" export default { name: 'App', components: { Button, }, // data() { return { titleList:[ { title1:'first', title2: "i am the first title", title3: "i am the first2 title", }, { title1:'second', title2: "i am the second title", title3: "i am the second2 title", }, { title1:'three', title2: "i am the three title", title3: "i am the three2 title", }] } } } </script>
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用
v-for、 v-bind
动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件。上面代码运行效果为:
-
【注意:】
prop 是单向绑定的,即单向数据流,当父组件的属性变化时,将传导给子组件,但是不会反过来。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。 -
prop 除了可以接收数组形式的值,还可以是对象形式。实际上任何类型的值都可以传给一个 prop。
如果希望每个 prop 都有指定的值类型。可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型:props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise // or any other constructor }
-
禁用特性继承。
如果你不希望组件的根元素继承特性,可以在组件的选项中设置inheritAttrs: false
。例如:Vue.component('my-component', { inheritAttrs: false, // ... })
inheritAttrs: false
选项不会影响 style 和 class 的绑定
5.父子通信$ref
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。——出自Vue官方文档
对官方文档的解释:
-
如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素即通过$ref可能获取到该DOM 的属性集合,继而访问到DOM元素,作用与jquary筛选器类似。
-
如果ref用在子组件上,引用就指向组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。
如下ref用在子组件的例子:
App.vue文件<template> <div id="app" class="container"> <Button ref="msg"/> </div> </template> <script> import Button from "./components/button.vue" export default { name: 'App', components: { Button, }, mounted:function(){ console.log(this.$refs.msg); this.$refs.msg.getMessage('$refs引用子组件')//减少获取dom节点的消耗 }, } </script>
子组件button.vue文件:
<template lang="html"> <!--模板要有一个根节点--> <div class="btn"> <div class="btn-header"><p>{{message}}</p></div> <p>{{message}}</p> </div> </template> <script> export default { name: "button", //props: ["title1","title2","title3"], //data()必须是函数 data() { return { message:'' } }, methods:{ getMessage(m){ this.message=m; } } } </script>
上方代码通过
ref=‘msg'
将子组件button的实例指给$ref
,并且通过.msg.getMessage()
调用子组件的getMessage()
方法,然后成功将参数传递给子组件。实现了父组件向子组件间的通信。
代码运行效果如下:
打印的this.$refs.msg
内容,便于看到$ref
获取的内容。
$ref使用过后发现取DOM、操作DOM十分方便。prop
和$ref
之间有些许差别:- 1.
prop
侧重数据的传递,不能调用子组件里的属性和方法。 - 2.
$ref
侧重索引,主要用来调用子组件里的属性和方法,其实并不擅长数据传递。而且ref
用在dom元素的时候,能起到选择器的作用,这个功能比作为索引更常用。
- 1.
6.子组件向父组件通信$emit
props
和$refs
属性都是用于父组件向子组件传值,实现父子通信。而子组件向父组件传递数据使用$emit
。$emit
用于触发当前实例上的事件,通过事件传递数据给父组件。
父组件App.vue文件
<template>
<div id="app" class="container">
<h2>{{message}}</h2>
<!--通过v-on绑定子组件getMessage方法,并为其赋值为showMessage方法-->
<Button v-on:getMessage="showMessage"/>
</div>
</template>
<script>
import Button from "./components/button.vue"
export default {
name: 'App',
components: {
Button,
},
//data()必须是函数
data() {
return {
message:''
}
},
methods:{
showMessage(m){
this.message=m;
}
},
}
</script>
子组件button.vue文件:
<template lang="html">
<!--模板要有一个根节点-->
<div class="btn">
<h2>我是子组件,我的内容会通过$emit传给父组件。</h2>
</div>
</template>
<script>
export default {
name: "button",
//props: ["title1","title2","title3"],
mounted:function(){
console.log(this.$emit);
this.$emit('getMessage','我是父组件,这是通过$emit从子组件获得。')
},
}
</script>
代码运行效果为:
子组件主要通过事件传递数据给父组件,如打印的this.$emit
结果为event事件函数,如下:
7.实现子向子组件的通信
Vue 没有直接子组件对子组件传递数据的方法,如若事项,是先把数据传到父组件,然后再由父组件传给相应的子组件。Vue 推出了一个状态管理工具 Vuex,可以很方便实现组件之间的参数传递。如果你有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享。可以参考vuex官方教程
【待续】
每天进步一点点、快乐一点点、充实一点点、加油!@girl