一、 组件component
1. 什么是组件?
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码
组件是自定义元素(对象)
2. 定义组件的方式
方式1:先创建组件构造器,然后由组件构造器创建组件
var mycomponent=Vue.extend({
template:''
})
Vue.component('组件名',mycomponent)
方式2:直接创建组件
Vue.component('组件名',{
template:''
})
3. 组件的分类
分类:全局组件、局部组件
全局组件:
Vue.component('组件名',{
template:''
})
局部组件:
在vue实例中写components:{
mycomponent: {
template:'',
data() {
return {}
}
}
}
4. 引用模板
将组件内容放到模板<template>中并引用
html:
<template id='template'>
<div></div>有且只有一个根元素
</template>
vue:
Vue.component('组件名',{
template: '#template'
})
5. 动态组件
<component :is="">组件 多个组件使用同一个挂载点,然后动态的在它们之间切换
如:
<div id="itany">
<button @click="flag='my-hello'">显示hello组件</button>
<button @click="flag='my-world'">显示world组件</button>
<div>
<keep-alive>
<component :is="flag"></component>
</keep-alive>
</div>
</div>
<script>
var vm=new Vue({
el:'#itany',
data:{
flag:'my-hello'
},
components:{
'my-hello':{
template:'<h3>我是hello组件:{{x}}</h3>',
data(){
return {
x:Math.random()
}
}
},
'my-world':{
template:'<h3>我是world组件:{{y}}</h3>',
data(){
return {
y:Math.random()
}
}
}
}
});
</script>
<keep-alive>
<component></component>
</keep-live> 使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建
二、 组件间数据传递
1. 父子组件
在一个组件内部定义另一个组件,称为父子组件
子组件只能在父组件内部使用
默认情况下,子组件无法访问父组件中的数据,每个组件实例的作用域是独立的
父组件调用子组件需要在父组件的template中调用即:
<template>
<h1>我是父组件</h1>
<my-word></my-word>
</template>
2. 组件间数据传递 (通信)
2.1 子组件访问父组件的数据
a)在调用子组件时,绑定想要获取的父组件中的数据
b)在子组件内部,使用props选项声明获取的数据,即接收来自父组件的数据
总结:父组件通过props向下传递数据给子组件
注:组件中的数据共有三种形式:data、props、computed
如:
父组件:
html部分:<my-hello :msg='msg'></my-hello>
vue: data(){ return { msg: 'lll'}}
子组件:
html部分: {{msg}}
vue: props:{ ['msg']} 接收父组件传递的值
props注:
props的type是对象或者数组默认值必须使用函数的形式来返回
props:{
name: {
type: String,
default: '默认值',
required: true,
validator(){}
}
}
2.2 父组件访问子组件的数据
a)在子组件中使用vm.$emit(事件名,数据)触发一个自定义事件,事件名自定义
b)父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
总结:子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
父组件:
html:
<h1>{{msg}}</h1>
<my-word @e-word="getData"></my-word>
vue:
methods:{
getData(msg){ this.msg=msg}
}
子组件:
html:
<button @click="sendData">发送数据</button>
vue:
methods:{
sendData(){
this.$emit('e-word',this.msg)
}
}
3. 单向数据流
props是单向绑定的,当父组件的属性变化时,将传导给子组件,但是不会反过来
而且不允许子组件直接修改父组件中的数据,报错
解决方式:
方式1:如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
如:
父组件:
html:
<my-hello :age="age"></my-hello>
子组件:
html:<button @click='change'>改变值</button>
vue:
new Vue({
data:{
uage:this.age
},
props: ['age'],
methods:{
change(){
this.uage=18
}
}
})
方式2:如果子组件想修改数据并且同步更新到父组件,两个方法:
a.使用.sync(1.0版本中支持,2.0版本中不支持,2.3版本又开始支持)
需要显式地触发一个更新事件
父组件:
html:
<my-hello :name.sync="name" ></my-hello>
子组件:
html:
<h1>{{name}}</h1>
<button @click='change'></button>
vue:
props:['name'],
methods:{
change(){
this.$emit('update:name','alice')
}
}
b.可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性(因为对象是引用类型,指向同一个内存空间),推荐
父组件:
html:
<my-word :user='user'></my-word>
vue:
data(){
return{
user:{
name: 'karry',
age: 18
}
}
}
子组件:
html:
<h1>{{user.name}}</h1>
<button @click="change"></button>
vue:
props:['user']
methods:{
change(){
this.user.name='roy'
}
}
4. 非父子组件间的通信
非父子组件间的通信,可以通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件
var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});
<div id="itany">
<my-a></my-a>
<my-b></my-b>
<my-c></my-c>
</div>
<template id="a">
<div>
<h3>A组件:{{name}}</h3>
<button @click="send">将数据发送给C组件</button>
</div>
</template>
<template id="b">
<div>
<h3>B组件:{{age}}</h3>
<button @click="send">将数组发送给C组件</button>
</div>
</template>
<template id="c">
<div>
<h3>C组件:{{name}},{{age}}</h3>
</div>
</template>
<script>
var Event=new Vue();
var A={
template:'#a',
data(){
return {
name:'tom'
}
},
methods:{
send(){
Event.$emit('data-a',this.name);
}
}
}
var B={
template:'#b',
data(){
return {
age:20
}
},
methods:{
send(){
Event.$emit('data-b',this.age);
}
}
}
var C={
template:'#c',
data(){
return {
name:'',
age:''
}
},
mounted(){
Event.$on('data-a',name => {
this.name=name;
});
Event.$on('data-b',age => {
this.age=age;
});
}
}
var vm=new Vue({
el:'#itany',
components:{
'my-a':A,
'my-b':B,
'my-c':C
}
});
</script>
三、 slot内容分发
本意:位置、槽
作用:用来获取组件中的原内容,类似angular中的transclude指令
<style>
.s2{
width:100px;
background:red;
margin-left:10%;
}
</style>
<body>
<div id="itany">
<my-hello>
<ul slot="s1">
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<ol slot="s2">
<li>111</li>
<li>222</li>
<li>333</li>
</ol>
</my-hello>
</div>
<template id="hello">
<div>
<div class="s2">
<slot name="s2"></slot>
</div>
<h3>welcome to itany</h3>
<slot name="s1"></slot>
</div>
</template>
<script>
var vm=new Vue({
el:'#itany',
components:{
'my-hello':{
template:'#hello'
}
}
});
</script>
</body>