Skip to content

Commit 17af58a

Browse files
committed
dropdown comp add before-visible-change callback method
1 parent 6b09ced commit 17af58a

File tree

2 files changed

+109
-25
lines changed

2 files changed

+109
-25
lines changed

packages/ve-dropdown/src/index.jsx

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import VeCheckbox from "vue-easytable/packages/ve-checkbox";
33
import VeRadio from "vue-easytable/packages/ve-radio";
44
import { COMPS_NAME, EMIT_EVENTS } from "./util/constant";
55
import { clsName } from "./util/index";
6+
import { isFunction, isBoolean } from "../../src/utils";
67
import { getRandomId } from "../../src/utils/random";
78
import {
89
getViewportOffset,
@@ -111,6 +112,14 @@ export default {
111112
return document.body;
112113
},
113114
},
115+
/*
116+
before visible change
117+
如果返回false 则阻止显示或者关闭
118+
*/
119+
beforeVisibleChange: {
120+
type: Function,
121+
default: null,
122+
},
114123
},
115124
data() {
116125
return {
@@ -232,30 +241,17 @@ export default {
232241
this.hideDropDown();
233242
},
234243

235-
// hide dropdown
236-
hideDropDown() {
237-
this.$emit(EMIT_EVENTS.VISIBLE_CHANGE, false);
238-
239-
setTimeout(() => {
240-
this.internalVisible = false;
241-
this.removeOrEmptyRootPanel();
242-
}, 150);
243-
},
244-
245-
// remove or emoty root panel
246-
removeOrEmptyRootPanel() {
247-
const { rootId } = this;
248-
249-
let rootEl = document.querySelector(`#${rootId}`);
250-
if (rootEl) {
251-
rootEl.innerHTML = "";
252-
}
253-
},
254-
255244
// show dropdown
256245
showDropDown() {
257246
const { rootId, dropdownItemsPanelId } = this;
258247

248+
const nextVisible = true;
249+
250+
const allowChange = this.beforeVisibleChangeCallback(nextVisible);
251+
if (isBoolean(allowChange) && !allowChange) {
252+
return false;
253+
}
254+
259255
let rootEl = document.querySelector(`#${rootId}`);
260256

261257
if (rootEl) {
@@ -271,7 +267,51 @@ export default {
271267

272268
this.internalVisible = true;
273269

274-
this.$emit(EMIT_EVENTS.VISIBLE_CHANGE, true);
270+
this.$emit(EMIT_EVENTS.VISIBLE_CHANGE, nextVisible);
271+
},
272+
273+
// hide dropdown
274+
hideDropDown() {
275+
const nextVisible = false;
276+
277+
const allowChange = this.beforeVisibleChangeCallback(nextVisible);
278+
if (isBoolean(allowChange) && !allowChange) {
279+
return false;
280+
}
281+
282+
this.$emit(EMIT_EVENTS.VISIBLE_CHANGE, nextVisible);
283+
284+
setTimeout(() => {
285+
this.internalVisible = false;
286+
this.removeOrEmptyRootPanel();
287+
}, 150);
288+
},
289+
290+
// before visible change callback
291+
beforeVisibleChangeCallback(nextVisible) {
292+
// console.log("nextVisible22::", nextVisible);
293+
const { beforeVisibleChange, isDropdownVisible } = this;
294+
295+
if (nextVisible === isDropdownVisible) {
296+
return false;
297+
}
298+
299+
if (isFunction(beforeVisibleChange)) {
300+
// next visible
301+
return beforeVisibleChange({
302+
nextVisible,
303+
});
304+
}
305+
},
306+
307+
// remove or emoty root panel
308+
removeOrEmptyRootPanel() {
309+
const { rootId } = this;
310+
311+
let rootEl = document.querySelector(`#${rootId}`);
312+
if (rootEl) {
313+
rootEl.innerHTML = "";
314+
}
275315
},
276316

277317
// change dropdown panel position
@@ -366,10 +406,14 @@ export default {
366406
this.inputValue = result;
367407
},
368408

369-
// dropdown show toggle
370-
dropdownShowToggle() {
409+
// dropdown panel click
410+
dropdownPanelClick() {
371411
this.isDropdownShowTriggerClicked = true;
412+
this.dropdownShowToggle();
413+
},
372414

415+
// dropdown show toggle
416+
dropdownShowToggle() {
373417
if (this.isDropdownVisible) {
374418
this.hideDropDown();
375419
} else {
@@ -520,7 +564,7 @@ export default {
520564
isSelect,
521565
width,
522566
maxHeight,
523-
dropdownShowToggle,
567+
dropdownPanelClick,
524568
getMaxWidth,
525569
reset,
526570
singleSelectOptionClick,
@@ -614,7 +658,7 @@ export default {
614658

615659
return (
616660
<dl {...dropdownProps}>
617-
<dt class="ve-dropdown-dt" on-click={dropdownShowToggle}>
661+
<dt class="ve-dropdown-dt" on-click={dropdownPanelClick}>
618662
<a
619663
class={[isSelect ? clsName("dt-selected") : ""]}
620664
style={{ width: width + "px" }}

tests/unit/specs/ve-dropdown.spec.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,4 +426,44 @@ describe("veDropdown", () => {
426426
.length,
427427
).toEqual(0);
428428
});
429+
430+
it("beforeVisibleChange callback method", async () => {
431+
const mockBeforeVisibleChangeFn = jest.fn();
432+
const wrapper = mount({
433+
render() {
434+
return (
435+
<ve-dropdown
436+
hide-by-item-click={true}
437+
before-visible-change={(args) =>
438+
mockBeforeVisibleChangeFn(args)
439+
}
440+
value={DROPDOWN_ITEMS}
441+
// slots= {
442+
// default: `<div class="btn">click me</div>`,
443+
// }
444+
>
445+
<div class="btn" style="color:blue;cursor: pointer;">
446+
点击这里
447+
</div>
448+
</ve-dropdown>
449+
);
450+
},
451+
});
452+
453+
wrapper.find(".btn").trigger("click");
454+
await later(100);
455+
expect(wrapper.find(".ve-dropdown-dd-show").exists()).toBe(true);
456+
457+
expect(mockBeforeVisibleChangeFn).toHaveBeenCalledWith({
458+
nextVisible: true,
459+
});
460+
461+
wrapper.find(".ve-dropdown-items-li").trigger("click");
462+
await later(150);
463+
464+
expect(wrapper.find(".ve-dropdown-dd-show").exists()).toBe(false);
465+
expect(mockBeforeVisibleChangeFn).toHaveBeenCalledWith({
466+
nextVisible: false,
467+
});
468+
});
429469
});

0 commit comments

Comments
 (0)