国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - 如何封裝Vue Element的table表格組件

如何封裝Vue Element的table表格組件

2022-01-17 17:02豫見陳公子 vue.js

這篇文章主要介紹了如何封裝Vue Element的table表格組件,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下

在封裝Vue組件時,我依舊會交叉使用函數式組件的方式來實現。關于函數式組件,我們可以把它想像成組件里的一個函數,入參是渲染上下文(render context),返回值是渲染好的HTML(VNode)。它比較適用于外層組件僅僅是對內層組件的一次邏輯封裝,而渲染的模板結構變化擴展不多的情況,且它一定是無狀態、無實例的,無狀態就意味著它沒有created、mounted、updated等Vue的生命周期函數,無實例就意味著它沒有響應式數據data和this上下文。

我們先來一個簡單的Vue函數式組件的例子吧,然后照著這個例子來詳細介紹一下。

?
1
2
3
4
5
6
7
export default {
 functional: true,
 props: {},
 render(createElement, context) {
   return createElement('span', 'hello world')
 }
}

Vue提供了一個functional開關,設置為true后,就可以讓組件變為無狀態、無實例的函數式組件。因為只是函數,所以渲染的開銷相對來說較小。

函數式組件中的Render函數,提供了兩個參數createElement和context,我們先來了解下第一個參數createElement。

createElement說白了就是用來創建虛擬DOM節點VNode的。它接收三個參數,第一個參數可以是DOM節點字符串,也可以是一個Vue組件,還可以是一個返回字符串或Vue組件的函數;第二個參數是一個對象,這個參數是可選的,定義了渲染組件所需的參數;第三個參數是子級虛擬節點,可以是一個由createElement函數創建的組件,也可以是一個普通的字符串如:'hello world',還可以是一個數組,當然也可以是一個返回字符串或Vue組件的函數。

createElement有幾點需要注意:

  • createElement第一個參數若是組件,則第三個參數可省略,即使寫上去也無效;
  • render函數在on事件中可監聽組件$emit發出的事件
  • 在2.3.0之前的版本中,如果一個函數式組件想要接收prop,則props選項是必須的。在2.3.0或以上的版本中,你可以省略props選項,組件上所有的attribute都會被自動隱式解析為prop。

函數式組件中Render的第二個參數是context上下文,data、props、slots、children以及parent都可以通過context來訪問。

在2.5.0及以上版本中,如果你使用了單文件組件,那么基于模板的函數式組件可以這樣聲明:<template functional></template>, 但是如果Vue組件中的render函數存在,則Vue構造函數不會從template選項或通過el選項指定的掛載元素中提取出的HTML模板編譯渲染函數,也就是說一個組件中templete和render函數不能共存,如果一個組件中有了templete,即使有了render函數,render函數也不會執行,因為template選項的優先級比render選項的優先級高。

到這里,Vue函數式組件介紹的就差不多了,我們就來看看Element的表格組件是如何通過函數式組件來實現封裝的吧。

效果圖:

如何封裝Vue Element的table表格組件

1、所封裝的table組件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<template>
 <div>
  <el-table :data="cfg.data" style="width: 100%" v-on="cfg.on" v-bind="attrs" v-loading="loading">
   <el-table-column v-if="cfg.hasCheckbox" v-bind="selectionAttrs" type="selection" width="55" label="xx" />
   <el-table-column v-for="n in cfg.headers" :prop="n.prop" :label="n.label" :key="n.prop" v-bind="{...columnAttrs, ...n.attrs}">
    <template slot-scope="{row}">
     <slot :name="n.prop" :row="row"><Cell :config="n" :data="row" /></slot>
    </template>
   </el-table-column>
  </el-table>
  <el-pagination
   class="pagination"
   v-if="showPage"
   layout="total, sizes, prev, pager, next, jumper"
   :page-sizes="[2, 3, 6, 11]"
   :page-size="page.size"
   :total="page.total"
   :current-page="page.page"
   @current-change="loadPage"
   @size-change="sizeChange"
  />
 </div>
</template>
 
<script>
import Cell from './cell'
 
export default {
 components: {
  Cell,
 },
 props: {
  config: Object,
 },
 data(){
  return {
   loading: true,
   columnAttrs: {
    align: 'left',
    resizable: false,
   },
   cfg: {
    on: this.getTableEvents(),
    attrs: {
     border: true,
           stripe: true,
    },
    data: [],
    ...this.config,
   },
   page: {
    size: this.config.size || 10,
    page: 1,
    total: 0,
   },
   checked: [],
  }
 },
 created(){
  this.load();
 },
 computed: {
  selectionAttrs(){
   let {selectable, reserveSelection = false} = this.config || {}, obj = {};
   // checkBox是否可以被選中
   if(selectable && typeof selectable == 'function'){
    Object.assign(obj, {
     selectable,
    })
   }
   //reserve-selection僅對type=selection的列有效,類型為Boolean,為true則會在數據更新之后保留之前選中的數據(需指定 row-key)
   if(reserveSelection){
    Object.assign(obj, {
     'reserve-selection': reserveSelection,
    })
   }
 
   return obj;
  },
  attrs(){
   let {config: {spanMethod, rowKey}, cfg: {attrs}} = this;
   // 合并單元格 - spanMethod是父組件傳過來的合并單元格的方法,請參照element合并單元格
   if(spanMethod && typeof spanMethod == 'function'){
    Object.assign(attrs, {
     'span-method': spanMethod,
    })
   }
   // 表格跨頁選中,需要設置row-key和reserve-selection,reserve-selection只能且必須設置在type為selection的el-table-column上
   if(rowKey && typeof rowKey == 'function'){
    Object.assign(attrs, {
     'row-key': rowKey,
    })
   }
 
   return attrs;
  },
  showPage(){
   let {size, total} = this.page;
   return size < total;
  },
 },
 methods: {
  getTableEvents(){
   let {hasCheckbox = false} = this.config || {}, events = {}, _this = this;
   if(hasCheckbox){
    // 綁定事件
    Object.assign(events, {
     'selection-change'(v){
        _this.checked = v;
     },
    });
   }
 
   return events;
  },
  // 獲取勾選的行
  getChecked(){
   return this.checked;
  },
  // 請求數據
  load(p = {}){
   let { size, page } = this.page, {loadData = () => Promise.resolve({})} = this.config;
   this.loading = true;
   // 這里loadData的參數在初始化時只有分頁所需的page和size,至于接口需要的其他參數,是在父組件的loadData中傳遞
   loadData({...p, page, size}).then(({data, total}) => {
    this.cfg.data = data;
    this.page.page = page;
    this.page.total = total;
    this.loading = false;
   });
  },
  loadPage(index){
   this.page.page = index
   this.load();
  },
  sizeChange(size){
   this.page.size = size
   this.load();
  },
  // 一般在點擊查詢按鈕或局部刷新表格列表時,可調用此方法,如果不傳參數,則默認從第一頁開始
  reload(p = {}){
   this.page.page = 1
   this.load(p);
  },
 },
}
</script>

2、匯總表格每一列的cell.js:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import * as Components from './components';
let empty = '-'
export default {
 props: {
  config: Object,
  data: Object,
 },
 functional: true,
 render: (h, c) => {
  let {props: {config = {}, data = {}}} = c, {prop, type = 'Default'} = config, value = data[prop] || config.value, isEmpty = value === '' || value === undefined;
  return isEmpty ? h(Components.Default, {props: {value: empty}}) : h(Components[type], {props: {value, empty, data, ...config}});
 }
}

3、本次封裝將每一列的渲染單獨分開成多個vue組件,最后再合并在一個components.js文件中一起進行匹配。

1)整合文件components.js:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Date     from './Date';
import Default   from './Default';
import Currency   from './Currency';
import Enum     from './Enum';
import Action    from './Action';
import Link     from './Link';
import Format    from './Format';
import Popover   from './Popover';
 
export {
 Default,
 Date,
 Currency,
 Enum,
 Action,
 Link,
 Format,
 Popover,
}

2)日期列Date.vue

?
1
2
3
<template functional>
  <span>{{props.value | date(props.format)}}</span>
</template>

3)默認列Default.vue

?
1
2
3
<template functional>
  <span>{{props.value}}</span>
</template>

4)金額千分位列Currency.vue

?
1
2
3
<template functional>
  <span>{{props.value | currency}}</span>
</template>

5)映射列Enum.js

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
let mapIdAndKey = list => list.reduce((c, i) => ({...c, [i.key]: i}), {});
 
let STATUS = {
  order: mapIdAndKey([
    {
      id: 'draft',
      key: 'CREATED',
      val: '未提交',
    },
    {
      id: 'pending',
      key: 'IN_APPROVAL',
      val: '審批中',
    },
    {
      id: 'reject',
      key: 'REJECT',
      val: '審批駁回',
    },
    {
      id: 'refuse',
      key: 'REFUSE',
      val: '審批拒絕',
    },
    {
      id: 'sign',
      key: 'CONTRACT_IN_SIGN',
      val: '合同簽署中',
    },
    {
      id: 'signDone',
      key: 'CONTRACT_SIGNED',
      val: '合同簽署成功',
    },
    {
      id: 'lendDone',
      key: 'LENDED',
      val: '放款成功',
    },
    {
      id: 'lendReject',
      key: 'LOAN_REJECT',
      val: '放款駁回',
    },
    {
      id: 'cancel',
      key: 'CANCEL',
      val: '取消成功',
    },
    {
      id: 'inLend',
      key: 'IN_LOAN',
      val: '放款審批中',
    },
  ]),
  monitor: mapIdAndKey([
    {
      key: '00',
      val: '未監控',
    },
    {
      key: '01',
      val: '監控中',
    },
  ]),
}
 
export default {
  functional: true,
  render(h, {props: {value, Enum, empty}, parent}){
    let enums = Object.assign({}, STATUS, parent.$store.getters.dictionary),
      {name = '', getVal = (values, v) => values[v]} = Enum, _value = getVal(enums[name], value);
      
    if( _value === undefined) return h('span', _value === undefined ? empty : _value);
 
    let {id, val} = _value;
    return h('span', {staticClass: id}, [h('span', val)]);
  }
}

6)操作列Action.js

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const getAcitons = (h, value, data) => {
 let result = value.filter(n => {
  let {filter = () => true} = n;
  return filter.call(n, data);
 });
 
 return result.map(a => h('span', {class: 'btn', on: {click: () => a.click(data)}, key: a.prop}, a.label))
}
 
export default {
 functional: true,
 render: (h, {props: {value, data}}) => {
  return h('div', {class: 'action'}, getAcitons(h, value, data))
 },
}

7)帶有可跳轉鏈接的列Link.vue

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
 <router-link :to="{ path, query: params }">{{value}}</router-link>
</template>
 
<script>
export default {
 props: {
  data: Object,
  value: String,
  query: {
   type: Function,
   default: () => {
    return {
     path: '',
     payload: {}
    }
   }
  },
 },
 computed: {
  // 路由path
  path(){
   const { path } = this.query(this.data)
   return path
  },
  params(){
   const { payload } = this.query(this.data)
   return payload
  },
 },
}
</script>

8)自定義想要展示的數據格式Format.vue

?
1
2
3
<template functional>
 <div v-html="props.format(props.value, props.data)" />
</template>

9)當內容過多需要省略并在鼠標移入后彈出一個提示窗顯示全部內容的列Popover.vue

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template functional>
 <el-popover
  placement="top-start"
  width="300"
  trigger="hover"
  popper-class="popover"
  :content="props.value">
  <span slot="reference" class="popover-txt">{{props.value}}</span>
 </el-popover>
</template>
<style scoped>
.popover-txt{
 overflow:hidden;
 text-overflow:ellipsis;
 white-space:nowrap;
 display: block;
 cursor: pointer;
}
</style>

從以上代碼中可以看出,我既使用了基于render函數類型的函數式組件也使用了基于模板的函數式組件,主要是為了在封裝時的方便,畢竟使用render這個最接近編譯器的函數還是有點麻煩的,不如基于模板的函數式組件來的方便。

4、使用封裝后的表格table組件

1)不使用插槽:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<template>
 <div style="margin: 20px;">
  <el-button type="primary" v-if="excelExport" @click="download">獲取勾選的表格數據</el-button>
  <Table :config="config" ref="table" />
 </div>
</template>
 
<script>
import Table from '@/components/table'
 
export default {
 components: {
  Table,
 },
 data() {
  return {
   config: {
    headers: [
     {prop: 'contractCode', label: '業務編號', attrs: {width: 200, align: 'center'}},
     {prop: 'payeeAcctName', label: '收款賬戶名', type: 'Link', query: row => this.query(row), attrs: {width: 260, align: 'right'}},
     {prop: 'tradeAmt', label: '付款金額', type: 'Currency'},
     {prop: 'status', label: '操作狀態', type: 'Enum', Enum: {name: 'order'}},
     {prop: 'statistic', label: '預警統計', type: 'Format', format: val => this.format(val)},  //自定義展示自己想要的數據格式
     {prop: 'reason', label: '原因', type: 'Popover'},
     {prop: 'payTime', label: '付款時間', type: "Date", format: 'yyyy-MM-dd hh:mm:ss'},  //不設置format的話,日期格式默認為yyyy/MM/dd
     {prop: 'monitorStatus', label: '當前監控狀態', type: 'Enum', Enum: {name: 'monitor'}},
    ].concat(this.getActions()),
    //通過接口獲取列表數據 - 這里的參數p就是子組件傳過來的包含分頁的參數
    loadData: p => request.post('permission/list', {...this.setParams(), ...p}),
    hasCheckbox: true,
    selectable: this.selectable,
    reserveSelection: false,
    rowKey: row => row.id,
   },
   status: "01",
   permission: ["handle", "pass", "refuse", "reApply", 'export']
  }
 },
 computed: {
  handle() {
   return this.permission.some(n => n == "handle");
  },
  pass() {
   return this.permission.some(n => n == "pass");
  },
  reject() {
   return this.permission.some(n => n == "reject");
  },
  refuse() {
   return this.permission.some(n => n == "refuse");
  },
  excelExport(){
   return this.permission.some(n => n == "handle") && this.permission.some(n => n == "export");
  },
 },
 methods: {
  getActions(){
   return {prop: 'action', name: '操作', type: "Action", value: [
    {label: "查看", click: data => {console.log(data)}},
    {label: "辦理", click: data => {}, filter: ({status}) => status == 'CREATED' && this.handle},
    {label: "通過", click: data => {}, filter: ({status}) => status == 'PASS' && this.pass},
    {label: "駁回", click: data => {}, filter: ({status}) => status == 'REJECT' && this.reject},
    {label: "拒絕", click: data => {}, filter: ({status}) => status == 'CREATED' && this.refuse},
   ]}
  },
  setParams(){
   return {
    name: '測試',
    status: '01',
    type: 'CREATED',
   }
  },
  query(row){
   return {
    path: '/otherElTable', // 路由path
    payload: {
     id: row.id,
     type: 'link'
    }
   }
  },
  format(val){
   let str = '';
   val.forEach(t => {
    str += '<span style="margin-right:5px;">' + t.total + '</span>';
   })
   return str;
  },
  selectable({status}){
   return status == "REFUSE" ? false : true
  },
  download(){
   console.log(this.$refs.table.getChecked())
  },
 },
};
</script>
<style>
.action span{margin-right:10px;color:#359C67;cursor: pointer;}
</style>

2)使用插槽:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<Table :config="config" ref="table">
  <template #statistic="{row}">
   <div v-html="loop(row.statistic)"></div>
  </template>
  <template #payeeAcctName="{row}">
   {{row.payeeAcctName}}
  </template>
  <template #tradeAmt="{row}">
   {{row.tradeAmt | currency}}
  </template>
  <template v-slot:reason="{row}">
   <template v-if="!row.reason">-</template>
   <el-popover
    v-else
    placement="top-start"
    width="300"
    trigger="hover"
    popper-class="popover"
    :content="row.reason">
    <span slot="reference" class="popover-txt">{{row.reason}}</span>
   </el-popover>
  </template>
  <template #payTime="{row}">
   {{row.payTime | date('yyyy-MM-dd hh:mm:ss')}}
  </template>
  <template #customize="{row}">
   {{customize(row.customize)}}
  </template>
  <template #opt="{row}">
   <div class="action">
    <span>查看</span>
    <span v-if="row.status == 'CREATED' && handle">辦理</span>
    <span v-if="row.status == 'PASS' && pass">通過</span>
    <span v-if="row.status == 'REJECT' && reject">駁回</span>
    <span v-if="row.status == 'REFUSE' && refuse">拒絕</span>
   </div>
  </template>
 </Table>
 
<script>
import Table from '@/components/table'
 
export default {
 components: {
  Table,
 },
 data(){
  return {
   config: {
    headers: [
     {prop: 'contractCode', label: '業務編號', attrs: {width: 200, align: 'center'}},
     {prop: 'payeeAcctName', label: '收款賬戶名', attrs: {width: 260, align: 'right'}},
     {prop: 'tradeAmt', label: '付款金額'},
     {prop: 'status', label: '操作狀態', type: 'Enum', Enum: {name: 'order'}},
     {prop: 'statistic', label: '預警統計'},
     {prop: 'payTime', label: '付款時間'},
     {prop: 'reason', label: '原因'},
     {prop: 'monitorStatus', label: '當前監控狀態', type: 'Enum', Enum: {name: 'monitor'}},
     {prop: 'customize', label: '自定義展示', type: 'Format', format: val => this.customize(val)},
     {prop: 'opt', label: '操作'},
    ],
    loadData: () => Promise.resolve({
     data: [
      {id: 1, contractCode: '', payeeAcctName: '中國銀行上海分行', tradeAmt: '503869.265', status: '00', payTime: 1593585652530,
       statistic:[
        {level: 3, total: 5},
        {level: 2, total: 7},
        {level: 1, total: 20},
        {level: 0, total: 0}
       ],
       customize: ['中國', '上海', '浦東新區']
      },
      {id: 2, contractCode: 'GLP-YG-B3-1111', payeeAcctName: '中國郵政上海分行', tradeAmt: '78956.85', status: 'CREATED', payTime: 1593416718317,
       reason: 'Popover的屬性與Tooltip很類似,它們都是基于Vue-popper開發的,因此對于重復屬性,請參考Tooltip的文檔,在此文檔中不做詳盡解釋。',
      },
      {id: 3, contractCode: 'HT1592985730310', payeeAcctName: '招商銀行上海支行', tradeAmt: '963587123', status: 'PASS', payTime: 1593420950772, monitorStatus: '01'},
      {id: 4, contractCode: 'pi239', payeeAcctName: '廣州物流有限公司', tradeAmt: '875123966', status: 'REJECT', payTime: 1593496609363},
      {id: 5, contractCode: '0701001', payeeAcctName: '建設銀行上海分賬', tradeAmt: '125879125', status: 'REFUSE', payTime: 1593585489177},
     ],
    }),
   },
   permission: ["handle", "pass", "refuse", "reApply", 'export'],
  }
 },
 computed: {
  handle() {
   return this.permission.some(n => n == "handle");
  },
  pass() {
   return this.permission.some(n => n == "pass");
  },
  reject() {
   return this.permission.some(n => n == "reject");
  },
  refuse() {
   return this.permission.some(n => n == "refuse");
  },
  excelExport(){
   return this.permission.some(n => n == "handle") && this.permission.some(n => n == "export");
  },
 },
 methods: {
  query(row){
   return {
    path: '/otherElTable',  // 路由path
    payload: {
     id: row.id,
     type: 'link'
    }
   }
  },
  loop(val){
   if(!val) return '-'
   let str = '';
   val.forEach(t => {
    str += '<span style="margin-right:5px;">' + t.total + '</span>';
   })
   return str;
  },
  customize(v){
   return v ? v[0] + v[1] + v[2] : '-'
  }
 }
}
</script>

在兩個不太相同的使用方式中,第一種是不基于插槽實現的,第二種是基于插槽實現的。通過兩種方式的對比,可以看出在第二種使用方式中,但凡是使用了插槽的列,在headers數組中其已經不再定義type字段了,即使定義了type,它也不起作用,起作用的是插槽,而且也不再使用concat去拼接一個操作列了,操作列也是通過插槽來渲染的,只是如果很多列都通過插槽的形式實現,私心覺得頁面看起來就不那么整潔了。

多說一句,既然我們已經對大部分場景的實現進行了封裝,那么大家在使用時就沒必要再通過插槽的形式去多此一舉了,盡量保持頁面的整潔。如果你實在覺得在headers數組后邊再concat一個操作列的方式有點別扭,那么就只需將操作列通過插槽的形式去實現就OK了。本博客中提到的插槽實現形式,只是為了給大家多一種選擇而已。

最后,關于金額千分位和時間戳格式化的實現,這里就不再貼代碼了,可自行實現。

最近又想了一下封裝的這個table組件,想著說在原來封裝的基礎上還有沒有其他的實現方法,比如我不想在原來定義的headers數組后邊再concat一個操作列,再比如表格的某一列的數據處理方法不包含在我們之前所封裝的那些方法當中,或者說作為第一次使用這個table組件的前端開發人員,我不太習慣你的那種寫法,那我可不可以在你封裝的基礎上自己寫一些處理方法呢,答案是可以的,當然我們說既然已經封裝好了組件,那么大家就按照一個套路來,省時又省力,何樂而不為呢?但有一說一,我們本著學習的態度,本著藝多不壓身的出發點來看的話,多學多思考多動手,總歸是有益于進步的。只是在實際的開發過程中,我們盡量要選擇一種封裝方式,然后大家一起遵守這個約定就好了。

其實說了這么多廢話,這次變更也是沒有多大力度的,只是在原來封裝的基礎上增加了插槽而已。看過本篇博客的你一定還記得我封裝的代碼中有一段專門用來處理每一列數據的代碼吧:
<Cell :config="n" :data="row" />
對,就是它。對于它,我不想再多說了,上邊已經做了介紹了。本次變更,我們主要用到的是插槽。

插槽這個API,VUE的官網和網上的各種文章介紹已經講的很清楚了,它大概分為:默認插槽(也有人管它叫匿名插槽)、具名插槽和作用域插槽。關于它們的介紹,請自行查閱官網或網上的各種文章資料。本次變更主要用到的就是具名插槽和作用域插槽。具名插槽,顧名思義就是帶有名稱的插槽,我們本次封裝所使用的插槽的名稱來自于table的每一列的prop。作用域插槽在本次封裝中的作用主要就是通過子組件的插槽向父組件傳值,其實現形式有點類似于vue父組件向子組件傳值,只不過兩者的接收值的方式不同??傊舜巫兏鼘崿F起來還是很簡單的,就是在<Cell :config="n" :data="row" />的外邊再包一層具名插槽就可以了。
<slot :name="n.prop" :row="row"><Cell :config="n" :data="row" /></slot>
就醬。

接下來,我們就可以回答上邊我們提出的那些問題了。來看答案:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Table :config="config" ref="table">
  <template #payTime="{row}">
   {{row.payTime | date('yyyy-MM-dd hh:mm:ss')}}
  </template>
  <template #customize="{row}">
   {{customize(row.customize)}}
  </template>
  <template #opt="{row}">
   <div class="action">
    <span>查看</span>
    <span v-if="row.status == 'CREATED' && handle">辦理</span>
    <span v-if="row.status == 'PASS' && pass">通過</span>
    <span v-if="row.status == 'REJECT' && reject">駁回</span>
    <span v-if="row.status == 'REFUSE' && refuse">拒絕</span>
   </div>
  </template>
</Table>

以上就是對某些特殊情況,而你又不想使用我最開始封裝的那些方法來實現,那么可以,我就再為你提供一個其他的“特殊服務”。這里要注意,如果你使用插槽來自己渲染數據,那么在headers數組中,你需要提供表格頭部的渲染,而不需要再加入type字段即可。
比如最開始渲染表格的日期列時我們是這么寫的:
{prop: 'payTime', label: '付款時間', type: "Date", format: 'yyyy-MM-dd hh:mm:ss'}
那么如果你使用插槽來自己渲染數據,這里的寫法就要變成了這樣:
{prop: 'payTime', label: '付款時間'}
還有之前我們定義操作列是在headers數組的后邊再concat了一個數組,如果你使用插槽來自己渲染數據,那么就不需要再concat一個數組了,而是在headers數組中再加一個{prop: 'opt', label: '操作'}就可以了。

其實,這次變更說的是在原來的基礎上重新包裝了一層插槽,那么對于那些不需要我們自行處理數據,只需直接展示接口返回的數據的情況,我們在使用這個封裝的table組件時也不需要進行什么特殊處理,更不需要像上邊使用插槽那樣去定義,只要還是跟之前一樣在headers數組中正常定義就可以了。因為插槽嘛,你不定義具名插槽,也不定義默認插槽,那么插槽中顯示的就是包裹在插槽標簽slot中的<Cell :config="n" :data="row" />
明白了吧。

多說一句,你說我不想使用插槽去處理日期、金額千分位這些列,那么你依舊可以根據上邊我介紹的插槽的原理,在headers數組中依舊這樣定義就OK了:

?
1
2
{prop: 'tradeAmt', label: '付款金額', type: 'Currency'},
{prop: 'payTime', label: '付款時間', type: "Date"},

寫到這里,其實我想說,即使加上了插槽,那么對之前的那些使用方法來說,基本沒啥影響,你該怎么用還怎么用,我只是給你提供了更多的選擇而已。

如果你實在不想用插槽,想保持頁面的整潔,那你在<Cell :config="n" :data="row" />這段代碼的外面包裹不包裹一層插槽都無所謂,直接使用上文中我介紹的第一種使用方法就可以了。

作者:小壞

出處:http://tnnyang.cnblogs.com

以上就是如何封裝Vue Element的table表格組件的詳細內容,更多關于封裝Vue Element的table表格組件的資料請關注服務器之家其它相關文章!

原文鏈接:https://www.cnblogs.com/tnnyang/p/13523699.html

延伸 · 閱讀

精彩推薦
  • vue.js用vite搭建vue3應用的實現方法

    用vite搭建vue3應用的實現方法

    這篇文章主要介紹了用vite搭建vue3應用的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.jsVue2.x 項目性能優化之代碼優化的實現

    Vue2.x 項目性能優化之代碼優化的實現

    這篇文章主要介紹了Vue2.x 項目性能優化之代碼優化的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優小U9632022-02-21
  • vue.jsVue項目中實現帶參跳轉功能

    Vue項目中實現帶參跳轉功能

    最近做了一個手機端系統,其中遇到了父頁面需要攜帶參數跳轉至子頁面的問題,現已解決,下面分享一下實現過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.jsVue2.x-使用防抖以及節流的示例

    Vue2.x-使用防抖以及節流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
主站蜘蛛池模板: 天堂中文网 | 亚洲一区在线日韩在线深爱 | 久久国产精品久久 | 午夜精品久久久久久久久久久久久 | 日韩精品91爱爱 | 狠狠艹| 日韩欧美精品在线 | 日韩一区二区在线观看 | 久色 | 久久久久久亚洲精品视频 | 99精品欧美一区二区三区 | 久久久精品 | 夜夜操天天操 | 国产一级片 | 婷婷色国产偷v国产偷v小说 | 激情久久久 | 色综合天天综合网国产成人网 | 国产精品免费一区二区 | 午夜电影网址 | 色猫猫国产区一区二在线视频 | 久久亚洲一区二区三区明星换脸 | 中文字幕在线精品 | 噜噜噜噜狠狠狠7777视频 | 91精品视频免费在线观看 | 国产四区 | 久久久高清| 伊人伊人| 色噜噜视频 | 色香阁99久久精品久久久 | 久久精品国产99 | 欧美一区二区三区在线看 | 久久免费精品 | 刘亦菲的毛片 | 欧美精品在欧美一区二区少妇 | 中国黄色三级毛片 | 国内精品一区二区 | 国产成人精品一区二区三区视频 | www.99| 国产精品99久久免费观看 | 亚洲欧美另类在线 | 一区二区三区在线观看国产 |