组件
vue有两大核心内容:
-
指令
-
组件
组件
- 组件是一个 html css js img 等的一个聚合体
- 在vue中使用了一个叫做单文件的技术来实现组件
- 他是一个后缀名为.vue的文件,必须要经过编译后才可以运行
组件化
:使用具有独立功能的一个整体【组件】来进行项目开发的一个趋势
为什么要使用组件
- 他是一个后缀名为.vue的文件,必须要经过编译后才可以运行
-
为了避免多人开发造成的冲突
-
为了加快开发效率
-
为了遍历更新和维护
vue是通过Vue.extend()实现组件的
Vue如何实现组件?
1.通过实例化Vue构造器函数得到一个Vue实例。该实例叫‘根实例’,他是最大的父级
2.
这个根实例是以标签的形式存在的,那么我们也称之为’ 根组件 ’
-
根实例也是一个组件,但是我们得到只是根组件
-
Vue.extend() 它就是对Vue功能的扩展,这个扩展就是组件
-
Vue是通过 Vue.extend() 来实现【 扩展 】 Vue的功能的,这个功能就是组件
6.Vue.extend如何使用?
- 通过new Vue.extend() 发现和new Vue一样了 排除了
- 组件就是一个以标签化呈现的东西,所以我应该像标签一样使用
- 但是无论是 html3 还是 html5 肯定不会同意它随意来个标签的
- Vue会将组件编译成html结构
- Vue的这个处理过程,我们称之为 ’ 组件注册 '
总结:
- Vue是通过Vue.extend() 来实现组件的
- Vue的组件的使用时需要注册的
vue 使用组件
1.组件注册:
- 全局注册
- 局部注册
全局注册
格式: Vue.extend(options)
<body>
<div id="app">
<Hello></Hello>
<!-- <hello-boy></hello-boy> -->
</div>
</body>
const Hello = Vue.extend({
template:'<div> Hello </div>'
})
//vue.component( 组件的名称,组件的配置 )
// Vue.component( 'HelloBoy', Hello )
// Vue.component( 'hello-boy', Hello )
vue.component( ‘Hello’,Hello)
// vue组件注册的简写
Vue.component( 'Hello', {
template: '<div> Hello 组件 </div>'
})
new Vue({
el:‘#app’
})
局部注册
局部注册使用 components 来完成的
局部注册只在当前注册的实例范围内有效
<body>
<div id="app">
<Hello></Hello>
<hello></hello>
</div>
// root 里面的Hello不会被编译
<div id="root">
<Hello></Hello>
</div>
</body>
<script>
new Vue({
el: '#app',
components: {
//局部注册组件的选项
// 组件的名称: 组件的选项
'Hello': {
template: '<div> Hello 这里是局部注册 </div>'
}
}
})
new Vue({
el: '#root'
})
</script>
组件在父子级和有直接关系的标签中是不能被直接解析出来的,必须通过 is 属性来解决的
<body>
<div id="app">
<table border="1">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr is = "Hello"></tr>
</table>
</div>
</body>
<script>
Vue.component('Hello',{
template: ` <tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>`
})
new Vue({
el: '#app'
})
</script>
动态组件
案例:
点击切换两个组件
- template 写在实例范围内,会直接被解析,并且将来不会再html结构中出现
- template 模板内直接的子元素只有一个
- Vue内部提供了一个 component 组件
通过keep-alive组件实现动态组件的缓存,加快组件的切换速度
<body>
<div id="app">
<button @click = "typeChange"> 点击 </button>
<keep-alive>
<component :is = "type"></component>
</keep-alive>
</div>
<template id="hello-box">
<div>
<h3> 手机号登录 </h3>
<div> 123 </div>
</div>
</template>
</body>
<script>
new Vue({
el:'#app',
data:{
type:'PhoneLogin'
},
methods:{
typeChange(){
this.type=(this.type==='PhoneLogin')&&'UserLogin' || 'PhoneLogin'
}
},
components:{
'PhoneLogin':{
template:'#hello-box'
},
'UserLogin':{
template:'<div>用户名密码登录</div>'
}
}
})
</script>
- 组件的起名: 一定要避免和原生标签冲突 举例: Header header
-
- 大驼峰 HeadTitle 使用
-
- 小写横杠 head-title 使用
-
- 一个单词 Hello 使用 或者 【 推荐 】
组件通信
- 组件的嵌套
子组件以标签的形式要在父组件的模板中使用
<body>
<div id="app">
<Father>
<!-- <Son></Son> -->
</Father>
</div>
<template id="father">
<!-- 唯一根元素 -->
<div>
<h3> 这里是父组件 </h3>
<hr>
<Son></Son>
</div>
</template>
<template id="son">
<div>
<h3> 这里是子组件 </h3>
</div>
</template>
</body>
嵌套的两种写法:
<script>
new Vue({
el: '#app',
components: {
'Father': {
template: '#father',
components: {
'Son': {
template: '#son'
}
}
}
}
})
</script>
<script>
Vue.component('Father',{
template: '#father'
})
Vue.component('Son',{
template: '#son'
})
new Vue({
el: '#app'
})
</script>
- 组件中数据的定义
- 组件通信
数据中数据的定义
数据定义是一个函数的形式
1.为什么组件中的data选项是一个函数,而根实例中是对象呢?
原因:
- 组件是一个独立的整体,那么数据也应该是一个独立的
- javascript最大的特点,就是函数式编程,而函数本身就有一个独立的作用域
- 多人开发中,数据如果不独立那么数据就会冲突
2.为什么组件中的data函数要有返回值,并且返回值是一个对象
- 因为data选项要经过es5 Object.defineProperty属性进行getter和setter设置
3.数据中的数据的使用?
组件的数据,使用范围只能在组件模中
<body>
<div id="app">
<Hello></Hello>
</div>
<template id="hello">
<div>
{{ msg }}
</div>
</template>
</body>
<script>
Vue.component('Hello',{
template: '#hello',
data () {
return {
msg: '今天热的要死' // 组件的数据,使用范围只能在组件的模板中
}
}
})
new Vue({
el: '#app'
})
</script>
组件通信
父子组件通信
- props选项
- props可以是一个对象
- props中的validator函数
- props第三方属性验证:vue-validator-help
1.父组件中定义一个数据
Vue.component('Father',{
template: '#father',
data () {
return {
money: 3000
}
}
})
2.在父组件的模板中,用v-bind将父组件的数据绑定在子组件身上
<Son :aa = "money"></Son>
其中aa是自定义的属性
<template id="father">
<div>
<h3> 这里是父组件 </h3>
<hr>
<Son :aa = "money"></Son>
</div>
</template>
3.在子组件的选项中,通过props选项来接收属性
Vue.component('Son',{
template: '#son',
props: ['aa']
// props: {
// 'aa': Number //属性验证
// }
// props: {
// 'aa': {
// validator ( val ) {
// return val > 2000
// }
// }
// }
})
4.此时,该属性就可以在子组件的模板中以全局变量的形式使用了
<template id="son">
<div>
<h4> 这里是子组件 </h4>
<p> 老爸给了我 {{ aa }} 生活费 </p>
</div>
</template>
子父组件通信
- 自定义事件 this.$emit
流程如下:
1.先在子组件中定义一个数据
Vue.component('Son',{
template: '#son',
data () {
return {
money: 1000
}
}
})
2.在父组件中·定义一个数据,这个数据用来接收子组件传递过来的数据
Vue.component('Father',{
template: '#father',
data () {
return {
bank: 1000
}
}
})
3.在父组件中定义一个事件处理程序,用于改变父组件定义的数据,这个事件处理程序的参数就是子组件传递过来的数据
Vue.component('Father',{
template: '#father',
data () {
return {
bank: 1000
}
},
methods: {
bankAdd ( val ) { //val就是子组件给的数据
this.bank += val
}
}
})
4.将这个事件处理程序通过事件绑定的形式绑定在父组件里面的子组件身上
<template id="father">
<div>
<h3> 这里是父组件 </h3>
<p> 我的私房钱有: {{ bank }} </p>
<hr>
<Son @aa = "bankAdd"></Son>
</div>
</template>
5.在子组件中定义一个事件处理程序,这个事件处理程序选中通过,this.$emit来触发自定义事件,并传递一个参数给父组件
Vue.component('Son',{
template: '#son',
data () {
return {
money: 1000
}
},
methods: {
give () {
// this.$emit('aa',传递给父组件的参数)
this.$emit('aa',this.money)
}
}
})
<template id="son">
<div>
<h4> 这里是子组件 </h4>
<button @click = " give "> 给老爸红包 </button>
</div>
</template>
非父子组件通信
- ref
- bus事件总线
1.首先定义三个组件
<script>
Vue.component('Father',{
template: '#father',
})
Vue.component('Son',{
template: '#son',
})
Vue.component('Girl',{
template: '#girl',
})
</script>
- 打造对应的三个模板
<template id="father">
<div></div>
</template>
<template id="girl">
<div></div>
</template>
<template id="son">
<div>
<img>
</div>
</template>
- 在父模板中嵌套子女模板
<template id="father">
<div>
<Girl></Girl>
<Son></Son>
</div>
</template>
4.女孩身上绑定一个动作,用按钮表示:
<button>揍弟弟</button>
5.在son组件中定义数据(让图片显示的数据)和 事件处理程序 让我们通过执行方法来显示图片
data () {
return {
flag: false
}
}
methods: {
cry () {
this.flag = true
}
}
6.绑定图片的flag
<img v-if = "flag" style = "width: 100px;height: 100px;" src="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1564471527&di=2c4707955cefb24c325842ea288b9647&src=http://b-ssl.duitang.com/uploads/item/201702/16/20170216145320_wyNiK.jpeg" alt="">
- 在父组件里通过 ref 关键字 绑定了一个son(取名自定义)
<Son ref = "son"></Son>
8.在父组件里面写一个方法触发cry
methods: {
emitCry () {
this.$refs.son.cry()
}
}
9.动作是girl在做,所以应该吧触发cry得方法传给 父模板中的 girl
<Girl :fn = "emitCry"></Girl>
10.girl接收父组件传来的方法用props接收
Vue.component('Girl',{
template: '#girl',
props: ['fn']
})
11.然后girl直接用该方法
<button @click = "fn"> 揍弟弟 </button>
1.通过bus串联两个组件:
var bus = new Vue()
2.还是相应的定义方法
Vue.component('Son',{
template: '#son',
data () {
return {
flag: false
}
},
methods: {
cry () {
this.flag = true
}
},
})
<img style = "width: 100px;height: 100px;" v-if = "flag" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564481613744&di=22ebae5b3c4655691a1244e46682d7c9&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201702%2F16%2F20170216145320_wyNiK.jpeg" alt="">
给son添加 mounted方法
mounted 这个方法是自动执行的,只要组件创建它,他就会自动执行
mounted() { //这个选项表示组件挂载结束 这个方法时自定执行,只要组件创建,它就自动执行
// bus.$on(自定义事件的名称,自定义事件的处理程序)
var _this = this
bus.$on('aa', function() { // 通过$on自定义一个叫做aa的事件
_this.cry()
})
}
在girl组件里触发事件:
Vue.component('Girl', {
template: '#girl',
methods: {
kick() {
bus.$emit('aa')
}
}
})