vue系列组件篇(二)
概述
vue
组件是vue
常用的功能,vue
也因为强大的组件功能得到很多开发者的青睐。一个好的组件,可以提供给开发者很多方便,特别是复用代码,代码一致性等。
本文通过实现一个列表my-list
组件,来讲解组件的用法和特性。
下面先看一下工程目录:
<div align=center>
![](https://img.haomeiwen.com/i13377572/6f571e8f7411feab.png)
整个工程可以在git上下载:点击下载,其中蓝色线条标记的,分别是我们这次用到的页面和组件。
组件引入
组件引入分全局引入和局部引入,顾名思义,全局引入可以在任何一个路由页面使用该组件,而局部引入是在引入页面才能使用。
import myList from '../components/my-list'
//全局引入
Vue.component('my-list',myList)
export default {
name: "componentStudy",
data: function () {
return {}
},
//局部引入,写法很灵活
components:{myList},
methods: {},
mounted: function () {
},
computed: {},
created: function () {
}
}
上面的代码的2中写法分别是全局引入和局部引入,整体来说,像分页组件,下拉框组件,表格组件等大多数页面都用得上的可以全局引入,像tab页面,特殊按钮等用的比较的少的页面可以采用局部引用。
组件传值
我们的列表组件,各个页面的数据不一样,这些数据往往是通过引入改组件的页面决定的,那么意味着,这些数据应该是从父组件传到子组件的,下面我们给我们的列表组件传一个dataList
(数据)和一个clickFunction
(点击每一项的触发函数)。vue
通过prop
子组件传值,这里传值可以是js
所有类型。
//文件componentSutdy.vue
<my-list :data-list="dataList" :click-fun="clickFunction"></my-list>
data: function () {
return {
dataList:[
{title:'携手打造更加紧密的中非命运共同体',content:'9月3日,2018年中非合作论...'},
{title:'“小眼镜”牵动大情怀',content:'近日,习近平总书记就青少年视力健...'},
{title:'倡议五周年之际',content:'2013年9月7日,国家主席习...'},
]
}
},
methods: {
clickFunction(item){
console.log(item)
}
},
//文件my-list.vue
<template>
<div class="my-list">
<ul>
<li class="list-group-item" v-for="(item,index) in dataList" @click="clickFun(1)">
<div class="main-title" v-text="item.title"></div>
<div class="content" v-text="item.content"></div>
</li>
</ul>
</div>
</template>
//子组件接收父组件传过来的值
props:{
dataList:{
type:[Array,Object], // 类型校验,多个可能的类型
require:true, //是否必传
default:function () { //默认值, 对象或数组默认值必须从一个工厂函数获取
return []
},
// //自定义校验
// validator: function (value) {
// // 这个值必须匹配下列字符串中的一个
// return ['success', 'warning', 'danger'].indexOf(value) !== -1
// }
},
clickFun:{
type: Function,
require: false
}
},
![](https://img.haomeiwen.com/i13377572/d8d2820152ca418f.png)
可以看到,子组件使用
propos
接收了父组件传过来的dataList
和clickFun
2个变量。注意传递形式就是vue常见语法v-bind来传递。试着点击列表,可以看到父组件的方法cliFun被调用了,并且接收到了子组件传过来的变量。
上面的例子,完成了父组件向子组件传递参数,子组件调用父组件方法。
子组件调用父组件方法
和其他框架一下,vue在子组件无法直接通过this.的方式调到父组件的方法,这里vue提供的是$emit的方式来调用父组件的方法。我们修改上面的例子,让子组件点击按钮来删除一个列表,这里值得注意的是,vue组件直接传递参数是单向的,意思是,父组件传递过去的变量,只能在父组件被改变子组件是不能改变父组件传过来的这个变量的。不过可以通过赋值、计算属性等方式来重新定义一个变量。
修改部分的代码:
//文件componentSutdy.vue
//添加了@deleteItem的绑定
<my-list :data-list="dataList" :click-fun="clickFunction" @deleteItem="removeItem"></my-list>
//方法里面添加执行函数
removeItem(index){
this.dataList.splice(index,1)
}
//文件my-list.vue
//添加了$emit('deleteItem',index)"执行函数
<li class="list-group-item" v-for="(item,index) in dataList" @click="clickFun(1)">
<div class="main-title" v-text="item.title"></div>
<div class="content" v-text="item.content"></div>
<i class="el-icon-delete" @click="$emit('deleteItem',index)"></i>
</li>
![](https://img.haomeiwen.com/i13377572/92299825772815ca.png)
设置点击删除按钮,顺利删除了一行,可以看到,我们在父组件通过
deleteItem
传递了removeItem
函数给子组件,子组件通过$emit('deleteItem',index)
顺利调到了父组件的函数,并且传递了一个参数,父组件通过这个参数删除了用户点击的数据,这个过程完成了字段就调用父组件的方法,也说明了,子组件不要直接改变父组件传递过来的参数,因为这里是单向绑定的。
值得注意的是,字段就调用父组件的函数,有2种方式,稳重第一种是通过prop传递,第二种是通过@绑定来传递的,实际使用过程中,建议使用第二种方式。
父组件调用子组件方法
很多时候,我们需要字段就来执行某种操作,来达到页面效果,比如说,我们需要在用户点击之后,改变列表颜色,来切换主题。
//文件componentSutdy.vue,关键代码
<my-list :data-list="dataList" ref="myList" :click-fun="clickFunction" @deleteItem="removeItem"</my-list>
<el-button @click="changeTheme" style="margin-top: 20px;">切换主题</el-button>
changeTheme(){
this.$refs.myList.changeColor()
},
//文件my-list.vue,关键代码
<li class="list-group-item" :class="{'has-bg':isChange}" v-for="(item,index) in dataList" @click="clickFun(1)">
<div class="main-title" v-text="item.title"></div>
<div class="content" v-text="item.content"></div>
<i class="el-icon-delete" @click="$emit('deleteItem',index)"></i>
</li>
changeColor(){
this.isChange = true
}
![](https://img.haomeiwen.com/i13377572/e167132cb7844d99.png)
点击按钮,顺利改变了列表的背景颜色。这里,在引用组件的时候,我们通过
ref
给组件添加了一个命名:myList
,父组件点击切换主题,执行this.$refs.myList.changeColor()
,子组件changeColor
方法被调用,最终实现了转换主题,这里组件能单独命名,意味着同一个页面可以引用同一个组件多次,通过不同的命名,来单独操作,互不影响。
组件插槽
组件插槽是为了组件能有更灵活的使用,能让主页面在适当的字符插入自定义的html片段,先看一张图
![](https://img.haomeiwen.com/i13377572/1f01febd32bf350a.png)
我们想给每一行添加一个序号并且加粗,如果是组件里面固定的html结构,和明显难以实现,这里我们需要用到slot插槽功能。
//文件componentSutdy.vue,关键代码
<my-list :data-list="dataList" ref="myList" :click-fun="clickFunction" @deleteItem="removeItem">
<template slot="title" slot-scope="{item,index}">
<div>
<span v-text="`${index + 1}.`" style="font-weight: bold"></span>
<span v-text="item.title"></span>
</div>
</template>
</my-list>
//文件my-list.vue,关键代码
<li class="list-group-item" :class="{'has-bg':isChange}" v-for="(item,index) in dataList" @click="clickFun(1)">
<slot name="title" :item="item" :index="index">
<div class="main-title" v-text="item.title"></div>
</slot>
<div class="content" v-text="item.content"></div>
<i class="el-icon-delete" @click="$emit('deleteItem',index)"></i>
</li>
可以看到,我们在子页面,添加了
name="title"
的slot
插槽,并且通过绑定数据的方式传递了2个参数,item,index
,父组件,<template slot="title" slot-scope="{item,index}">
通过sole与字段就name匹配,来将html代码插入到对应的位置。这样主页面就轻松定制了新闻列表标题栏的html结构,当主页面不引入插槽是,将使用默认的html解析。这里接收参数的方式是采用es205的解构语法。
总结:关于vue组件就将到这里,相信上面的类容能涵盖到大多数用法,还有部分动态组件和异步组件不作讲解,实际使用中,用到很少,整个代码的源码可以在git:https://github.com/jackzhujie/vue-study.git上下载到。
最后想查看更多文章,可以关注我的个人公众号:
![](https://img.haomeiwen.com/i13377572/bd7c69392ac8190b.jpg)