JS元件系列——自己動手擴充套件BootstrapTable的treegrid功能
前言
上一篇 JS元件系列——自己動手封裝bootstrap-treegrid元件 博主自己動手封裝了下treegrid的功能,但畢竟那個元件只是一個單獨針對樹形表格做的,適用性還比較有限。關注博主的小夥伴應該知道,博主的部落格裡面寫了很多bootstrapTable的擴充套件,今天打算在直接在bootstrapTable的基礎上擴充套件一個treegrid的功能,很多長期關注博主部落格的小夥伴一直在問我怎麼在bootstrapTable裡面直接使用treegrid的功能,所以今天還是帶來點福利。有興趣的可以捧個人場!
本文原創地址:JS元件系列——自己動手擴充套件BootstrapTable的trefgrid功能
一、效果預覽
全部摺疊
展開一級
全部展開
二、程式碼示例
怎麼樣?效果還行吧。給出js的原始碼供大家參考。
(
function
(
$
)
{
‘use strict’
;
var
sprintf
=
function
(
str
)
{
var
args
=
arguments
,
flag
=
true
,
i
=
1
;
str
=
str
。
replace
(
/%s/g
,
function
()
{
var
arg
=
args
[
i
++
];
if
(
typeof
arg
===
‘undefined’
)
{
flag
=
false
;
return
‘’
;
}
return
arg
;
});
return
flag
?
str
:
‘’
;
};
var
getFieldIndex
=
function
(
columns
,
field
)
{
var
index
=
-
1
;
$
。
each
(
columns
,
function
(
i
,
column
)
{
if
(
column
。
field
===
field
)
{
index
=
i
;
return
false
;
}
return
true
;
});
return
index
;
};
var
calculateObjectValue
=
function
(
self
,
name
,
args
,
defaultValue
)
{
var
func
=
name
;
if
(
typeof
name
===
‘string’
)
{
var
names
=
name
。
split
(
‘。’
);
if
(
names
。
length
>
1
)
{
func
=
window
;
$
。
each
(
names
,
function
(
i
,
f
)
{
func
=
func
[
f
];
});
}
else
{
func
=
window
[
name
];
}
}
if
(
typeof
func
===
‘object’
)
{
return
func
;
}
if
(
typeof
func
===
‘function’
)
{
return
func
。
apply
(
self
,
args
);
}
if
(
!
func
&&
typeof
name
===
‘string’
&&
sprintf
。
apply
(
this
,
[
name
]。
concat
(
args
)))
{
return
sprintf
。
apply
(
this
,
[
name
]。
concat
(
args
));
}
return
defaultValue
;
};
var
getItemField
=
function
(
item
,
field
)
{
var
value
=
item
;
if
(
typeof
field
!==
‘string’
||
item
。
hasOwnProperty
(
field
))
{
return
item
[
field
];
}
var
props
=
field
。
split
(
‘。’
);
for
(
var
p
in
props
)
{
value
=
value
[
props
[
p
]];
}
return
value
;
};
var
getParent
=
function
(
node
,
source
,
field
)
{
var
data
=
[];
var
items
=
$
。
grep
(
source
,
function
(
item
,
index
)
{
return
node
。
ParentId
==
item
[
field
];
});
$
。
each
(
items
,
function
(
index
,
item
)
{
data
。
splice
(
0
,
0
,
item
);
var
child
=
getParent
(
item
,
source
,
field
);
$
。
each
(
child
,
function
(
i
,
n
)
{
data
。
splice
(
0
,
0
,
n
);
});
});
return
data
;
};
var
getChild
=
function
(
node
,
source
,
field
)
{
var
data
=
[];
var
items
=
$
。
grep
(
source
,
function
(
item
,
index
)
{
return
item
。
ParentId
==
node
[
field
];
});
$
。
each
(
items
,
function
(
index
,
item
)
{
data
。
push
(
item
);
var
child
=
getChild
(
item
,
source
,
field
);
$
。
each
(
child
,
function
(
i
,
n
)
{
data
。
push
(
n
);
});
});
return
data
;
};
//呼叫bootstrapTable元件的構造器得到物件
var
BootstrapTable
=
$
。
fn
。
bootstrapTable
。
Constructor
,
_initData
=
BootstrapTable
。
prototype
。
initData
,
_initPagination
=
BootstrapTable
。
prototype
。
initPagination
,
_initBody
=
BootstrapTable
。
prototype
。
initBody
;
//重寫bootstrapTable的initData方法
BootstrapTable
。
prototype
。
initData
=
function
()
{
_initData
。
apply
(
this
,
Array
。
prototype
。
slice
。
apply
(
arguments
));
var
that
=
this
;
if
(
that
。
options
。
treeView
&&
this
。
data
。
length
>
0
)
{
var
rows
=
[];
var
roots
=
$
。
grep
(
this
。
data
,
function
(
row
,
index
)
{
return
row
。
Level
==
that
。
options
。
treeRootLevel
;
});
$
。
each
(
roots
,
function
(
index
,
item
)
{
rows
。
push
(
item
);
var
child
=
getChild
(
item
,
that
。
data
,
that
。
options
。
treeId
);
$
。
each
(
child
,
function
(
i
,
n
)
{
if
(
that
。
options
。
treeCollapseAll
)
{
n
。
hidden
=
true
;
}
rows
。
push
(
n
);
});
});
that
。
options
。
data
=
that
。
data
=
rows
;
}
};
//重寫bootstrapTable的initPagination方法
BootstrapTable
。
prototype
。
initPagination
=
function
()
{
//理論情況下,treegrid是不支援分頁的,所以預設分頁引數為false
this
。
options
。
pagination
=
false
;
//呼叫“父類”的“虛方法”
_initPagination
。
apply
(
this
,
Array
。
prototype
。
slice
。
apply
(
arguments
));
};
//重寫bootstrapTable的initBody方法
BootstrapTable
。
prototype
。
initBody
=
function
(
fixedScroll
)
{
var
that
=
this
,
html
=
[],
data
=
this
。
getData
();
this
。
trigger
(
‘pre-body’
,
data
);
this
。
$body
=
this
。
$el
。
find
(
‘tbody’
);
if
(
!
this
。
$body
。
length
)
{
this
。
$body
=
$
(
‘
’)。
appendTo
(
this
。
$el
);
}
if
(
!
this
。
options
。
pagination
||
this
。
options
。
sidePagination
===
‘server’
)
{
this
。
pageFrom
=
1
;
this
。
pageTo
=
data
。
length
;
}
for
(
var
i
=
this
。
pageFrom
-
1
;
i
<
this
。
pageTo
;
i
++
)
{
var
key
,
item
=
data
[
i
],
style
=
{},
csses
=
[],
data_
=
‘’
,
attributes
=
{},
htmlAttributes
=
[];
if
(
item
。
hidden
)
continue
;
style
=
calculateObjectValue
(
this
。
options
,
this
。
options
。
rowStyle
,
[
item
,
i
],
style
);
if
(
style
&&
style
。
css
)
{
for
(
key
in
style
。
css
)
{
csses
。
push
(
key
+
‘: ’
+
style
。
css
[
key
]);
}
}
attributes
=
calculateObjectValue
(
this
。
options
,
this
。
options
。
rowAttributes
,
[
item
,
i
],
attributes
);
if
(
attributes
)
{
for
(
key
in
attributes
)
{
htmlAttributes
。
push
(
sprintf
(
‘%s=“%s”’
,
key
,
escapeHTML
(
attributes
[
key
])));
}
}
if
(
item
。
_data
&&
!
$
。
isEmptyObject
(
item
。
_data
))
{
$
。
each
(
item
。
_data
,
function
(
k
,
v
)
{
if
(
k
===
‘index’
)
{
return
;
}
data_
+=
sprintf
(
‘ data-%s=“%s”’
,
k
,
v
);
});
}
html
。
push
(
‘
,
sprintf
(
‘ %s’
,
htmlAttributes
。
join
(
‘ ’
)),
sprintf
(
‘ id=“%s”’
,
$
。
isArray
(
item
)
?
undefined
:
item
。
_id
),
sprintf
(
‘ class=“%s”’
,
style
。
classes
||
(
$
。
isArray
(
item
)
?
undefined
:
item
。
_class
)),
sprintf
(
‘ data-index=“%s”’
,
i
),
sprintf
(
‘ data-uniqueid=“%s”’
,
item
[
this
。
options
。
uniqueId
]),
sprintf
(
‘%s’
,
data_
),
‘>’
);
if
(
this
。
options
。
cardView
)
{
html
。
push
(
sprintf
(
‘
,
this
。
header
。
fields
。
length
));
}
if
(
!
this
。
options
。
cardView
&&
this
。
options
。
detailView
)
{
html
。
push
(
‘
,
‘’
,
sprintf
(
‘’
,
this
。
options
。
iconsPrefix
,
this
。
options
。
icons
。
detailOpen
),
‘’
,
‘
);
}
$
。
each
(
this
。
header
。
fields
,
function
(
j
,
field
)
{
var
text
=
‘’
,
value
=
getItemField
(
item
,
field
),
type
=
‘’
,
cellStyle
=
{},
id_
=
‘’
,
class_
=
that
。
header
。
classes
[
j
],
data_
=
‘’
,
rowspan_
=
‘’
,
title_
=
‘’
,
column
=
that
。
columns
[
getFieldIndex
(
that
。
columns
,
field
)];
if
(
!
column
。
visible
)
{
return
;
}
style
=
sprintf
(
‘style=“%s”’
,
csses
。
concat
(
that
。
header
。
styles
[
j
])。
join
(
‘; ’
));
value
=
calculateObjectValue
(
column
,
that
。
header
。
formatters
[
j
],
[
value
,
item
,
i
],
value
);
if
(
item
[
‘_’
+
field
+
‘_id’
])
{
id_
=
sprintf
(
‘ id=“%s”’
,
item
[
‘_’
+
field
+
‘_id’
]);
}
if
(
item
[
‘_’
+
field
+
‘_class’
])
{
class_
=
sprintf
(
‘ class=“%s”’
,
item
[
‘_’
+
field
+
‘_class’
]);
}
if
(
item
[
‘_’
+
field
+
‘_rowspan’
])
{
rowspan_
=
sprintf
(
‘ rowspan=“%s”’
,
item
[
‘_’
+
field
+
‘_rowspan’
]);
}
if
(
item
[
‘_’
+
field
+
‘_title’
])
{
title_
=
sprintf
(
‘ title=“%s”’
,
item
[
‘_’
+
field
+
‘_title’
]);
}
cellStyle
=
calculateObjectValue
(
that
。
header
,
that
。
header
。
cellStyles
[
j
],
[
value
,
item
,
i
],
cellStyle
);
if
(
cellStyle
。
classes
)
{
class_
=
sprintf
(
‘ class=“%s”’
,
cellStyle
。
classes
);
}
if
(
cellStyle
。
css
)
{
var
csses_
=
[];
for
(
var
key
in
cellStyle
。
css
)
{
csses_
。
push
(
key
+
‘: ’
+
cellStyle
。
css
[
key
]);
}
style
=
sprintf
(
‘style=“%s”’
,
csses_
。
concat
(
that
。
header
。
styles
[
j
])。
join
(
‘; ’
));
}
if
(
item
[
‘_’
+
field
+
‘_data’
]
&&
!
$
。
isEmptyObject
(
item
[
‘_’
+
field
+
‘_data’
]))
{
$
。
each
(
item
[
‘_’
+
field
+
‘_data’
],
function
(
k
,
v
)
{
if
(
k
===
‘index’
)
{
return
;
}
data_
+=
sprintf
(
‘ data-%s=“%s”’
,
k
,
v
);
});
}
if
(
column
。
checkbox
||
column
。
radio
)
{
type
=
column
。
checkbox
?
‘checkbox’
:
type
;
type
=
column
。
radio
?
‘radio’
:
type
;
text
=
[
that
。
options
。
cardView
?
‘
:
‘
,
‘
+
sprintf
(
‘ data-index=“%s”’
,
i
)
+
sprintf
(
‘ name=“%s”’
,
that
。
options
。
selectItemName
)
+
sprintf
(
‘ type=“%s”’
,
type
)
+
sprintf
(
‘ value=“%s”’
,
item
[
that
。
options
。
idField
])
+
sprintf
(
‘ checked=“%s”’
,
value
===
true
||
(
value
&&
value
。
checked
)
?
‘checked’
:
undefined
)
+
sprintf
(
‘ disabled=“%s”’
,
!
column
。
checkboxEnabled
||
(
value
&&
value
。
disabled
)
?
‘disabled’
:
undefined
)
+
‘ />’
,
that
。
header
。
formatters
[
j
]
&&
typeof
value
===
‘string’
?
value
:
‘’
,
that
。
options
。
cardView
?
‘’
:
‘
]。
join
(
‘’
);
item
[
that
。
header
。
stateField
]
=
value
===
true
||
(
value
&&
value
。
checked
);
}
else
{
value
=
typeof
value
===
‘undefined’
||
value
===
null
?
that
。
options
。
undefinedText
:
value
;
var
indent
,
icon
;
if
(
that
。
options
。
treeView
&&
column
。
field
==
that
。
options
。
treeField
)
{
var
indent
=
item
。
Level
==
that
。
options
。
Level
?
‘’
:
sprintf
(
‘’
,
(
item
。
Level
-
that
。
options
。
treeRootLevel
)
*
15
);
var
child
=
$
。
grep
(
data
,
function
(
d
,
i
)
{
return
d
。
ParentId
==
item
[
that
。
options
。
treeId
]
&&
!
d
。
hidden
;
});
icon
=
sprintf
(
‘’
,
child
。
length
>
0
?
that
。
options
。
expandIcon
:
that
。
options
。
collapseIcon
);
//icon = sprintf(‘’, child。length > 0 ? that。options。expandIcon : “”);
}
text
=
that
。
options
。
cardView
?
[
‘
,
that
。
options
。
showHeader
?
sprintf
(
‘%s’
,
style
,
getPropertyFromOther
(
that
。
columns
,
‘field’
,
‘title’
,
field
))
:
‘’
,
sprintf
(
‘%s’
,
value
),
‘
]。
join
(
‘’
)
:
[
sprintf
(
‘
,
id_
,
class_
,
style
,
data_
,
rowspan_
,
title_
),
indent
,
icon
,
value
,
‘
]。
join
(
‘’
);
if
(
that
。
options
。
cardView
&&
that
。
options
。
smartDisplay
&&
value
===
‘’
)
{
text
=
‘’
;
}
}
html
。
push
(
text
);
});
if
(
this
。
options
。
cardView
)
{
html
。
push
(
‘’
);
}
html
。
push
(
‘
);
}
if
(
!
html
。
length
)
{
html
。
push
(
‘
,
sprintf
(
‘
,
this
。
$header
。
find
(
‘th’
)。
length
,
this
。
options
。
formatNoMatches
()),
‘
);
}
this
。
$body
。
html
(
html
。
join
(
‘’
));
if
(
!
fixedScroll
)
{
this
。
scrollTo
(
0
);
}
this
。
$body
。
find
(
‘> tr[data-index] > td’
)。
off
(
‘click dblclick’
)。
on
(
‘click dblclick’
,
function
(
e
)
{
var
$td
=
$
(
this
),
$tr
=
$td
。
parent
(),
item
=
that
。
data
[
$tr
。
data
(
‘index’
)],
index
=
$td
[
0
]。
cellIndex
,
field
=
that
。
header
。
fields
[
that
。
options
。
detailView
&&
!
that
。
options
。
cardView
?
index
-
1
:
index
],
column
=
that
。
columns
[
getFieldIndex
(
that
。
columns
,
field
)],
value
=
getItemField
(
item
,
field
);
if
(
$td
。
find
(
‘。detail-icon’
)。
length
)
{
return
;
}
that
。
trigger
(
e
。
type
===
‘click’
?
‘click-cell’
:
‘dbl-click-cell’
,
field
,
value
,
item
,
$td
);
that
。
trigger
(
e
。
type
===
‘click’
?
‘click-row’
:
‘dbl-click-row’
,
item
,
$tr
);
if
(
e
。
type
===
‘click’
&&
that
。
options
。
clickToSelect
&&
column
。
clickToSelect
)
{
var
$selectItem
=
$tr
。
find
(
sprintf
(
‘[name=“%s”]’
,
that
。
options
。
selectItemName
));
if
(
$selectItem
。
length
)
{
$selectItem
[
0
]。
click
();
}
}
});
this
。
$body
。
find
(
‘> tr[data-index] > td > 。detail-icon’
)。
off
(
‘click’
)。
on
(
‘click’
,
function
()
{
debugger
;
var
$this
=
$
(
this
),
$tr
=
$this
。
parent
()。
parent
(),
index
=
$tr
。
data
(
‘index’
),
row
=
data
[
index
];
if
(
$tr
。
next
()。
is
(
‘tr。detail-view’
))
{
$this
。
find
(
‘i’
)。
attr
(
‘class’
,
sprintf
(
‘%s %s’
,
that
。
options
。
iconsPrefix
,
that
。
options
。
icons
。
detailOpen
));
$tr
。
next
()。
remove
();
that
。
trigger
(
‘collapse-row’
,
index
,
row
);
}
else
{
$this
。
find
(
‘i’
)。
attr
(
‘class’
,
sprintf
(
‘%s %s’
,
that
。
options
。
iconsPrefix
,
that
。
options
。
icons
。
detailClose
));
$tr
。
after
(
sprintf
(
‘
,
$tr
。
find
(
‘td’
)。
length
,
calculateObjectValue
(
that
。
options
,
that
。
options
。
detailFormatter
,
[
index
,
row
],
‘’
)));
that
。
trigger
(
‘expand-row’
,
index
,
row
,
$tr
。
next
()。
find
(
‘td’
));
}
that
。
resetView
();
});
this
。
$body
。
find
(
‘> tr[data-index] > td > 。tree-icon’
)。
off
(
‘click’
)。
on
(
‘click’
,
function
(
e
)
{
debugger
;
e
。
stopPropagation
();
var
$this
=
$
(
this
),
$tr
=
$this
。
parent
()。
parent
(),
index
=
$tr
。
data
(
‘index’
),
row
=
data
[
index
];
var
icon
=
$
(
this
);
var
child
=
getChild
(
data
[
index
],
data
,
that
。
options
。
treeId
);
$
。
each
(
child
,
function
(
i
,
c
)
{
$
。
each
(
that
。
data
,
function
(
index
,
item
)
{
if
(
item
[
that
。
options
。
treeId
]
==
c
[
that
。
options
。
treeId
])
{
item
。
hidden
=
icon
。
hasClass
(
that
。
options
。
expandIcon
);
that
。
uncheck
(
index
);
return
;
}
});
});
if
(
icon
。
hasClass
(
that
。
options
。
expandIcon
))
{
icon
。
removeClass
(
that
。
options
。
expandIcon
)。
addClass
(
that
。
options
。
collapseIcon
);
}
else
{
icon
。
removeClass
(
that
。
options
。
collapseIcon
)。
addClass
(
that
。
options
。
expandIcon
);
}
that
。
options
。
data
=
that
。
data
;
that
。
initBody
(
true
);
});
this
。
$selectItem
=
this
。
$body
。
find
(
sprintf
(
‘[name=“%s”]’
,
this
。
options
。
selectItemName
));
this
。
$selectItem
。
off
(
‘click’
)。
on
(
‘click’
,
function
(
event
)
{
event
。
stopImmediatePropagation
();
var
$this
=
$
(
this
),
checked
=
$this
。
prop
(
‘checked’
),
row
=
that
。
data
[
$this
。
data
(
‘index’
)];
if
(
that
。
options
。
maintainSelected
&&
$
(
this
)。
is
(
‘:radio’
))
{
$
。
each
(
that
。
options
。
data
,
function
(
i
,
row
)
{
row
[
that
。
header
。
stateField
]
=
false
;
});
}
row
[
that
。
header
。
stateField
]
=
checked
;
if
(
that
。
options
。
singleSelect
)
{
that
。
$selectItem
。
not
(
this
)。
each
(
function
()
{
that
。
data
[
$
(
this
)。
data
(
‘index’
)][
that
。
header
。
stateField
]
=
false
;
});
that
。
$selectItem
。
filter
(
‘:checked’
)。
not
(
this
)。
prop
(
‘checked’
,
false
);
}
that
。
updateSelected
();
that
。
trigger
(
checked
?
‘check’
:
‘uncheck’
,
row
,
$this
);
});
$
。
each
(
this
。
header
。
events
,
function
(
i
,
events
)
{
if
(
!
events
)
{
return
;
}
if
(
typeof
events
===
‘string’
)
{
events
=
calculateObjectValue
(
null
,
events
);
}
var
field
=
that
。
header
。
fields
[
i
],
fieldIndex
=
$
。
inArray
(
field
,
that
。
getVisibleFields
());
if
(
that
。
options
。
detailView
&&
!
that
。
options
。
cardView
)
{
fieldIndex
+=
1
;
}
for
(
var
key
in
events
)
{
that
。
$body
。
find
(
‘tr’
)。
each
(
function
()
{
var
$tr
=
$
(
this
),
$td
=
$tr
。
find
(
that
。
options
。
cardView
?
‘。card-view’
:
‘td’
)。
eq
(
fieldIndex
),
index
=
key
。
indexOf
(
‘ ’
),
name
=
key
。
substring
(
0
,
index
),
el
=
key
。
substring
(
index
+
1
),
func
=
events
[
key
];
$td
。
find
(
el
)。
off
(
name
)。
on
(
name
,
function
(
e
)
{
var
index
=
$tr
。
data
(
‘index’
),
row
=
that
。
data
[
index
],
value
=
row
[
field
];
func
。
apply
(
this
,
[
e
,
value
,
row
,
index
]);
});
});
}
});
this
。
updateSelected
();
this
。
resetView
();
this
。
trigger
(
‘post-body’
);
};
//給元件增加預設引數列表
$
。
extend
(
$
。
fn
。
bootstrapTable
。
defaults
,
{
treeView
:
false
,
//treeView檢視
treeField
:
“id”
,
//treeView檢視欄位
treeId
:
“id”
,
treeRootLevel
:
0
,
//根節點序號
treeCollapseAll
:
false
,
//是否全部展開
collapseIcon
:
“glyphicon glyphicon-chevron-right”
,
//摺疊樣式
expandIcon
:
“glyphicon glyphicon-chevron-down”
//展開樣式
});
})(
jQuery
);
元件的使用如下:
1、首先引用這個js檔案。
2、然後初始化元件
$
(
‘#tb’
)。
bootstrapTable
({
url
:
ActionUrl
+
‘GetMenuList’
,
toolbar
:
‘#toolbar’
,
sidePagination
:
‘client’
,
pagination
:
false
,
treeView
:
true
,
treeId
:
“Id”
,
treeField
:
“Name”
,
treeRootLevel
:
1
,
clickToSelect
:
true
,
//collapseIcon: “glyphicon glyphicon-triangle-right”,//摺疊樣式
//expandIcon: “glyphicon glyphicon-triangle-bottom”//展開樣式
})
;
treeView:true表示啟用樹表格模式;
treeId:‘Id’表示每一行tree的id;
treeField:‘Name’表示要對那一列進行展開;
treeRootLevel:1表示樹根的級別。
還有一個地方需要注意,要建立記錄之間的父子級關係,必然後有一個ParentId的概念,所以在從後端返回的結果集裡面,每條記錄勢必有一個ParentId的屬性,如果是根節點,ParentId為null。比如我們後臺得到的結果集的json格式如下:
[{
Id
:
1
,
Name
:
“系統設定”
,
Url
:
null
,
ParentId
:
null
,
Level
:
1
,
CreateTime
:
null
,
Status
:
1
,
SortOrder
:
1
,
…
},
{
Id
:
2
,
Name
:
“選單管理”
,
Url
:
“/Systems/Menu/Index”
,
ParentId
:
1
,
Level
:
2
,
CreateTime
:
null
,
Status
:
1
,
…
},
{
Id
:
3
,
Name
:
“訂單管理”
,
Url
:
null
,
ParentId
:
null
,
Level
:
1
,
CreateTime
:
“2017-05-31 17:05:27”
,
…
},
{
Id
:
4
,
Name
:
“基礎資料”
,
Url
:
null
,
ParentId
:
null
,
Level
:
1
,
CreateTime
:
“2017-05-31 17:05:55”
,
…
},
{
Id
:
5
,
Name
:
“新增訂單”
,
Url
:
“/order/add”
,
ParentId
:
3
,
Level
:
2
,
CreateTime
:
“2017-05-31 17:07:03”
,
…
}]
三、元件需要完善的地方
上述封裝給大家提供一個擴充套件bootstrapTable元件treeview功能,還有很多地方需要完善,比如:
1、我們的葉子節點前面的圖示可以去掉;
2、增加展開所有、摺疊所有的功能;
3、Level欄位可以去掉,透過ParentId為null來確定根節點。
有興趣的小夥伴可以自己試試。
四、總結
至此本文就結束了,這篇針對上篇做了一個補充,使得我們可以根據專案的需求自己選擇用哪種方式,如果我們專案使用的是bootstrapTable作為資料展示的元件,可以考慮上述擴充套件;如果沒有使用bootstrapTable,可以試試上篇的元件。