@elementplus-kit/uikit 1.0.5 → 1.2.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.
@@ -170,7 +170,6 @@ export default defineComponent({
170
170
 
171
171
  // 渲染表单
172
172
  const renderForm = () => {
173
- console.log("$attrs", $attrs);
174
173
  return h(
175
174
  ElConfigProvider,
176
175
  {
@@ -1,35 +1,29 @@
1
- import {
2
- ref,
3
- computed,
4
- defineComponent,
5
- } from "vue";
1
+ import { ref, defineComponent, onMounted, onUnmounted, nextTick } from "vue";
6
2
 
7
3
  import { CForm, CDrawer } from "@elementplus-kit/uikit";
8
4
  import { ArrowUpBold } from "@element-plus/icons-vue";
9
- import '../style/index.scss';
5
+ import "../style/index.scss";
10
6
 
11
7
  export default defineComponent({
12
8
  props: {
13
9
  modelValue: {
14
10
  type: Object,
15
- default: {}
11
+ default: {},
16
12
  },
17
13
  formOptions: {
18
14
  type: Array,
19
- default: () => []
15
+ default: () => [],
20
16
  },
21
17
  isDrawer: {
22
18
  type: Boolean,
23
- default: false
19
+ default: false,
24
20
  },
25
21
  },
26
- emits: ['update:modelValue', 'search', 'reset', 'close'],
22
+ emits: ["update:modelValue", "search", "reset", "close"],
27
23
 
28
24
  setup(props, { emit, slots, attrs, expose }) {
29
25
  // 自己的 slot
30
26
  const slotsList = ["active", "btn-left", "btn-right"];
31
- // console.log('slots', slots);
32
- // console.log('attrs', attrs);
33
27
  // 解析 attrs 中的事件
34
28
  const getEvent = () => {
35
29
  let formObj: any = {};
@@ -37,8 +31,8 @@ export default defineComponent({
37
31
  if (name.indexOf("on") === 0) {
38
32
  formObj[name] = attrs[name];
39
33
  }
40
- })
41
- return formObj
34
+ });
35
+ return formObj;
42
36
  };
43
37
 
44
38
  // 解析插槽
@@ -49,13 +43,14 @@ export default defineComponent({
49
43
  formObj[key] = slots[key];
50
44
  }
51
45
  });
52
- return formObj
46
+ return formObj;
53
47
  };
54
48
 
55
49
  // 搜索
56
50
  const handleSearch = () => {
57
51
  emit("search");
58
52
  showSearchForm.value = false;
53
+ document.removeEventListener("click", handleClickOutside); // 销毁点击事件
59
54
  };
60
55
  // 重置
61
56
  const handleReset = () => {
@@ -64,65 +59,198 @@ export default defineComponent({
64
59
  // 关闭
65
60
  const handleClose = () => {
66
61
  showSearchForm.value = false;
62
+ document.removeEventListener("click", handleClickOutside); // 销毁点击事件
67
63
  emit("close");
68
64
  };
65
+ // 点击元素外关闭
66
+ const dropdownRef = ref<HTMLElement | null>(null); // 下拉表单的 ref
67
+ // 判断点击事件是否在 targetElement 外部
68
+ const isClickOutside = (event, targetElement) => {
69
+ console.log("🚀 ~ isClickOutside ~ targetElement:", targetElement);
70
+ return !targetElement.contains(event.target);
71
+ };
72
+ // 点击外部关闭函数
73
+ const handleClickOutside = (event: MouseEvent) => {
74
+ // 如果下拉表单可见,且点击事件不在下拉表单内部
75
+ if (
76
+ showSearchForm.value &&
77
+ dropdownRef.value &&
78
+ !dropdownRef.value?.$el?.contains(event.target)
79
+ ) {
80
+ showSearchForm.value = false; // 关闭下拉表单
81
+ document.removeEventListener("click", handleClickOutside); // 销毁点击事件
82
+ }
83
+ };
84
+ // 显示隐藏折叠搜索表单
85
+ const showSearchForm = ref(false);
86
+ const handleShow = () => {
87
+ if (showSearchForm.value) {
88
+ showSearchForm.value = false;
89
+ document.removeEventListener("click", handleClickOutside); // 销毁点击事件
90
+ } else {
91
+ showSearchForm.value = true;
92
+ setTimeout(() => {
93
+ document.addEventListener("click", handleClickOutside); // 注册点击事件
94
+ }, 0);
95
+ }
96
+ };
69
97
 
70
- const showCountC = computed(() => {
71
- return props.showCount;
72
- });
98
+ const showCount = ref(6); // 显示个数
99
+ const simpleRef = ref<HTMLDivElement>(null);
100
+ const simpleFormRef = ref<HTMLDivElement>(null);
101
+ const simpleBtnRef = ref<HTMLDivElement>(null);
102
+ const cFormRef = ref<HTMLDivElement>(null);
103
+ const calcFlg = ref(false); // 计算宽度后再显示表单
104
+ const childW = ref([]);
73
105
 
74
- const showCount = ref(3); // 显示个数
75
- const showSearchForm = ref(false); // 显示搜索表单
76
- const handleShow = () => {
77
- showSearchForm.value = !showSearchForm.value;
106
+ // 设置节流
107
+ let timer: any = null;
108
+ const searchResize = () => {
109
+ if (timer) {
110
+ clearTimeout(timer);
111
+ }
112
+ timer = setTimeout(() => {
113
+ calcSunResize();
114
+ }, 200);
115
+ };
116
+
117
+ // 初次计算显示个数
118
+ const calcSunInit = () => {
119
+ if (simpleFormRef.value) {
120
+ // 寻找cForm 先写死 后期做成动态寻找
121
+ const cFormDom = simpleFormRef.value.children[0];
122
+ const cFormW = cFormDom.offsetWidth;
123
+ // 收集子元素宽度并保存到数组中
124
+ const cW = [];
125
+ // const marginR = [];
126
+ Array.from(cFormDom.children).map((child) => {
127
+ const computedStyles = window.getComputedStyle(child); // 获取元素 css 样式
128
+ const mg = computedStyles.marginRight; // 获取元素 margin-right 样式值 有单位
129
+ const mgValue = parseFloat(mg); // 转换为数值
130
+ // marginR.push(mgValue);
131
+ cW.push(child.offsetWidth + mgValue); // 把mg加上 mg 一般不会变 为了避免多次计算
132
+ });
133
+ childW.value = cW; // 储存子元素宽度
134
+ childW.value.reduce((pre, cur, index) => {
135
+ if (pre > cFormW) {
136
+ return 10000; // 终止累加
137
+ }
138
+ if (pre + cur > cFormW) {
139
+ showCount.value = index;
140
+ return pre + cur;
141
+ }
142
+ return pre + cur;
143
+ }, 0);
144
+ }
78
145
  };
79
- return () => (
80
- <div className="c-search">
81
- <div className="c-search-simple">
82
- <div className="c-search-simple-form">
83
- <CForm
84
- {...getEvent()}
85
- inline
86
- model={props.modelValue}
87
- formOptions={props.formOptions?.filter(
88
- (item, index) => index < showCount.value
146
+ // 变化时计算显示个数
147
+ const calcSunResize = () => {
148
+ if (simpleFormRef.value) {
149
+ // 寻找cForm 先写死 后期做成动态寻找
150
+ const cFormDom = simpleFormRef.value.children[0];
151
+ const cFormW = cFormDom.offsetWidth;
152
+ childW.value.reduce((pre, cur, index) => {
153
+ if (pre > cFormW) {
154
+ return 10000; // 终止累加
155
+ }
156
+ if (pre + cur > cFormW) {
157
+ showCount.value = index;
158
+ return pre + cur;
159
+ }
160
+ return pre + cur;
161
+ }, 0);
162
+ }
163
+ };
164
+
165
+ onMounted(() => {
166
+ // 初始化执行一次
167
+ calcSunInit();
168
+ // 注册页面大小函数
169
+ window.addEventListener("resize", searchResize);
170
+ });
171
+ // 销毁
172
+ onUnmounted(() => {
173
+ window.removeEventListener("resize", searchResize);
174
+ document.removeEventListener("click", handleClickOutside); // 销毁点击事件
175
+ });
176
+ return () => {
177
+ return (
178
+ <div className="c-search">
179
+ <div
180
+ className="c-search-simple"
181
+ ref={simpleRef}
182
+ >
183
+ <div className="c-search-simple-form" ref={simpleFormRef}>
184
+ <CForm
185
+ ref={(el) => (cFormRef.value = el)}
186
+ {...getEvent()}
187
+ inline
188
+ model={props.modelValue}
189
+ formOptions={props.formOptions?.filter(
190
+ (item, index) => index < showCount.value
191
+ )}
192
+ >
193
+ {getSlot()}
194
+ </CForm>
195
+ </div>
196
+ <div className="c-search-simple-btn" ref={simpleBtnRef}>
197
+ {slots["btn-left"]?.()}
198
+ {showCount.value < props.formOptions?.length && (
199
+ <div
200
+ className={`c-search-simple-icon ${showSearchForm.value ? "icon-rotate" : ""
201
+ }`}
202
+ onClick={handleShow}
203
+ >
204
+ <el-icon className="el-icon c-search-icon">
205
+ <ArrowUpBold />
206
+ </el-icon>
207
+ </div>
89
208
  )}
90
- ref="formRef"
91
- >
92
- {getSlot()}
93
- </CForm>
209
+ <el-button type="primary" onClick={handleSearch}>
210
+ 搜索
211
+ </el-button>
212
+ <el-button type="primary" onClick={handleReset}>
213
+ 重置
214
+ </el-button>
215
+ {slots["btn-right"]?.()}
216
+ </div>
94
217
  </div>
95
- <div className="c-search-simple-btn">
96
- {slots["btn-left"]?.()}
97
- {showCount.value < props.formOptions?.length && (
98
- <div
99
- className={
100
- `c-search-simple-icon ${showSearchForm.value ? "icon-rotate" : ""}`
101
- }
102
- onClick={handleShow}
218
+
219
+ {/* 下拉悬浮 */}
220
+ {!props.isDrawer && showSearchForm.value && (
221
+ <transition name="search-form-transition">
222
+ <el-card
223
+ ref={dropdownRef}
224
+ className="c-search-form el-card is-always-shadow"
103
225
  >
104
- <el-icon className="el-icon c-search-icon">
105
- <ArrowUpBold />
106
- </el-icon>
107
- </div>
108
- )}
109
- <el-button type="primary" onClick={handleSearch}>
110
- 搜索
111
- </el-button>
112
- <el-button type="primary" onClick={handleReset}>
113
- 重置
114
- </el-button>
115
- {slots["btn-right"]?.()}
116
- </div>
117
- </div>
226
+ <CForm
227
+ {...getEvent()}
228
+ inline
229
+ model={props.modelValue}
230
+ formOptions={props.formOptions.filter(
231
+ (item, index) => index >= showCount.value
232
+ )}
233
+ ref="formRef"
234
+ >
235
+ {getSlot()}
236
+ </CForm>
237
+ <div style="text-align: right;">
238
+ <el-button type="primary" onClick={handleSearch}>
239
+ 搜索
240
+ </el-button>
241
+ <el-button type="primary" onClick={handleClose}>
242
+ 关闭
243
+ </el-button>
244
+ </div>
245
+ </el-card>
246
+ </transition>
247
+ )}
118
248
 
119
- {/* 下拉悬浮 */}
120
- {!props.isDrawer && showSearchForm.value && (
121
- <transition name="search-form-transition">
122
- <el-card className="c-search-form el-card is-always-shadow">
249
+ {props.isDrawer && (
250
+ <CDrawer title="搜索" v-model={showSearchForm.value} size="660px">
123
251
  <CForm
124
252
  {...getEvent()}
125
- inline
253
+ col={12}
126
254
  model={props.modelValue}
127
255
  formOptions={props.formOptions.filter(
128
256
  (item, index) => index >= showCount.value
@@ -139,34 +267,10 @@ export default defineComponent({
139
267
  关闭
140
268
  </el-button>
141
269
  </div>
142
- </el-card>
143
- </transition>
144
- )}
145
-
146
- {props.isDrawer && (
147
- <CDrawer title="搜索" v-model={showSearchForm.value} size="660px">
148
- <CForm
149
- {...getEvent()}
150
- col={12}
151
- model={props.modelValue}
152
- formOptions={props.formOptions.filter(
153
- (item, index) => index >= showCount.value
154
- )}
155
- ref="formRef"
156
- >
157
- {getSlot()}
158
- </CForm>
159
- <div style="text-align: right;">
160
- <el-button type="primary" onClick={handleSearch}>
161
- 搜索
162
- </el-button>
163
- <el-button type="primary" onClick={handleClose}>
164
- 关闭
165
- </el-button>
166
- </div>
167
- </CDrawer>
168
- )}
169
- </div>
170
- )
270
+ </CDrawer>
271
+ )}
272
+ </div>
273
+ );
274
+ };
171
275
  },
172
- })
276
+ });
@@ -11,7 +11,15 @@
11
11
  display: flex;
12
12
  justify-content: space-between;
13
13
  }
14
-
14
+ .c-search-simple-form {
15
+ flex: 1; // 占满剩余空间
16
+ overflow: auto; // 开启滚动条
17
+ // 滚动条宽度
18
+ scrollbar-width: none; // 隐藏滚动条
19
+ > .c-form {
20
+ white-space: nowrap; // 防止表单内容换行
21
+ }
22
+ }
15
23
  .c-search-simple-btn {
16
24
  display: flex;
17
25
  margin-left: auto;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementplus-kit/uikit",
3
- "version": "1.0.5",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "./components/index.ts",
6
6
  "peerDependencies": {
@@ -1,256 +0,0 @@
1
- <template>
2
- <div class="c-search">
3
- <div class="c-search-simple">
4
- <div class="c-search-simple-form">
5
- <c-form v-bind="getEvent(), getSlot('form')" inline :model="formData"
6
- :formOptions="props.formOptions.filter((item, index) => index < showCount)" ref="formRef">
7
- <template #[`c-search-button`]>
8
- <slot name="active"></slot>
9
- </template>
10
- </c-form>
11
- </div>
12
- <div class="c-search-simple-btn">
13
- <slot name="btn-left" />
14
- <div class="c-search-simple-icon" @click="handleShow" v-if="showCount < props.formOptions.length"
15
- :class="{ 'icon-rotate': showSearchForm }">
16
- <el-icon class="c-search-icon">
17
- <ArrowUpBold />
18
- </el-icon>
19
- </div>
20
- <el-button type="primary" @click="handleSearch">搜索</el-button>
21
- <el-button type="primary" @click="handleReset">重置</el-button>
22
- <slot name="btn-right" />
23
- </div>
24
- </div>
25
- <!-- 下拉悬浮 -->
26
- <transition name="search-form-transition">
27
- <el-card class="c-search-form" v-if="showSearchForm && props.isDrawer">
28
- <c-form v-bind="getEvent(), getSlot('form')"" inline :model="formData"
29
- :formOptions="props.formOptions.filter((item, index) => index >= showCount)" ref="formRef">
30
- </c-form>
31
- <div style="text-align: right;">
32
- <el-button type="primary" @click="handleSearch">搜索</el-button>
33
- <el-button type="primary" @click="handleClose">关闭</el-button>
34
- </div>
35
- </el-card>
36
- </transition>
37
- <c-drawer v-if="!props.isDrawer" title="搜索" v-model="showSearchForm" size="660px">
38
- <c-form v-bind="getEvent(), getSlot('form')" :col="12" :model="formData"
39
- :formOptions="props.formOptions.filter((item, index) => index >= showCount)" ref="formRef">
40
- </c-form>
41
- <div style="text-align: right;">
42
- <el-button type="primary" @click="handleSearch">搜索</el-button>
43
- <el-button type="primary" @click="handleClose">关闭</el-button>
44
- </div>
45
- </c-drawer>
46
- </div>
47
- </template>
48
- <script setup lang="ts">
49
- import { ref, computed, useAttrs, useSlots, defineModel } from 'vue'
50
- import { CForm, CDrawer } from '@elementplus-kit/uikit'
51
- import { ArrowUpBold } from '@element-plus/icons-vue'
52
- const props = defineProps({
53
- formOptions: {
54
- type: Array,
55
- default: () => []
56
- },
57
- formItemButton: {
58
- type: Object,
59
- default: () => ({
60
- label: '',
61
- prop: 'c-button',
62
- })
63
- },
64
- isDrawer: {
65
- type: Boolean,
66
- default: true
67
- },
68
- showCount: { // 显示简洁栏的个数
69
- type: Number,
70
- default: 3
71
- }
72
- })
73
- const emit = defineEmits(['search', 'reset', 'close'])
74
-
75
- const formData = defineModel()
76
- const attr = useAttrs()
77
- const slots = useSlots()
78
-
79
- // 自己的 slot
80
- const slotsMap = ['active']
81
- // 解析 attr 中的事件
82
- const getEvent = (name: string) => {
83
- let obj = {}
84
- Object.keys(attr).forEach(key => {
85
- if (key.startsWith('on')) {
86
- obj[key] = attr[key]
87
- }
88
- })
89
- return obj
90
- }
91
-
92
- // 解析插槽
93
- const getSlot = (type: 'form' | 'search') => {
94
- let searchObj: any = {}
95
- let formObj: any = {}
96
- Object.keys(slots).forEach(key => {
97
- if (slotsMap.includes(key)) {
98
- searchObj[key] = slots[key]
99
- } else {
100
- formObj[key] = slots[key]
101
- }
102
- })
103
- return type === 'search' ? formObj : searchObj
104
- }
105
-
106
- const handleSearch = () => {
107
- emit('search')
108
- showSearchForm.value = false
109
- }
110
-
111
- const handleReset = () => {
112
- emit('reset')
113
- }
114
-
115
- const handleClose = () => {
116
- showSearchForm.value = false
117
- emit('close')
118
- }
119
- const showCountC = computed(() => {
120
- return props.showCount
121
- })
122
-
123
- const showCount = ref(3) // 显示个数
124
- const showSearchForm = ref(false) // 显示搜索表单
125
- const handleShow = () => {
126
- showSearchForm.value = !showSearchForm.value
127
- }
128
-
129
- // const formOptionsSimple = computed(() => {
130
- // // 取3为简洁栏
131
- // const l = props.formOptions?.slice(0, 3)
132
- // l.push(props.formItemButton)
133
- // formOptionsHidden.value = props.formOptions?.slice(3)
134
- // return l
135
- // })
136
-
137
- // // const formOptionsSimple = ref([]) // 简洁栏
138
- // // const formOptionsHidden = ref([]) // 隐藏栏
139
-
140
- // 窗口大小变化时,调整搜索表单的宽度
141
- // const handleResize = () => {
142
- // if (window.innerWidth <= 768) {
143
- // formOptions.value.forEach(item => {
144
- // item.col = {
145
- // span: 24
146
- // }
147
- // })
148
- // } else {
149
- // formOptions.value.forEach(item => {
150
- // item.col = {
151
- // span: 8
152
- // }
153
- // })
154
- // }
155
- // }
156
- // window.addEventListener('resize', handleResize)
157
- </script>
158
- <style scoped lang="scss">
159
- .search-btn {
160
- margin-right: 20px;
161
- margin-left: auto;
162
- }
163
-
164
- .c-search {
165
- position: relative;
166
- height: 50px;
167
-
168
- .c-search-simple {
169
- display: flex;
170
- justify-content: space-between;
171
- }
172
-
173
- .c-search-simple-btn {
174
- display: flex;
175
- margin-left: auto;
176
- }
177
-
178
- .c-search-simple-icon {
179
- display: flex;
180
- justify-content: center;
181
- align-items: center;
182
- cursor: pointer;
183
- height: 32px;
184
- width: 32px;
185
- margin-right: 10px;
186
- border-radius: 4px;
187
- background-color: #409eff;
188
- transition: all 0.2s;
189
-
190
- &:hover {
191
- background-color: rgb(121, 187, 255);
192
- }
193
-
194
- &:active {
195
- background-color: rgb(51, 126, 204);
196
- }
197
- }
198
-
199
- .c-search-icon {
200
- // 添加鼠标悬停效果
201
- display: inline-block;
202
- color: #fff;
203
- transition: all 0.2s;
204
-
205
- }
206
-
207
- .icon-rotate {
208
- background-color: rgb(51, 126, 204);
209
-
210
- .c-search-icon {
211
- transform: rotate(180deg);
212
- }
213
- }
214
-
215
- .c-search-form {
216
- width: 100%;
217
- position: absolute;
218
- top: 50px;
219
- left: 0;
220
- overflow: hidden;
221
- z-index: 10;
222
- background-color: #fff;
223
- }
224
- }
225
-
226
- /* 下拉动画效果 */
227
- .search-form-transition {
228
-
229
- &-enter-active,
230
- &-leave-active {
231
- transition: all 0.3s ease;
232
- /* 动画过渡时间和缓动函数 */
233
- overflow: hidden;
234
- max-height: 500px;
235
- /* 确保足够大的最大高度以容纳内容 */
236
- }
237
-
238
- &-enter-from {
239
- max-height: 0;
240
- /* 入场开始时高度为0 */
241
- opacity: 0;
242
- /* 可以添加透明度效果增强视觉体验 */
243
- padding-top: 0;
244
- padding-bottom: 0;
245
- }
246
-
247
- &-leave-to {
248
- max-height: 0;
249
- /* 出场结束时高度为0 */
250
- opacity: 0;
251
- /* 可以添加透明度效果增强视觉体验 */
252
- padding-top: 0;
253
- padding-bottom: 0;
254
- }
255
- }
256
- </style>