vue-editify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,440 @@
1
+ <template>
2
+ <div class="editify-button">
3
+ <div class="editify-button-wrap" :class="{ 'right-border': rightBorder, 'left-border': leftBorder }">
4
+ <Tooltip :content="title" :disabled="!tooltip">
5
+ <div ref="btn" :style="btnStyle" class="editify-button-el" :class="{ disabled: disabled, active: active }" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" @mousedown="handleMouseDown" @mouseup="handleMouseUp" @click="handleClick">
6
+ <div v-if="type == 'default' || type == 'select'" class="editify-button-slot">
7
+ <slot></slot>
8
+ </div>
9
+ <div v-else-if="type == 'display'">{{ displayLabel }}</div>
10
+ <Icon v-if="type == 'select' || type == 'display'" value="caret-down" class="editify-button-caret" :class="{ rotate: layerConfig.show }"></Icon>
11
+ </div>
12
+ </Tooltip>
13
+ <Layer ref="layer" v-model="layerConfig.show" :node="layerConfig.node" border fade placement="bottom-start" :z-index="20" animation="translate" @show="layerShow" @shown="layerShown" @hidden="layerHidden">
14
+ <div class="editify-button-layer" :style="{ width: (type == 'select' ? parseSelectConfig.width : parseDisplayConfig.width) + 'px', maxHeight: (type == 'select' ? parseSelectConfig.maxHeight : parseDisplayConfig.maxHeight) + 'px', overflow: hideScroll ? 'visible' : '' }">
15
+ <slot v-if="$slots.layer" name="layer" :options="cmpOptions"></slot>
16
+ <div v-else class="editify-button-options">
17
+ <div @click="select(item)" class="editify-button-option" :class="{ active: type == 'display' ? item.value == parseDisplayConfig.value : false }" :style="item.style || ''" v-for="item in cmpOptions">
18
+ <slot v-if="$slots.option" name="option" :item="item"></slot>
19
+ <div class="editify-button-option-flex" v-else>
20
+ <Icon v-if="item.icon" :value="item.icon"></Icon>
21
+ <span>{{ item.label }}</span>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </Layer>
27
+ </div>
28
+ </div>
29
+ </template>
30
+ <script>
31
+ import Tooltip from './Tooltip'
32
+ import Layer from './Layer'
33
+ import Icon from './Icon'
34
+ import Dap from 'dap-util'
35
+ export default {
36
+ name: 'Button',
37
+ emits: ['operate', 'layerShow', 'layerShown', 'layerHidden'],
38
+ props: {
39
+ //按钮类型
40
+ type: {
41
+ type: String,
42
+ default: 'default',
43
+ validator(value) {
44
+ //default表示默认的点击按钮
45
+ //select表示下拉列表的按钮
46
+ //display表示显示值的下拉列表按钮
47
+ return ['default', 'select', 'display'].includes(value)
48
+ }
49
+ },
50
+ //按钮名称,唯一值
51
+ name: {
52
+ type: String,
53
+ default: ''
54
+ },
55
+ //按钮提示内容
56
+ title: {
57
+ type: String,
58
+ default: ''
59
+ },
60
+ //是否显示工具提示
61
+ tooltip: {
62
+ type: Boolean,
63
+ default: false
64
+ },
65
+ //是否显示右侧边框
66
+ rightBorder: {
67
+ type: Boolean,
68
+ default: false
69
+ },
70
+ //是否显示左侧边框
71
+ leftBorder: {
72
+ type: Boolean,
73
+ default: false
74
+ },
75
+ //主题色,用于按钮悬浮颜色变化使用,仅支持十六进制
76
+ color: {
77
+ type: String,
78
+ default: ''
79
+ },
80
+ //是否禁用
81
+ disabled: {
82
+ type: Boolean,
83
+ default: false
84
+ },
85
+ //是否激活
86
+ active: {
87
+ type: Boolean,
88
+ default: false
89
+ },
90
+ //type=select时的配置
91
+ selectConfig: {
92
+ type: Object,
93
+ default: null
94
+ },
95
+ //type=display时的配置
96
+ displayConfig: {
97
+ type: Object,
98
+ default: null
99
+ },
100
+ //浮层隐藏滚动条
101
+ hideScroll: {
102
+ type: Boolean,
103
+ default: false
104
+ }
105
+ },
106
+ data() {
107
+ return {
108
+ //选择列表的浮层配置
109
+ layerConfig: {
110
+ show: false,
111
+ node: null
112
+ },
113
+ //按钮状态
114
+ status: null //hover表示悬浮,down表示按下
115
+ }
116
+ },
117
+ computed: {
118
+ //显示在页面的value值对应的label
119
+ displayLabel() {
120
+ const val = this.parseDisplayConfig.options.find(item => {
121
+ return item.value == this.parseDisplayConfig.value
122
+ })
123
+ return val ? val.label : ''
124
+ },
125
+ //渲染的浮层列表数据
126
+ cmpOptions() {
127
+ return this.type == 'select' ? this.parseSelectConfig.options : this.parseDisplayConfig.options
128
+ },
129
+ //处理后的select配置
130
+ parseSelectConfig() {
131
+ let options = []
132
+ let width = ''
133
+ let maxHeight = ''
134
+ if (Dap.common.isObject(this.selectConfig)) {
135
+ if (Array.isArray(this.selectConfig.options)) {
136
+ options = this.selectConfig.options.map(item => {
137
+ if (Dap.common.isObject(item)) {
138
+ return {
139
+ label: item.label,
140
+ value: item.value,
141
+ icon: item.icon,
142
+ style: item.style
143
+ }
144
+ }
145
+ return {
146
+ label: item,
147
+ value: item
148
+ }
149
+ })
150
+ }
151
+ if (typeof this.selectConfig.width == 'number') {
152
+ width = this.selectConfig.width
153
+ }
154
+ if (typeof this.selectConfig.maxHeight == 'number') {
155
+ maxHeight = this.selectConfig.maxHeight
156
+ }
157
+ }
158
+ return {
159
+ options,
160
+ width,
161
+ maxHeight
162
+ }
163
+ },
164
+ //处理后的display配置
165
+ parseDisplayConfig() {
166
+ let options = []
167
+ let width = ''
168
+ let maxHeight = ''
169
+ let value = ''
170
+ if (Dap.common.isObject(this.displayConfig)) {
171
+ if (typeof this.displayConfig.value == 'string' || typeof this.displayConfig.value == 'number') {
172
+ value = this.displayConfig.value
173
+ }
174
+ if (Array.isArray(this.displayConfig.options)) {
175
+ options = this.displayConfig.options.map(item => {
176
+ if (Dap.common.isObject(item)) {
177
+ return {
178
+ label: item.label,
179
+ value: item.value,
180
+ icon: item.icon,
181
+ style: item.style
182
+ }
183
+ }
184
+ return {
185
+ label: item,
186
+ value: item
187
+ }
188
+ })
189
+ let optItem = options.find(item => {
190
+ return item.value == value
191
+ })
192
+ if (!optItem && options[0]) {
193
+ value = options[0].value
194
+ }
195
+ }
196
+ if (typeof this.displayConfig.width == 'number') {
197
+ width = this.displayConfig.width
198
+ }
199
+ if (typeof this.displayConfig.maxHeight == 'number') {
200
+ maxHeight = this.displayConfig.maxHeight
201
+ }
202
+ }
203
+ return {
204
+ options,
205
+ width,
206
+ maxHeight,
207
+ value
208
+ }
209
+ },
210
+ //十六进制颜色转换的rgb颜色数组
211
+ parseColor() {
212
+ return Dap.color.hex2rgb(this.color)
213
+ },
214
+ //按钮样式
215
+ btnStyle() {
216
+ if (this.disabled) {
217
+ return {}
218
+ }
219
+ if (this.color) {
220
+ //激活情况下和鼠标按下状态
221
+ if (this.active || this.status == 'down') {
222
+ return {
223
+ color: this.color,
224
+ backgroundColor: `rgba(${this.parseColor[0]},${this.parseColor[1]},${this.parseColor[2]},0.15)`
225
+ }
226
+ }
227
+ //鼠标悬浮状态
228
+ if (this.status == 'hover') {
229
+ return {
230
+ color: `rgba(${this.parseColor[0]},${this.parseColor[1]},${this.parseColor[2]},0.9)`,
231
+ backgroundColor: `rgba(${this.parseColor[0]},${this.parseColor[1]},${this.parseColor[2]},0.05)`
232
+ }
233
+ }
234
+ }
235
+ return {}
236
+ }
237
+ },
238
+ components: {
239
+ Tooltip,
240
+ Layer,
241
+ Icon
242
+ },
243
+ methods: {
244
+ //主动关闭浮层
245
+ hideLayer() {
246
+ this.layerConfig.show = false
247
+ this.layerConfig.node = null
248
+ },
249
+ //浮层显示时
250
+ layerShow() {
251
+ this.$emit('layerShow')
252
+ },
253
+ //浮层显示后
254
+ layerShown() {
255
+ this.$emit('layerShown')
256
+ },
257
+ //浮层隐藏后
258
+ layerHidden() {
259
+ this.$emit('layerHidden')
260
+ },
261
+ //列表选择
262
+ select(item) {
263
+ if (this.disabled) {
264
+ return
265
+ }
266
+ this.$emit('operate', this.name, item.value)
267
+ this.hideLayer()
268
+ },
269
+ //按钮点击处理
270
+ handleClick() {
271
+ if (this.disabled) {
272
+ return
273
+ }
274
+ if (this.type == 'default') {
275
+ this.$emit('operate', this.name)
276
+ } else {
277
+ if (this.layerConfig.show) {
278
+ this.hideLayer()
279
+ } else {
280
+ this.layerConfig.node = this.$refs.btn
281
+ this.layerConfig.show = true
282
+ }
283
+ }
284
+ },
285
+ //鼠标移入处理
286
+ handleMouseEnter() {
287
+ this.status = 'hover'
288
+ },
289
+ //鼠标移出处理
290
+ handleMouseLeave() {
291
+ this.status = null
292
+ },
293
+ //鼠标按下处理
294
+ handleMouseDown() {
295
+ this.status = 'down'
296
+ },
297
+ //鼠标松开处理
298
+ handleMouseUp() {
299
+ this.status = 'hover'
300
+ }
301
+ }
302
+ }
303
+ </script>
304
+ <style lang="less" scoped>
305
+ .editify-button {
306
+ display: inline-flex;
307
+ justify-content: center;
308
+ align-items: center;
309
+ position: relative;
310
+ color: @font-color;
311
+ font-size: @font-size;
312
+
313
+ .editify-button-wrap {
314
+ padding: 0 4px;
315
+ position: relative;
316
+
317
+ &.right-border::after {
318
+ position: absolute;
319
+ right: 0;
320
+ top: 50%;
321
+ content: '';
322
+ transform: translateY(-50%);
323
+ height: 18px;
324
+ width: 1px;
325
+ background-color: @border-color;
326
+ }
327
+
328
+ &.left-border::before {
329
+ position: absolute;
330
+ left: 0;
331
+ top: 50%;
332
+ content: '';
333
+ transform: translateY(-50%);
334
+ height: 18px;
335
+ width: 1px;
336
+ background-color: @border-color;
337
+ }
338
+
339
+ .editify-button-el {
340
+ display: inline-flex;
341
+ justify-content: flex-start;
342
+ align-items: center;
343
+ white-space: nowrap;
344
+ height: 28px;
345
+ line-height: 1;
346
+ transition: all 200ms;
347
+ background-color: @background;
348
+ padding: 0 8px;
349
+ border-radius: 2px;
350
+
351
+ .editify-button-slot {
352
+ display: inline-flex;
353
+ justify-content: flex-start;
354
+ align-items: center;
355
+ }
356
+
357
+ .editify-button-caret {
358
+ margin-left: 2px;
359
+ transform: scale(0.6);
360
+ transition: transform 200ms;
361
+ font-size: 14px;
362
+
363
+ &.rotate {
364
+ transform: scale(0.6) rotate(180deg);
365
+ }
366
+ }
367
+
368
+ &:hover {
369
+ cursor: pointer;
370
+ background-color: @background-dark;
371
+ }
372
+
373
+ &:active,
374
+ &.active {
375
+ background-color: @background-darker;
376
+ }
377
+
378
+ &.disabled {
379
+ color: @font-color-disabled;
380
+ cursor: not-allowed;
381
+ background-color: @background;
382
+ }
383
+ }
384
+ }
385
+
386
+ .editify-button-layer {
387
+ display: block;
388
+ position: relative;
389
+ overflow-x: hidden;
390
+ overflow-y: auto;
391
+
392
+ .editify-button-options {
393
+ display: block;
394
+ width: 100%;
395
+ padding: 4px 0;
396
+
397
+ .editify-button-option {
398
+ display: flex;
399
+ justify-content: flex-start;
400
+ align-items: center;
401
+ width: 100%;
402
+ padding: 6px 12px;
403
+ transition: all 200ms;
404
+ opacity: 0.8;
405
+ white-space: nowrap;
406
+ text-overflow: ellipsis;
407
+ overflow: hidden;
408
+ box-sizing: border-box;
409
+
410
+ &:hover {
411
+ opacity: 1;
412
+ cursor: pointer;
413
+ background-color: @background-dark;
414
+ }
415
+
416
+ &:active {
417
+ opacity: 1;
418
+ background-color: @background-darker;
419
+ }
420
+
421
+ &.active {
422
+ opacity: 1;
423
+ background-color: @background-darker;
424
+ }
425
+
426
+ .editify-button-option-flex {
427
+ display: flex;
428
+ justify-content: flex-start;
429
+ align-items: center;
430
+ width: 100%;
431
+
432
+ :deep(.editify-icon) {
433
+ margin-right: 10px;
434
+ }
435
+ }
436
+ }
437
+ }
438
+ }
439
+ }
440
+ </style>
@@ -0,0 +1,196 @@
1
+ <template>
2
+ <label class="editify-checkbox" :class="{ disabled: disabled }">
3
+ <span v-if="placement == 'left' && label" class="editify-checkbox-label" :data-editify-placement="placement" v-text="label"></span>
4
+ <input @change="change" :value="value" :disabled="disabled" :checked="check" type="checkbox" />
5
+ <span class="editify-checkbox-item" :class="{ reverse: !color, round: round, checked: check && !disabled }" :style="itemStyle">
6
+ <Icon value="check" :style="{ opacity: check ? '' : 0 }" />
7
+ </span>
8
+ <span v-if="placement == 'right' && label" class="editify-checkbox-label" :data-editify-placement="placement" v-text="label"></span>
9
+ </label>
10
+ </template>
11
+
12
+ <script>
13
+ import Dap from 'dap-util'
14
+ import Icon from './Icon'
15
+ export default {
16
+ name: 'Checkbox',
17
+ emits: ['update:modelValue', 'change'],
18
+ props: {
19
+ //是否禁用
20
+ disabled: {
21
+ type: Boolean,
22
+ default: false
23
+ },
24
+ //是否选中
25
+ modelValue: {
26
+ type: [Boolean, Array],
27
+ default: false
28
+ },
29
+ //label文字
30
+ label: {
31
+ type: String,
32
+ default: null
33
+ },
34
+ //值
35
+ value: {
36
+ type: [Object, Number, String, Array],
37
+ default: ''
38
+ },
39
+ //是否圆形
40
+ round: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ //文字位置
45
+ placement: {
46
+ type: String,
47
+ default: 'right',
48
+ validator(value) {
49
+ return ['left', 'right'].includes(value)
50
+ }
51
+ },
52
+ //主题颜色
53
+ color: {
54
+ type: String,
55
+ default: '',
56
+ validator(value) {
57
+ return Dap.common.matchingText(value, 'hex')
58
+ }
59
+ }
60
+ },
61
+ computed: {
62
+ check() {
63
+ if (typeof this.modelValue == 'boolean') {
64
+ return this.modelValue
65
+ }
66
+ if (Array.isArray(this.modelValue)) {
67
+ //数组中是否已包含此复选框的值
68
+ return this.modelValue.some(item => {
69
+ return Dap.common.equal(item, this.value)
70
+ })
71
+ }
72
+ return false
73
+ },
74
+ itemStyle() {
75
+ let style = {}
76
+ if (this.color && this.check && !this.disabled) {
77
+ style.backgroundColor = this.color
78
+ style.borderColor = this.color
79
+ }
80
+ return style
81
+ }
82
+ },
83
+ components: {
84
+ Icon
85
+ },
86
+ methods: {
87
+ change(event) {
88
+ if (Array.isArray(this.modelValue)) {
89
+ let arr = [...this.modelValue]
90
+ //勾选且不包含
91
+ if (event.target.checked && !this.check) {
92
+ arr.push(this.value)
93
+ }
94
+ //取消且包含
95
+ else if (this.check) {
96
+ arr = arr.filter(item => {
97
+ return !Dap.common.equal(item, this.value)
98
+ })
99
+ }
100
+ this.$emit('update:modelValue', arr)
101
+ this.$emit('change', arr)
102
+ } else if (typeof this.modelValue == 'boolean') {
103
+ this.$emit('update:modelValue', event.target.checked)
104
+ this.$emit('change', event.target.checked)
105
+ }
106
+ }
107
+ }
108
+ }
109
+ </script>
110
+
111
+ <style scoped lang="less">
112
+ .editify-checkbox {
113
+ display: inline-flex;
114
+ margin: 0;
115
+ padding: 0;
116
+ position: relative;
117
+ vertical-align: middle;
118
+ justify-content: flex-start;
119
+ align-items: center;
120
+ cursor: pointer;
121
+ user-select: none;
122
+ font-size: @font-size;
123
+
124
+ input[type='checkbox'] {
125
+ width: 0;
126
+ height: 0;
127
+ opacity: 0;
128
+ border: none;
129
+ display: none;
130
+ }
131
+
132
+ .editify-checkbox-item {
133
+ display: inline-flex;
134
+ display: -webkit-inline-flex;
135
+ justify-content: center;
136
+ align-items: center;
137
+ position: relative;
138
+ margin: 0;
139
+ padding: 1px;
140
+ border: 1px solid @border-color;
141
+ background-color: @background;
142
+ border-radius: 2px;
143
+ color: @background;
144
+ transition: border-color 0.1s cubic-bezier(0.71, -0.46, 0.29, 1.46), background-color 0.1s cubic-bezier(0.71, -0.46, 0.29, 1.46), color 0.1s cubic-bezier(0.71, -0.46, 0.29, 1.46);
145
+
146
+ &.round {
147
+ border-radius: 50%;
148
+ }
149
+
150
+ &.checked {
151
+ background-color: @font-color;
152
+ border-color: @font-color;
153
+
154
+ &.reverse {
155
+ background-color: @background;
156
+ color: @font-color-light;
157
+ border-color: @border-color;
158
+ }
159
+ }
160
+
161
+ :deep(.editify-icon) {
162
+ font-size: 18px;
163
+ zoom: 50%;
164
+ }
165
+ }
166
+
167
+ .editify-checkbox-label {
168
+ vertical-align: middle;
169
+ color: @font-color;
170
+ user-select: none;
171
+ line-height: 1;
172
+
173
+ &[data-editify-placement='left'] {
174
+ margin-right: 6px;
175
+ }
176
+
177
+ &[data-editify-placement='right'] {
178
+ margin-left: 6px;
179
+ }
180
+ }
181
+
182
+ &.disabled {
183
+ cursor: not-allowed;
184
+ .editify-checkbox-item,
185
+ .editify-checkbox-item.check {
186
+ background-color: @background-darker;
187
+ border-color: @border-color;
188
+ color: @font-color-disabled;
189
+ }
190
+
191
+ .editify-checkbox-label {
192
+ color: @font-color-disabled;
193
+ }
194
+ }
195
+ }
196
+ </style>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <i class="editify-icon" :class="'editify-icon-' + value"></i>
3
+ </template>
4
+ <script>
5
+ export default {
6
+ name: 'Icon',
7
+ props: {
8
+ //图标值
9
+ value: {
10
+ type: String,
11
+ default: ''
12
+ }
13
+ }
14
+ }
15
+ </script>
16
+ <style lang="less" scoped>
17
+ @font-face {
18
+ font-family: 'editify-icon';
19
+ src: url('../../icon/iconfont.woff?t=1699274556400') format('woff'), url('../../icon/iconfont.ttf?t=1699274556400') format('truetype');
20
+ }
21
+
22
+ .editify-icon {
23
+ font-family: 'editify-icon' !important;
24
+ font-size: inherit;
25
+ font-style: normal;
26
+ -webkit-font-smoothing: antialiased;
27
+ -moz-osx-font-smoothing: grayscale;
28
+ line-height: 1;
29
+ vertical-align: middle;
30
+ }
31
+ </style>