1 组件与复用
通过使用组件,实现代码复用。需求变更需要修改功能时,只需要修改一处即可完全修改。但是当一个组件复用的次数变多后,不同的功能就会因为组件耦合在一起。遇到需要针对单个功能进行修改组件的时候,就需要慎之又慎,防止对其他功能造成影响。
vue组件创建
<div>
<test></test>
</div>
Vue.component('test',{
template:'<div>测试</div>'
})
以上是定义在页面内部的组件。但是我通常使用webpack结构的工程,组件直接定义成一个单独的*.vue文件,当需要使用组件时直接在对应的页面通过import关键字引入,然后注册在components属性中。
vue文件格式如下
<template>
<div></div>
</template>
<script>
//这里可以使用import引入方法、对象、组件等等,或者定义方法、属性
export defaut{
//这里定义组件相关的属性。包括数据、方法、生命周期函数、父组件传入数据、组件名等
}
</script>
一个template中最多只能有一层div,其他的元素都需要定义在该div中。另外如果没有export关键字,组件无法被其他的页面调用。组件的data属性需要定义成function的形式,data中定义的数据只对当前组件有效。当组件被复制了多份,组件之间的数据相互独立,如果需要进行数据共享可以将数据定义在外部。
外部调用组件的时候还可以通过is关键字将dom元素替换为组件定义的元素。
2 组件传值
2.1 父组件向子组件传值
当一个组件中调用另一个组件,则前者被称为父组件,后者称为子组件。父组件通过props关键字传值到子组件,如果不用v-bind绑定则该值只会被传一次,不会数据双向绑定(即父组件的数据如果改变了,不会对已经渲染后的子组件产生效果)。不用v-bind还会导致传入的值的数据类型变成String。
<test msg="message"></test>
<test :msg="message"></test>
<template>
<div>{{msg}}</div>
</template>
<script>
export default{
props:[msg]
//props:{
// msg:String,
// hasMes:[Boolean,Number],
// msgDetail:{
// type:Array,
// required:true
// }
//}
}
子组件的props属性可以定义为数组或者对象。定义为对象时,需要设置传入字段的数据类型,数据类型可以定义多个。
• String
• Number
• Boolean
• Object
• Array
• Function
props属性传值,默认是从父到子组件单向的。vue1的时候,可以通过.sync关键字双向绑定,当时vue2取消了这个。
2.2 子组件向父组件传值
子组件通过 e m i t 函 数 将 数 据 提 交 到 父 组 件 。 emit函数将数据提交到父组件。 emit函数将数据提交到父组件。emit方法有两个参数,第一个是字符串,代表事件名,第二个是提交的数据。当父组件中定义了v-on对应的事件后,可以直接使用方法获取子组件提交的值。
<test @submit="sumbitValue"></test>
methods:{
submitValue(value){
console.log(value);
}
}
this.$emit('submit',123);
$emit也可以提交input事件,父组件中使用v-model来将子组件中的值绑定到父组件的值上。
2.3 非父子组件之间传值
vue1的时候,定义了
d
i
s
p
a
t
c
h
(
)
和
dispatch()和
dispatch()和broadcast(),分别用于向上级、下级进行广播事件,事件发出后按就近原则被该方向上最近的组件捕获,且被接受一次后就停止广播。Vue2的时候把这些都废除了,按树形结构传值理解不方便且不能解决同级组件之间传值的问题。
vue2推出了bus的方式,通过创建一个空的vue实例(bus,中央事件总线)用于管理所有事件。所有事件通过bus进行寻找或者接受事件。
var bus = new Vue();
bus.$emit('submit',123);
bue.$on('submit',function(value){
console.log(value);
})
当协同开发时,需要共享值或者方法等等,可以使用bus。但是eventbus这个东西也差不多不怎么用到,我用vuex插件会比较多一些。
还可以通过以下两个函数直接获取父子组件,从而获取并修改其中的值。但是这样会导致逻辑混乱,各个组件之间耦合在一起。所以最好还是通过props和$emit传值。
this.$parent().message
this.$children()
因为子组件可能有多个,所以$children函数用起来不是很方便。
为了精确定位子组件,还有一个$ref函数。
<test ref = "child"></test>
this.$refs.child.message="i am a child";
$refs 渲染完成后才填充,并且它是非响应式的. 它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用。
3 内容分发slot
当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到slot, 这个过程叫作内容分发(transclusion)
<child-component>
{{message }}
</child-component>
这里的message是一个slot,绑定父组件的数据。当父组件定义了slot,子组件的内容中如果定义了元素就会被替代掉。slot可以定义name属性,当父组件中指定了slot属性后,子组件就会根据slot关联替换对应的元素。
<div slot="footer">底部信息</div>
<slot name = "footer"></slot>
slot还可以通过props来传值。
<child-component>
<p>{{ props.msg }}</p>
</child-component>
<slot msg="来自子组件的内容"></slot>
4 组件递归
组件可以递归调用自己本身,但是需要设置name属性,并且搭配v-if限制递归次数。
5内联模板
组件标签可以添加inline-template属性,从而将内容当做模板,而不将内容分发。在父组件中声明的数据message和子组件中声明的数据msg,两个都可以渲染(如果同名,优先使用子组件的数据)。
这是内联模板的缺点,作用域比较难理解,如果不是非常特殊的场景,不要轻易使用内联模板。
6 动态组件
通过is属性,可以实现组件动态切换。
<component :is="currentView"></component>
components:{
comA:{
template:"<div>A</div>"
},
comB:{
template:"<div>B</div>"
}
}
change:funciton(componentName){
this.currentView = componentName;
}
7 异步组件
组件可以通过resolve,reject方法实现异步加载。但是有了webpack和.vue类型的文件,直接写路由会更加方便。
8 $nextTick
vue会异步更新dom元素,$nextTick能在异步更新完毕后执行js。主要用于搭配第三方库,我主要用到swiper,echarts。