element 實現自定義表格列
阿新 • • 發佈:2020-08-09
在我們開發PC端的專案使用表單時,尤其是crm系統,應該經常會遇到這樣的需求, 使用者需要根據設定來自定義顯示列。 查了element的官方文件, 並沒有此類元件, 所以手動封裝了一個簡單的元件, 希望能在大家開發此類需求時能夠有所幫助。
效果圖
具體效果圖如下:
自定義顯示列 (可實現拖拽進行排序,點選選中,再次點選取消選中)
按照使用者已設定好的欄位排序/顯示/隱藏每一列
setTable元件
首先實現拖拽排序的話我們需要藉助一個外掛:
npminstallvuedraggable-S
具體的元件程式碼如下, 程式碼內已寫有詳細的註釋,在這裡就不過多贅述了。。
setTable.vue
<template>
<div>
<el-dialogtitle="自定義顯示列":visible.sync="dialogVisible"width="50%">
<divclass="select-menusmenus-box">
<pclass="menus-title">拖動區塊調整顯示順序</p>
<divclass="menus-content">
<draggablev-model="selected"@update="datadragEnd":options="{animation:500}">
<transition-group>
<divv-for="menuinselected" :key="menu.field"class="drag-itemitem">{{menu.name}}</div>
</transition-group>
</draggable>
</div>
</div>
<divclass="menus-containermenus-box"v-if="fields.length">
<pclass="menus-title">選擇顯示列</p>
<divclass="menus-content">
<div
class="item"
:class="{active:menu.active}"
v-for="menuoffields"
:key="menu.field"
@click="onSelect(menu)"
>{{menu.name}}</div>
</div>
</div>
<span slot="footer"class="dialog-footer">
<el-button@click="dialogVisible=false">取消</el-button>
<el-buttontype="primary"@click="onSave">確定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
importdraggablefrom"vuedraggable";
import{getFields,setFields,getFieldControl}from"@/api/user";
exportdefault{
name:"setTable",
inject:["reload"],
props:{
types:String,
},
components:{
draggable,
},
data(){
return{
dialogVisible:false,
fields:[],//全部選單
selected:[],//已選中選單
};
},
watch:{
selected:{
handler(oldVal,newVal){
if(this.fields.length===0){
return;
}
newVal.map((i)=>{
this.fields.map((j)=>{
if(i.field===j.field){
//如果已選中陣列內已有相同欄位,則active為true。active主要用來控制全部選單選中/未選中的樣式
j.active=true;
}
});
});
},
},
},
mounted(){
//為了防止火狐瀏覽器拖拽的時候以新標籤開啟
document.body.ondrop=function(event){
event.preventDefault();
event.stopPropagation();
};
},
methods:{
asyncgetData(){
//獲取全部選單資料
const{data:fields}=awaitgetFields({
types:this.types,
});
fields.map((item)=>{
//由於伺服器並沒有返回active欄位,為此需要每一條資料增加active欄位,來控制選中的樣式
item.active=false;
});
this.fields=fields;
},
asyncgetFields(){
//獲取使用者已選中的選單,為了再次開啟設定時能夠把上次選中選單回顯到頁面,方便使用者再次修改
letfields=awaitgetFieldControl({
account_id:this.$store.state.user.token.account_id,
userid:this.$store.state.user.token.userid,
types:this.types,
});
this.$nextTick(()=>{
this.selected.push(...fields.data);
});
},
asynconSave(){
//儲存已選中選單
awaitsetFields({
account_id:this.$store.state.user.token.account_id,
userid:this.$store.state.user.token.userid,
types:this.types,
content:this.selected,
});
this.reload();//重新整理頁面
},
asyncopen(){
//開啟設定視窗時清空資料,並再次請求獲取最新資料
this.fields=[];
this.selected=[];
this.dialogVisible=true;
awaitthis.getData();
awaitthis.getFields();
},
onSelect(item){
//判斷已選中選單內是否已有點選選擇的選單
letfindex=this.selected.findIndex((i)=>{
returnitem.field===i.field;
});
if(findex===-1){
//如果已選中選單內沒有,則新增到最後一條
this.selected.push(item);
}else{
//如果已選中已有,則點選時應該對其移除,並把active設定為false,改變其選中的樣式
item.active=false;
this.selected.splice(findex,1);
}
},
datadragEnd(evt){
//拖動排序
evt.preventDefault();
},
},
};
</script>
<stylelang="scss"scoped>
/*全部選單*/
.menus-container{
margin-top:20px;
.menus-content{
.item{
color:#575757;
background:rgba(238,238,238,1);
border:1pxsolidrgba(220,220,220,1);
border-radius:2px0px0px2px;
}
}
}
/*選單通用樣式*/
.menus-box{
.menus-title{
margin-top:10px;
line-height:32px;
}
.menus-content{
display:flex;
flex-wrap:wrap;
.item{
cursor:pointer;
display:inline-flex;
align-items:center;
justify-content:center;
padding:8px;
margin:10px;
border-radius:3px;
}
.active{
color:#fff;
background:rgba(72,153,229,1);
border-radius:2px0px0px2px;
}
}
}
/*已選選單*/
.select-menus{
.menus-content{
.item{
margin:0px;
border-radius:0;
background:rgba(255,255,255,1);
border:1pxsolidrgba(220,220,220,1);
}
}
}
</style>
使用
具體使用如下, 在這裡已經隱去不必要的業務程式碼, 只把最核心實現的程式碼貼了出來, 以免對大家產生誤導..
<template>
<div>
<el-table
ref="multipleTable"
:data="tableData"
height="60vh"
:row-class-name="tableRowClassName"
@selection-change="handleSelectionChange"
@row-click="handleRead"
>
<el-table-columntype="selection"min-width="55px;"></el-table-column>
<templatev-for="(item,index)offields">
<el-table-column
v-if="item.field==='name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='gender'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<templateslot-scope="scope">{{scope.row.gender===1?'男':'女'}}</template>
</el-table-column>
<el-table-column
v-if="item.field==='corp_full_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='corp_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="12%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='up_date'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='position'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='remark_mobiles'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='source_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='address'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='detail_address'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='description'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='remark'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='recordContent'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='owner_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='follow_time'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<templateslot-scope="scope">
<divv-if="scope.row.follow_time===scope.row.createtime">暫無</div>
<divv-else>{{scope.row.follow_time|formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='next_follow_time'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<templateslot-scope="scope">
<divv-if="scope.row.next_follow_time===0">暫無</div>
<divv-else>{{scope.row.next_follow_time|formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='createtime'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<templateslot-scope="scope">
<div>{{scope.row.createtime|formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='updatetime'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<templateslot-scope="scope">
<div>{{scope.row.updatetime|formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='is_record'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
>
<templateslot-scope="scope">
<div>{{scope.row.is_record===0?'未跟進':'已跟進'}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='if_record'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
</template>
<el-table-columnlabel="操作"min-width="8%;">
<templateslot-scope="scope">
<el-button@click="handleRead(scope.row)"type="text">詳情</el-button>
</template>
</el-table-column>
<el-table-columnalign="right"min-width="4%;">
<templateslot="header">
<iclass="iconfonticongengduo"@click="onMore"></i>
</template>
</el-table-column>
</el-table>
<set-tableref="setting"types="leads"></set-table>
</div>
</template>
<script>
importsetTablefrom"@/components/setTable";
import{getFieldControl}from"@/api/user";
exportdefault{
name:"clues",
components:{
setTable,
},
data(){
return{
fields:[],
};
},
asyncmounted(){
awaitthis.getFields();
this.clues();
},
methods:{
asyncgetFields(){
letfields=awaitgetFieldControl({
account_id:this.$store.state.user.token.account_id,
userid:this.$store.state.user.token.userid,
types:"leads",
});
this.fields=fields.data;
},
onMore(){
this.$refs.setting.open();
},
},
};
</script>
在這裡其實也可以設定成固定的列寬或者通過伺服器返回具體的尺寸, 這樣的話就不用寫這麼多的if語句了, 會更加方便簡潔..
結束語
其實剛接到這個需求時,感覺挺複雜的, 尤其是需要進行拖動, 還要根據伺服器返回不同的欄位來進行表單列的排序。 但整體做下來並沒有我想象的那麼麻煩。 大家在遇到需求時, 也一定不要一直想的太多, 一定要先去嘗試, 說不定它並沒有你想的那麼難..