song-ui-u
Version:
vue3 + js的PC前端组件库
287 lines (283 loc) • 9.3 kB
JavaScript
;
var vue = require('vue');
var index$1 = require('../../../hook/use-namespace/index.cjs');
var icons = require('song-ui-pro-icon');
require('../../../hook/use-zindex/index.cjs');
var constant = require('./constant.cjs');
require('../../button/index.cjs');
require('../../buttonGroup/index.cjs');
var index = require('../../icon/index.cjs');
require('../../input/index.cjs');
require('../../textarea/index.cjs');
require('../../row/index.cjs');
require('../../col/index.cjs');
require('../../container/index.cjs');
require('../../checkbox/index.cjs');
require('../../switch/index.cjs');
require('../../form/index.cjs');
require('../../message/index.cjs');
require('../../mask/src/mask.cjs');
require('../../modal/index.cjs');
require('../../messageBox/index.cjs');
require('../../drawer/index.cjs');
require('../../badge/index.cjs');
require('../../space/index.cjs');
require('../../image/index.cjs');
require('../../radio/index.cjs');
require('../../divider/index.cjs');
require('../../chat/index.cjs');
require('../../progress/index.cjs');
require('../../upload/index.cjs');
require('../../vTree/index.cjs');
require('../../table/index.cjs');
require('../../tabs/index.cjs');
require('../../menu/index.cjs');
require('../../steps/index.cjs');
require('../../header/index.cjs');
require('../../breadcrumble/index.cjs');
require('../../datePicker/index.cjs');
require('../../tooltip/index.cjs');
require('../../popover/index.cjs');
require('../../timePicker/index.cjs');
require('../index.cjs');
require('../../collapse/index.cjs');
require('../../card/index.cjs');
require('../../timeline/index.cjs');
require('../../tag/index.cjs');
require('../../result/index.cjs');
require('../../sender/index.cjs');
var Select = /* @__PURE__ */ vue.defineComponent({
name: "x-select",
props: {
modelValue: {
type: [String, Number, Array],
default: ""
},
multiple: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: "\u8BF7\u9009\u62E9"
},
filterable: {
type: Boolean,
default: false
},
size: {
type: String,
default: "default"
},
width: {
type: String,
default: "100%"
}
},
emits: ["update:modelValue", "change", "clear", "blur", "focus"],
setup(props, {
slots,
emit
}) {
const ns = index$1.useNamespace("select");
const visible = vue.ref(false);
const selectedLabel = vue.ref("");
const selectedLabels = vue.ref([]);
const inputValue = vue.ref("");
const options = vue.ref([]);
const selectRef = vue.ref(null);
const inputRef = vue.ref(null);
const dropdownRef = vue.ref(null);
const isFocus = vue.ref(false);
const isHover = vue.ref(false);
const styleWidth = vue.computed(() => ({
width: props.width
}));
const controlSize = vue.computed(() => props.size);
const registerOption = (option) => {
options.value.push(option);
};
const unregisterOption = (id) => {
const index = options.value.findIndex((option) => option.id === id);
if (index !== -1) {
options.value.splice(index, 1);
}
};
const selectOption = (value, label) => {
if (props.multiple) {
const values = Array.isArray(props.modelValue) ? [...props.modelValue] : [];
const index = values.indexOf(value);
if (index === -1) {
values.push(value);
selectedLabels.value.push(label);
} else {
values.splice(index, 1);
selectedLabels.value.splice(index, 1);
}
emit("update:modelValue", values);
emit("change", values);
} else {
if (selectedLabel.value == label) {
selectedLabel.value = "";
} else {
selectedLabel.value = label;
}
emit("update:modelValue", value);
emit("change", value);
closeDropdown();
}
};
const clearSelection = (e) => {
e.stopPropagation();
console.log("clearSelection");
if (props.multiple) {
emit("update:modelValue", []);
selectedLabels.value = [];
} else {
emit("update:modelValue", "");
selectedLabel.value = "";
}
emit("clear");
};
const toggleDropdown = () => {
if (props.disabled) return;
visible.value = !visible.value;
if (visible.value && props.filterable) {
vue.nextTick(() => {
inputRef.value?.focus();
});
}
};
const closeDropdown = () => {
visible.value = false;
if (props.filterable) {
inputValue.value = "";
}
};
const handleInput = (e) => {
inputValue.value = e.target.value;
};
const handleFocus = () => {
isFocus.value = true;
emit("focus");
};
const handleBlur = () => {
isFocus.value = false;
emit("blur");
};
const handleMouseEnter = () => {
isHover.value = true;
};
const handleMouseLeave = () => {
isHover.value = false;
};
const isOptionSelected = (value) => {
if (props.multiple) {
return Array.isArray(props.modelValue) && props.modelValue.includes(value);
}
return props.modelValue === value && selectedLabel.value;
};
vue.watch(() => props.modelValue, (newVal) => {
if (props.multiple) ; else {
const selectedOption = options.value.find((option) => option.value === newVal);
selectedLabel.value = selectedOption ? selectedOption.label : "";
}
}, {
immediate: true
});
vue.provide(constant.SELECT_KEY, {
props,
registerOption,
unregisterOption,
selectOption,
isOptionSelected,
inputValue
});
const handleClickOutside = (e) => {
if (selectRef.value && !selectRef.value.contains(e.target)) {
closeDropdown();
}
};
vue.watch(visible, (newVal) => {
if (newVal) {
document.addEventListener("click", handleClickOutside);
} else {
document.removeEventListener("click", handleClickOutside);
}
});
return () => vue.createVNode("div", {
"ref": selectRef,
"style": styleWidth.value,
"class": [ns.b(), ns.is("focus", isFocus.value), ns.is("disabled", props.disabled), ns.m("size", controlSize.value), ns.is("clearable", props.clearable && !props.disabled && (props.multiple ? selectedLabels.value.length > 0 : selectedLabel.value)), ns.is("multiple", props.multiple), ns.is("filterable", props.filterable)],
"onClick": toggleDropdown,
"onMouseenter": handleMouseEnter,
"onMouseleave": handleMouseLeave
}, [vue.createVNode("div", {
"class": [ns.e("wrapper"), ns.is("hover", isHover.value && !props.disabled)]
}, [props.multiple ? vue.createVNode("div", {
"class": [ns.e("tags")]
}, [selectedLabels.value.length > 0 ? selectedLabels.value.map((label, index$1) => vue.createVNode("span", {
"class": [ns.e("tag")],
"key": index$1
}, [label, vue.createVNode(index.XIcon, {
"onClick": (e) => {
e.stopPropagation();
selectOption(props.modelValue[index$1], label);
}
}, {
default: () => [vue.createVNode(icons.X, null, null)]
})])) : vue.createVNode("span", {
"class": [ns.e("placeholder")]
}, null), props.filterable && vue.createVNode("input", {
"ref": inputRef,
"type": "text",
"class": [ns.e("filter-input")],
"value": inputValue.value,
"onInput": handleInput,
"disabled": props.disabled,
"onFocus": handleFocus,
"onBlur": handleBlur,
"placeholder": selectedLabel.value || props.placeholder
}, null)]) : (
/* 单选模式 */
vue.createVNode("div", {
"class": [ns.e("selected")]
}, [props.filterable && visible.value ? vue.createVNode("input", {
"ref": inputRef,
"type": "text",
"class": [ns.e("filter-input")],
"value": inputValue.value,
"placeholder": selectedLabel.value || props.placeholder,
"onInput": handleInput,
"onFocus": handleFocus,
"onBlur": handleBlur
}, null) : vue.createVNode("span", {
"class": [selectedLabel.value ? ns.e("label") : ns.e("placeholder")]
}, [selectedLabel.value || props.placeholder])])
), props.clearable && !props.disabled && (props.multiple ? selectedLabels.value.length > 0 : selectedLabel.value) && isHover.value && vue.createVNode(index.XIcon, {
"class": [ns.e("clear")],
"onClick": clearSelection
}, {
default: () => [vue.createVNode(icons.X, null, null)]
}), vue.createVNode(index.XIcon, {
"class": [ns.e("arrow"), visible.value ? ns.is("reverse", true) : ""]
}, {
default: () => [vue.createVNode(icons.ChevronDown, null, null)]
})]), visible.value && vue.createVNode("div", {
"ref": dropdownRef,
"class": [ns.e("dropdown")]
}, [options.value.length === 0 && vue.createVNode("div", {
"class": [ns.e("empty")]
}, [vue.createTextVNode("\u65E0\u6570\u636E")]), slots.default?.()])]);
}
});
module.exports = Select;
//# sourceMappingURL=select.cjs.map