效果描述:点击输入框弹出table面板,面板包括标题、列表分页、检索条件、确定取消安钮、单选全选框。面板回显已选中条目,切换页时仍能显示。
思路:组件中包括面板整体样式、标题 、按钮、分页组件;页面中将搜索条件、th、tr用slot传入组件模板中,形成每页的table。监听面板打开关闭的变量进行重新渲染,点击确定时页面父组件监听事件传出选中条目的数组,符合条件则执行面板关闭及后续。点击检索按钮时通过this.$refs.comName.method(‘tag’);调用组件内检索方法、改变组件内检索条件。
技能点:主要为slot使用方法以及业务梳理,合理提取组件。外表及方法共用,仅传入url和检索条件,确定时传出选定数组。若为多个table且表头不同,则在一个父组件内通过变量控制显示与数组赋值。slot用v-if控制显示(不可v-show,此属性为控制dom元素display属性),不可出现同名slot,但slot内可用template显示不同的html内容。 slot-scope=" " 为vue2.5+中写法。
<table class="table table-hover table-bordered">
<tbody>
<slot name="ths"></slot>
<slot name="item"
v-for="item in items"
:item="item">
</slot>
</tbody>
</table>
<tr slot="ths">
<th>ID</th>
<th>Project</th>
<th>Version</th>
</tr>
html中的组件外框公共模板
<script type="text/template" id="table-wrapper">
<!--弹出面板-->
<div class="modal fade" tabindex="-1" style="z-index:99999;" id="modal-table">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header no-padding">
<div class="table-header">
<button type="button" class="close" aria-hidden="true" @click="closeAssocModal">
<span class="white">×</span>
</button>
{{title}}
</div>
</div>
<div class="modal-body no-padding"style="min-height:445px">
<div class="staff-search">
<slot name="search-condition"></slot>
</div>
<table class="table table-striped table-bordered table-hover no-margin-bottom no-border-top">
<thead>
<slot name="ths"></slot>
</thead>
<tbody>
<tr v-for="(item,index) in items"
:item="item" :class="{ isSelected: item.isSelected }" @click="pushItem(item,index)">
<slot name="item" :item="item"></slot>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer no-margin-top">
<button class="btn btn-sm btn-danger pull-left" @click="closeAssocModal">
<i class="ace-icon fa fa-times"></i>
关闭
</button>
<button class="btn btn-sm btn-success pull-left" @click="addItems()">
<i class="ace-icon fa fa-times"></i>
确认
</button>
<ul class="pagination pull-right no-margin">
<navigation :pages="employeePages" :current.sync="employeePageNo" @navpage="employeePageList" ref="associNavigation"></navigation>
</ul>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
<loading class="associationLayer" v-show="associationLayer"></loading>
</div>
</script>
页面内代码
<template>
<ttable-wrapper :title="'企业检索'" @add-items="confirmAssociation" @close-asso-modal="closeAssoModal" ref="association" :if-add-employee="ifAddAssociateItems" :selected-items="selectedAssoItems" :url="''">
<template slot="search-condition">
<div class="form-group col-sm-10">
<label class="col-sm-4 control-label no-padding-right">企业名称:</label>
<div class="col-sm-8">
<input type="text" autocomplete="off" maxlength="20" class="col-sm-9" v-model="enterName" @keyup.enter="getEnterList()">
<button @click="getEnterList()" class="btn btn-primary col-sm-2 tbl-search"><i class="ace-icon fa fa-search"></i></button>
</div>
</div>
</template>
<template slot="ths">
<tr>
<th class="center" >
<label class="position-relative">
<input type="checkbox" class="ace association-check-all" @click="checkedAllAssoc">
<span class="lbl"></span>
</label>
</th>
<th>企业名称</th>
<th>负责人</th>
<th>联系方式</th>
</tr>
</template>
<template slot="item" scope="scope">
<td class="td-center" style="cursor: pointer;"><label class="position-relative"><input type="checkbox" class="ace" :checked="scope.item.isSelected"> <span class="lbl"></span></label></td>
<td>
{{scope.item.name}}
</td>
<td>
{{scope.item.leader}}
</td>
<td>
{{scope.item.telephone}}
</td>
</template>
</table-wrapper>
</template>
组件封装
Vue.component("table-wrapper",{
data:function(){
return {
employeePageNo:1, //当前页
employeePages:0, //总共页数
employPageSize:10,
senddata:{},
items:[], //table列表数据
associationLayer:false,//loading标志
tempSelectedItems:[], //组件内确定时外传数据
};
},
props:["title","ifAddEmployee","url","selectedItems"],//面板标题、监听打开面板、地址、数据、选中项
template:'#table-wrapper',
methods:{
//点击分页页码
employeePageList:function(curPage) {
if(curPage){
this.employeePageNo = curPage;
this.getEmployeeList();
}
},
//点击确定按钮 添加
addItems:function(){
this.$emit("add-items",this.tempSelectedItems);
},
//点击关闭按钮时
closeAssocModal:function(){
this.$emit("close-asso-modal");// 替换data-dismiss="modal"
},
//获取table列表
getEmployeeList:function(tag){
var This = this;
var url = This.url;
var data = This.senddata;
if(tag){
data.pageNum = 1;
This.employeePageNo = 1;
}else{
data.pageNum = This.employeePageNo;
}
data.pageSize = This.employPageSize;
ajax('post',url,data,function(response){
This.associationLayer = false;//关闭等待框
if(response.code==1){
var list = response.data.records||response.data;
if(list.length>0){
$.each(list,function (index,item) {//选中数组渲染与回显
item.isSelected = false;
$.each(This.tempSelectedItems,function(eindex,dispatchItem){
if(item.id==dispatchItem.id){
item.isSelected = true;
}
});
});
This.items = list;
This.employeePages = response.data.pages || Math.ceil(response.data.totalCount/This.employPageSize) ||Math.ceil(response.totalCount/This.employPageSize);
}else{
var msg = "未检索到相关内容";
errorMsgTip(msg);
}
}
});
if(tag){
var pageNum = data.current||data.pageNum;
this.$refs.associNavigation.goPage(pageNum);//分页组件首页点击效果
}
$(".association-check-all").prop("checked", false);
},
//面板中选择 新增或删除
pushItem:function(item,index){
/*添加删除*/
event.preventDefault();
item.isSelected = !item.isSelected;
var This = this;
if(item.isSelected){
This.tempSelectedItems.push(item);
}else{
var items = This.tempSelectedItems;
for(var i=items.length-1;i>=0;i--){
if(item.id === items[i].id){ //索引值为选中数组中的索引值
This.tempSelectedItems.splice(i,1);
}
}
}
},
//全选 页面传递全选标志
checkedAllAssoc:function(event){
var ifChecked = event.target.checked;
var This = this;
if(ifChecked){
$.each(This.items,function (index,item) {
item.isSelected = true;//显示
var flag = false;
$.each(This.tempSelectedItems,function(indexSelected,itemSelected){
if(itemSelected.id == item.id){
flag = true;//已选定数组中已存在
return false;
}
});
if(!flag){//未存在则存入
This.tempSelectedItems.push(item);
}
});
}else{
$.each(this.items,function (index,item) {
item.isSelected = false;
$.each(This.tempSelectedItems,function(indexSelected,itemSelected){
if(itemSelected.id == item.id){
This.tempSelectedItems.splice(i,1);
return false;
}
});
});
}
}
},
watch: {
ifAddEmployee:function(curVal,oldVal){
if(curVal){
var This = this;
this.senddata = {};
this.getEmployeeList('search');//初始搜索 条件空、页码1
this.associationLayer = true;
this.tempSelectedItems = [];
$.each(this.selectedItems,function(index,item){
This.tempSelectedItems.push(item);
});
}
}
}
})
参考:Vue实战(六)通用Table组件