el-crud-page 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/index.esm.js +3606 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +3613 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +3615 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +60 -0
- package/src/asyncDialog.js +6 -0
- package/src/form.vue +659 -0
- package/src/index.js +7 -0
- package/src/index.vue +341 -0
- package/src/pagination.vue +114 -0
- package/src/queryForm.vue +339 -0
- package/src/rightToolbar.vue +172 -0
- package/src/style.scss +115 -0
- package/src/table.vue +159 -0
- package/src/tableColumn.js +330 -0
- package/src/utils/clone-deep.js +42 -0
- package/src/utils/index.js +135 -0
- package/src/utils/is-plain-object.js +32 -0
- package/src/utils/kind-of.js +129 -0
- package/src/utils/parse.js +29 -0
- package/src/utils/scroll-to.js +58 -0
- package/src/utils/shallow-clone.js +79 -0
- package/src/utils/value-hook.js +97 -0
- package/src/utils/vnode.jsx +215 -0
package/src/table.vue
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<!-- crud table 组件 -->
|
|
2
|
+
<template>
|
|
3
|
+
<el-table :data="data" class="crud-table" ref="table" v-bind="combinedProps" v-on="combinedEvents">
|
|
4
|
+
<crud-table-column v-for="column in columns" :indexMethod="(index)=>( baseIndex + 1 + index )"
|
|
5
|
+
v-if="!column[`v-hasPermi`] || !column[`v-hasPermi`].length || $auth.hasPermiOr(column[`v-hasPermi`] || [])"
|
|
6
|
+
:column="column" @action="onRowAction">
|
|
7
|
+
</crud-table-column>
|
|
8
|
+
</el-table>
|
|
9
|
+
</template>
|
|
10
|
+
<script>
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* CRUD table组件
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import CrudTableColumn from "./tableColumn.js";
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: "CrudTable",
|
|
21
|
+
components: {
|
|
22
|
+
CrudTableColumn
|
|
23
|
+
},
|
|
24
|
+
inject: ["crud"],
|
|
25
|
+
props: {
|
|
26
|
+
columns: {
|
|
27
|
+
type: Array,
|
|
28
|
+
default: () => []
|
|
29
|
+
},
|
|
30
|
+
on: {
|
|
31
|
+
type: Object,
|
|
32
|
+
default: () => {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
data: {
|
|
37
|
+
type: Array,
|
|
38
|
+
default: () => {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
data() {
|
|
44
|
+
return {
|
|
45
|
+
emit: {},
|
|
46
|
+
defaultProps: {
|
|
47
|
+
stripe: true,
|
|
48
|
+
size: "mini",
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
computed: {
|
|
53
|
+
// 将外部传入的 props 与 crud 内部样式合并
|
|
54
|
+
combinedProps() {
|
|
55
|
+
return Object.assign({}, this.defaultProps, this.$attrs);
|
|
56
|
+
},
|
|
57
|
+
// 将各事件处理函数合并,包括 emit 与 on 上的回调
|
|
58
|
+
combinedEvents() {
|
|
59
|
+
return Object.assign(
|
|
60
|
+
{},
|
|
61
|
+
{
|
|
62
|
+
"selection-change": this.onSelectionChange,
|
|
63
|
+
"sort-change": this.onSortChange,
|
|
64
|
+
"row-contextmenu": this.onRowContextMenu
|
|
65
|
+
},
|
|
66
|
+
this.emit,
|
|
67
|
+
this.on
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
baseIndex(){
|
|
71
|
+
if( this.crud?.pagination ){
|
|
72
|
+
return (this.crud?.pagination?.pageNum-1) * this.crud?.pagination?.pageSize;
|
|
73
|
+
}else{
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
mounted() {
|
|
79
|
+
this.bindEmits();
|
|
80
|
+
this.bindMethods();
|
|
81
|
+
},
|
|
82
|
+
methods: {
|
|
83
|
+
// 绑定 el-table 回调
|
|
84
|
+
bindEmits() {
|
|
85
|
+
const emits = [
|
|
86
|
+
"select",
|
|
87
|
+
"select-all",
|
|
88
|
+
"cell-mouse-enter",
|
|
89
|
+
"cell-mouse-leave",
|
|
90
|
+
"cell-click",
|
|
91
|
+
"cell-dblclick",
|
|
92
|
+
"row-click",
|
|
93
|
+
"row-contextmenu",
|
|
94
|
+
"row-dblclick",
|
|
95
|
+
"header-click",
|
|
96
|
+
"header-contextmenu",
|
|
97
|
+
"filter-change",
|
|
98
|
+
"current-change",
|
|
99
|
+
"header-dragend",
|
|
100
|
+
"expand-change"
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
emits.forEach((name) => {
|
|
104
|
+
this.emit[name] = (...args) => {
|
|
105
|
+
this.$emit(name, ...args);
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// 绑定 el-table 事件
|
|
111
|
+
bindMethods() {
|
|
112
|
+
const methods = [
|
|
113
|
+
"clearSelection",
|
|
114
|
+
"toggleRowSelection",
|
|
115
|
+
"toggleAllSelection",
|
|
116
|
+
"toggleRowExpansion",
|
|
117
|
+
"setCurrentRow",
|
|
118
|
+
"clearSort",
|
|
119
|
+
"clearFilter",
|
|
120
|
+
"doLayout",
|
|
121
|
+
"sort"
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
methods.forEach((n) => {
|
|
125
|
+
this[n] = this.$refs["table"][n];
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
onSelectionChange(selection) {
|
|
129
|
+
this.$emit("selection-change", selection);
|
|
130
|
+
},
|
|
131
|
+
onSortChange({ prop, order }) {
|
|
132
|
+
this.$emit("sort-change", { prop, order });
|
|
133
|
+
},
|
|
134
|
+
onRowContextMenu(row, column, event) {
|
|
135
|
+
this.$emit("row-contextmenu", row, column, event);
|
|
136
|
+
},
|
|
137
|
+
onRowAction(action, scope) {
|
|
138
|
+
this.$emit("row-action", action, scope);
|
|
139
|
+
this.$emit(`row-${action}`, scope);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
</script>
|
|
145
|
+
|
|
146
|
+
<style scoped lang="scss">
|
|
147
|
+
.crud-table {
|
|
148
|
+
&::v-deep {
|
|
149
|
+
.el-table__body-wrapper {
|
|
150
|
+
.el-table__cell {
|
|
151
|
+
.cell:empty::after {
|
|
152
|
+
content: '/';
|
|
153
|
+
color: #c0c4cc;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// 组件说明:TableColumn 用于在 CRUD 表格中动态渲染列,支持嵌套子列,处理字典与格式化展示。
|
|
2
|
+
import { renderNode } from "./utils/vnode.jsx";
|
|
3
|
+
import { isFunction, isString, isArray, cloneDeep, isObject,isPromise } from "./utils";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const TableColumn = {
|
|
7
|
+
// 组件名称
|
|
8
|
+
name: "TableColumn",
|
|
9
|
+
data() {
|
|
10
|
+
return {
|
|
11
|
+
// emit:{},
|
|
12
|
+
actionMap: {
|
|
13
|
+
info: {
|
|
14
|
+
label: "详情",
|
|
15
|
+
type: "text",
|
|
16
|
+
action: "info",
|
|
17
|
+
icon: "el-icon-document"
|
|
18
|
+
},
|
|
19
|
+
update: {
|
|
20
|
+
label: "编辑",
|
|
21
|
+
type: "text",
|
|
22
|
+
action: "update",
|
|
23
|
+
icon: "el-icon-edit"
|
|
24
|
+
},
|
|
25
|
+
delete: {
|
|
26
|
+
label: "删除",
|
|
27
|
+
type: "text",
|
|
28
|
+
action: "delete",
|
|
29
|
+
icon: "el-icon-delete"
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
props: {
|
|
36
|
+
// 列配置对象,包含列属性、子列、格式化函数等
|
|
37
|
+
column: {
|
|
38
|
+
type: Object,
|
|
39
|
+
required: true
|
|
40
|
+
},
|
|
41
|
+
// 行索引生成方法,用于动态生成行号
|
|
42
|
+
indexMethod: {
|
|
43
|
+
type: Function,
|
|
44
|
+
required: false
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
computed: {
|
|
48
|
+
// 判断当前列是否包含子列
|
|
49
|
+
hasChildren() {
|
|
50
|
+
return this.column.children && this.column.children.length > 0;
|
|
51
|
+
},
|
|
52
|
+
// 生成并返回列的属性集合,默认居中对齐
|
|
53
|
+
columnProps() {
|
|
54
|
+
return Object.assign({}, this.column, {
|
|
55
|
+
align: this.column.align || "center"
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
// 生成唯一的列 key,用于 Vue 渲染优化
|
|
59
|
+
columnKey() {
|
|
60
|
+
return "crud-table-column-" + (this.column.prop || Math.random());
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
},
|
|
64
|
+
mounted() {
|
|
65
|
+
},
|
|
66
|
+
methods: {
|
|
67
|
+
// 根据传入值查找并返回字典中对应的对象
|
|
68
|
+
getDict(value) {
|
|
69
|
+
if( isPromise(this.column.dict)){
|
|
70
|
+
this.column.dict.then((dict)=>{
|
|
71
|
+
this.column.dict = dict;
|
|
72
|
+
});
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
// this.column.dict 如果 this.column.dict 是个 function
|
|
76
|
+
// 则调用 this.column.dict(value) 返回字典对象
|
|
77
|
+
if (typeof this.column.dict === "function") {
|
|
78
|
+
return this.column.dict(value).find(d => d.value == value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (this.column.dict) {
|
|
82
|
+
return this.column.dict?.find(d => d.value == value);
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
},
|
|
86
|
+
// 检查传入的值是否严格为 null
|
|
87
|
+
isNull(val) {
|
|
88
|
+
return val === null;
|
|
89
|
+
},
|
|
90
|
+
renderNode(vnode, options) {
|
|
91
|
+
return renderNode.call(this, vnode, options);
|
|
92
|
+
},
|
|
93
|
+
renderSelection(h) {
|
|
94
|
+
return h(
|
|
95
|
+
"el-table-column",
|
|
96
|
+
{
|
|
97
|
+
key: this.columnKey,
|
|
98
|
+
props: Object.assign({}, this.columnProps, { index: this.indexMethod })
|
|
99
|
+
},
|
|
100
|
+
[]
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
},
|
|
104
|
+
// 渲染操作列
|
|
105
|
+
renderActions(h) {
|
|
106
|
+
return h(
|
|
107
|
+
"el-table-column",
|
|
108
|
+
{
|
|
109
|
+
key: this.columnKey,
|
|
110
|
+
props: Object.assign({}, this.columnProps, { index: this.indexMethod }),
|
|
111
|
+
scopedSlots: {
|
|
112
|
+
default: scope => {
|
|
113
|
+
let actions = this.column.actions;
|
|
114
|
+
if (isFunction(this.column.actions)) {
|
|
115
|
+
actions = this.column.actions({ scope, h });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return actions?.map(action => {
|
|
119
|
+
|
|
120
|
+
// 自定义渲染函数
|
|
121
|
+
if (isFunction(action)) {
|
|
122
|
+
return action({ scope, h });
|
|
123
|
+
}
|
|
124
|
+
// 预设的操作映射
|
|
125
|
+
if (isString(action)) {
|
|
126
|
+
action = this.actionMap[action];
|
|
127
|
+
if( !action){
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// action 如果是数组 创建 更多 按钮列表
|
|
132
|
+
if (isArray(action)) {
|
|
133
|
+
return h(
|
|
134
|
+
"el-dropdown",
|
|
135
|
+
{
|
|
136
|
+
props: {
|
|
137
|
+
trigger: "hover",
|
|
138
|
+
// size: "mini"
|
|
139
|
+
},
|
|
140
|
+
on: {
|
|
141
|
+
command: (e) => {
|
|
142
|
+
this.$emit("action", e, scope);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
style: {
|
|
146
|
+
right: "auto",
|
|
147
|
+
"margin-left":"10px"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
[
|
|
151
|
+
h(
|
|
152
|
+
"span",
|
|
153
|
+
{
|
|
154
|
+
class: "el-dropdown-link",
|
|
155
|
+
style: "margin-left: 0",
|
|
156
|
+
},
|
|
157
|
+
[
|
|
158
|
+
"更多",
|
|
159
|
+
h("i", {
|
|
160
|
+
class: "el-icon-arrow-down el-icon--right"
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
),
|
|
164
|
+
h(
|
|
165
|
+
"el-dropdown-menu",
|
|
166
|
+
{
|
|
167
|
+
slot: "dropdown"
|
|
168
|
+
},
|
|
169
|
+
action.map(item => {
|
|
170
|
+
let _item = item
|
|
171
|
+
// 预设的操作映射
|
|
172
|
+
if (isString(_item)) {
|
|
173
|
+
_item = this.actionMap[_item];
|
|
174
|
+
if( !_item){
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return h(
|
|
179
|
+
"el-dropdown-item",
|
|
180
|
+
{
|
|
181
|
+
props: {
|
|
182
|
+
command: _item.action,
|
|
183
|
+
icon: _item.icon,
|
|
184
|
+
disabled: _item.disabled,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
_item.label
|
|
188
|
+
);
|
|
189
|
+
})
|
|
190
|
+
)
|
|
191
|
+
]
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
// 渲染 action 按钮
|
|
198
|
+
return h(
|
|
199
|
+
"el-button",
|
|
200
|
+
{
|
|
201
|
+
props: {
|
|
202
|
+
type: action.type || "text",
|
|
203
|
+
size: action.size || "mini",
|
|
204
|
+
icon: action.icon || "",
|
|
205
|
+
disabled: action.disabled || false
|
|
206
|
+
},
|
|
207
|
+
on: {
|
|
208
|
+
click:(e)=> {
|
|
209
|
+
this.$emit("action", action.action, scope);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
action.label
|
|
214
|
+
);
|
|
215
|
+
}).filter(item=>item);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
[]
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
},
|
|
224
|
+
// 动态渲染函数,根据列配置渲染 el-table-column
|
|
225
|
+
render(h) {
|
|
226
|
+
if ( this.column.hidden ){
|
|
227
|
+
if( typeof this.column.hidden === "function" ){
|
|
228
|
+
// 如果 hidden 是函数,则调用函数判断是否隐藏
|
|
229
|
+
if (this.column.hidden(this.column)) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (this.column.visible === false) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
if (this.column.type === "selection" || this.column.type === "index") {
|
|
239
|
+
// 对于 selection 类型,直接传递 props 让 Element 内部处理选中状态
|
|
240
|
+
return this.renderSelection(h);
|
|
241
|
+
} else if (this.column.type === "action") {
|
|
242
|
+
// 对于 action 类型,渲染操作列
|
|
243
|
+
return this.renderActions(h);
|
|
244
|
+
}
|
|
245
|
+
return h(
|
|
246
|
+
"el-table-column",
|
|
247
|
+
{
|
|
248
|
+
key: this.columnKey,
|
|
249
|
+
props: Object.assign({}, this.columnProps, { index: this.indexMethod }),
|
|
250
|
+
scopedSlots: {
|
|
251
|
+
// 自定义表头渲染:支持 slot 覆盖默认表头
|
|
252
|
+
header: scope => {
|
|
253
|
+
return this.$scopedSlots["header-" + this.column.prop]
|
|
254
|
+
? this.$scopedSlots["header-" + this.column.prop](scope)
|
|
255
|
+
: scope.column.label;
|
|
256
|
+
},
|
|
257
|
+
// 自定义单元格渲染:支持 slot、组件、格式化函数或字典
|
|
258
|
+
default: (scope) => {
|
|
259
|
+
let content;
|
|
260
|
+
// 检查是否有自定义 slot 渲染
|
|
261
|
+
if (this.$scopedSlots["column-" + this.column.prop]) {
|
|
262
|
+
content = this.$scopedSlots["column-" + this.column.prop]({
|
|
263
|
+
scope: scope,
|
|
264
|
+
column: this.column
|
|
265
|
+
});
|
|
266
|
+
} else if (this.column.component) {
|
|
267
|
+
// 通过 renderNode 调用渲染组件,确保 this 指向当前实例
|
|
268
|
+
content = this.renderNode(this.column.component, { prop: this.column.prop, scope: scope });
|
|
269
|
+
} else if (this.column.formatter) {
|
|
270
|
+
content = this.column.formatter(
|
|
271
|
+
scope.row,
|
|
272
|
+
scope.column,
|
|
273
|
+
scope.row[this.column.prop],
|
|
274
|
+
scope.$index
|
|
275
|
+
);
|
|
276
|
+
} else if (this.column.dict) {
|
|
277
|
+
const dictItem = this.getDict(scope.row[this.column.prop]);
|
|
278
|
+
if (dictItem?.label) {
|
|
279
|
+
content = h(
|
|
280
|
+
"el-tag",
|
|
281
|
+
{
|
|
282
|
+
props: {
|
|
283
|
+
size: "mini",
|
|
284
|
+
disableTransitions: true,
|
|
285
|
+
type: dictItem.type
|
|
286
|
+
// effect: "dark"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
dictItem.label
|
|
290
|
+
);
|
|
291
|
+
} else {
|
|
292
|
+
content = scope.row[this.column.prop];
|
|
293
|
+
}
|
|
294
|
+
} else if (this.isNull(scope.row[this.column.prop])) {
|
|
295
|
+
content = scope.emptyText;
|
|
296
|
+
} else {
|
|
297
|
+
content = scope.row[this.column.prop];
|
|
298
|
+
}
|
|
299
|
+
return content;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
// 若有子列则递归渲染
|
|
304
|
+
this.hasChildren
|
|
305
|
+
? this.column.children.map((child, idx) =>
|
|
306
|
+
h(TableColumn, {
|
|
307
|
+
key: idx,
|
|
308
|
+
props: {
|
|
309
|
+
column: child,
|
|
310
|
+
indexMethod: this.indexMethod,
|
|
311
|
+
|
|
312
|
+
},
|
|
313
|
+
on: this.$listeners,
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
})
|
|
318
|
+
)
|
|
319
|
+
: []
|
|
320
|
+
);
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// 支持自身递归调用(递归组件)
|
|
326
|
+
TableColumn.components = {
|
|
327
|
+
TableColumn
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export default TableColumn;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import clone from './shallow-clone';
|
|
4
|
+
import typeOf from './kind-of';
|
|
5
|
+
import {isPlainObject} from './is-plain-object';
|
|
6
|
+
|
|
7
|
+
function cloneDeep(val, instanceClone) {
|
|
8
|
+
switch (typeOf(val)) {
|
|
9
|
+
case 'object':
|
|
10
|
+
return cloneObjectDeep(val, instanceClone);
|
|
11
|
+
case 'array':
|
|
12
|
+
return cloneArrayDeep(val, instanceClone);
|
|
13
|
+
default: {
|
|
14
|
+
return clone(val);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function cloneObjectDeep(val, instanceClone) {
|
|
20
|
+
if (typeof instanceClone === 'function') {
|
|
21
|
+
return instanceClone(val);
|
|
22
|
+
}
|
|
23
|
+
if (instanceClone || isPlainObject(val)) {
|
|
24
|
+
const res = (val.constructor !== undefined) ? new val.constructor() : Object.create(null);
|
|
25
|
+
for (let key in val) {
|
|
26
|
+
res[key] = cloneDeep(val[key], instanceClone);
|
|
27
|
+
}
|
|
28
|
+
return res;
|
|
29
|
+
}
|
|
30
|
+
return val;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function cloneArrayDeep(val, instanceClone) {
|
|
34
|
+
const res = new val.constructor(val.length);
|
|
35
|
+
for (let i = 0; i < val.length; i++) {
|
|
36
|
+
res[i] = cloneDeep(val[i], instanceClone);
|
|
37
|
+
}
|
|
38
|
+
return res;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export default cloneDeep;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import cloneDeep from './clone-deep';
|
|
2
|
+
import { scrollTo } from './scroll-to';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function isArray(value) {
|
|
6
|
+
if (typeof Array.isArray === "function") {
|
|
7
|
+
return Array.isArray(value);
|
|
8
|
+
} else {
|
|
9
|
+
return Object.prototype.toString.call(value) === "[object Array]";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isObject(value) {
|
|
14
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isNumber(value) {
|
|
18
|
+
return !isNaN(Number(value));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isFunction(value) {
|
|
22
|
+
return typeof value === "function";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isString(value) {
|
|
26
|
+
return typeof value === "string";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isNull(value) {
|
|
30
|
+
return !value && value !== 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function isBoolean(value) {
|
|
34
|
+
return typeof value === "boolean";
|
|
35
|
+
}
|
|
36
|
+
export function isPromise(value) {
|
|
37
|
+
return value && typeof value === 'object' && typeof value.then === 'function' && typeof value.catch === 'function';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isEmpty(value) {
|
|
41
|
+
if (isArray(value)) {
|
|
42
|
+
return value.length === 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isObject(value)) {
|
|
46
|
+
return Object.keys(value).length === 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return value === "" || value === undefined || value === null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function clone(obj) {
|
|
53
|
+
return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getParent(name) {
|
|
57
|
+
let parent = this.$parent;
|
|
58
|
+
|
|
59
|
+
while (parent) {
|
|
60
|
+
if (parent.$options.componentName !== name) {
|
|
61
|
+
parent = parent.$parent;
|
|
62
|
+
} else {
|
|
63
|
+
return parent;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
export function deepMerge(a, b) {
|
|
73
|
+
let k;
|
|
74
|
+
for (k in b) {
|
|
75
|
+
a[k] =
|
|
76
|
+
a[k] && a[k].toString() === "[object Object]" ? deepMerge(a[k], b[k]) : (a[k] = b[k]);
|
|
77
|
+
}
|
|
78
|
+
return a;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function contains(parent, node) {
|
|
82
|
+
if (document.documentElement.contains) {
|
|
83
|
+
return parent !== node && parent.contains(node);
|
|
84
|
+
} else {
|
|
85
|
+
while (node && (node = node.parentNode)) if (node === parent) return true;
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {Function} func
|
|
92
|
+
* @param {number} wait
|
|
93
|
+
* @param {boolean} immediate
|
|
94
|
+
* @return {*}
|
|
95
|
+
*/
|
|
96
|
+
export function debounce(func, wait, immediate) {
|
|
97
|
+
let timeout, args, context, timestamp, result
|
|
98
|
+
|
|
99
|
+
const later = function() {
|
|
100
|
+
// 据上一次触发时间间隔
|
|
101
|
+
const last = +new Date() - timestamp
|
|
102
|
+
|
|
103
|
+
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
|
|
104
|
+
if (last < wait && last > 0) {
|
|
105
|
+
timeout = setTimeout(later, wait - last)
|
|
106
|
+
} else {
|
|
107
|
+
timeout = null
|
|
108
|
+
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
|
|
109
|
+
if (!immediate) {
|
|
110
|
+
result = func.apply(context, args)
|
|
111
|
+
if (!timeout) context = args = null
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return function(...args) {
|
|
117
|
+
context = this
|
|
118
|
+
timestamp = +new Date()
|
|
119
|
+
const callNow = immediate && !timeout
|
|
120
|
+
// 如果延时不存在,重新设定延时
|
|
121
|
+
if (!timeout) timeout = setTimeout(later, wait)
|
|
122
|
+
if (callNow) {
|
|
123
|
+
result = func.apply(context, args)
|
|
124
|
+
context = args = null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function toLine(name) {
|
|
132
|
+
return name.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { cloneDeep,scrollTo };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2014-2017, Jon Schlinkert.
|
|
5
|
+
* Released under the MIT License.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
function isObject(o) {
|
|
9
|
+
return Object.prototype.toString.call(o) === '[object Object]';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isPlainObject(o) {
|
|
13
|
+
var ctor,prot;
|
|
14
|
+
|
|
15
|
+
if (isObject(o) === false) return false;
|
|
16
|
+
|
|
17
|
+
// If has modified constructor
|
|
18
|
+
ctor = o.constructor;
|
|
19
|
+
if (ctor === undefined) return true;
|
|
20
|
+
|
|
21
|
+
// If has modified prototype
|
|
22
|
+
prot = ctor.prototype;
|
|
23
|
+
if (isObject(prot) === false) return false;
|
|
24
|
+
|
|
25
|
+
// If constructor does not have an Object-specific method
|
|
26
|
+
if (prot.hasOwnProperty('isPrototypeOf') === false) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Most likely a plain Object
|
|
31
|
+
return true;
|
|
32
|
+
};
|