123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- import { ref, watch, computed, onActivated, onMounted, defineComponent, nextTick, createVNode as _createVNode } from "vue";
- import { makeNumericProp, makeStringProp, createNamespace, windowWidth } from "../utils/index.mjs";
- import { useExpose } from "../composables/use-expose.mjs";
- const [name, bem] = createNamespace("text-ellipsis");
- const textEllipsisProps = {
- rows: makeNumericProp(1),
- dots: makeStringProp("..."),
- content: makeStringProp(""),
- expandText: makeStringProp(""),
- collapseText: makeStringProp(""),
- position: makeStringProp("end")
- };
- var stdin_default = defineComponent({
- name,
- props: textEllipsisProps,
- emits: ["clickAction"],
- setup(props, {
- emit,
- slots
- }) {
- const text = ref(props.content);
- const expanded = ref(false);
- const hasAction = ref(false);
- const root = ref();
- const actionRef = ref();
- let needRecalculate = false;
- const actionText = computed(() => expanded.value ? props.collapseText : props.expandText);
- const pxToNum = (value) => {
- if (!value) return 0;
- const match = value.match(/^\d*(\.\d*)?/);
- return match ? Number(match[0]) : 0;
- };
- const cloneContainer = () => {
- if (!root.value || !root.value.isConnected) return;
- const originStyle = window.getComputedStyle(root.value);
- const container = document.createElement("div");
- const styleNames = Array.prototype.slice.apply(originStyle);
- styleNames.forEach((name2) => {
- container.style.setProperty(name2, originStyle.getPropertyValue(name2));
- });
- container.style.position = "fixed";
- container.style.zIndex = "-9999";
- container.style.top = "-9999px";
- container.style.height = "auto";
- container.style.minHeight = "auto";
- container.style.maxHeight = "auto";
- container.innerText = props.content;
- document.body.appendChild(container);
- return container;
- };
- const calcEllipsisText = (container, maxHeight) => {
- var _a, _b;
- const {
- content,
- position,
- dots
- } = props;
- const end = content.length;
- const middle = 0 + end >> 1;
- const actionHTML = slots.action ? (_b = (_a = actionRef.value) == null ? void 0 : _a.outerHTML) != null ? _b : "" : props.expandText;
- const calcEllipse = () => {
- const tail = (left, right) => {
- if (right - left <= 1) {
- if (position === "end") {
- return content.slice(0, left) + dots;
- }
- return dots + content.slice(right, end);
- }
- const middle2 = Math.round((left + right) / 2);
- if (position === "end") {
- container.innerText = content.slice(0, middle2) + dots;
- } else {
- container.innerText = dots + content.slice(middle2, end);
- }
- container.innerHTML += actionHTML;
- if (container.offsetHeight > maxHeight) {
- if (position === "end") {
- return tail(left, middle2);
- }
- return tail(middle2, right);
- }
- if (position === "end") {
- return tail(middle2, right);
- }
- return tail(left, middle2);
- };
- return tail(0, end);
- };
- const middleTail = (leftPart, rightPart) => {
- if (leftPart[1] - leftPart[0] <= 1 && rightPart[1] - rightPart[0] <= 1) {
- return content.slice(0, leftPart[0]) + dots + content.slice(rightPart[1], end);
- }
- const leftMiddle = Math.floor((leftPart[0] + leftPart[1]) / 2);
- const rightMiddle = Math.ceil((rightPart[0] + rightPart[1]) / 2);
- container.innerText = props.content.slice(0, leftMiddle) + props.dots + props.content.slice(rightMiddle, end);
- container.innerHTML += actionHTML;
- if (container.offsetHeight >= maxHeight) {
- return middleTail([leftPart[0], leftMiddle], [rightMiddle, rightPart[1]]);
- }
- return middleTail([leftMiddle, leftPart[1]], [rightPart[0], rightMiddle]);
- };
- return props.position === "middle" ? middleTail([0, middle], [middle, end]) : calcEllipse();
- };
- const calcEllipsised = () => {
- const container = cloneContainer();
- if (!container) {
- needRecalculate = true;
- return;
- }
- const {
- paddingBottom,
- paddingTop,
- lineHeight
- } = container.style;
- const maxHeight = Math.ceil((Number(props.rows) + 0.5) * pxToNum(lineHeight) + pxToNum(paddingTop) + pxToNum(paddingBottom));
- if (maxHeight < container.offsetHeight) {
- hasAction.value = true;
- text.value = calcEllipsisText(container, maxHeight);
- } else {
- hasAction.value = false;
- text.value = props.content;
- }
- document.body.removeChild(container);
- };
- const toggle = (isExpanded = !expanded.value) => {
- expanded.value = isExpanded;
- };
- const onClickAction = (event) => {
- toggle();
- emit("clickAction", event);
- };
- const renderAction = () => {
- const action = slots.action ? slots.action({
- expanded: expanded.value
- }) : actionText.value;
- return _createVNode("span", {
- "ref": actionRef,
- "class": bem("action"),
- "onClick": onClickAction
- }, [action]);
- };
- onMounted(() => {
- calcEllipsised();
- if (slots.action) {
- nextTick(calcEllipsised);
- }
- });
- onActivated(() => {
- if (needRecalculate) {
- needRecalculate = false;
- calcEllipsised();
- }
- });
- watch([windowWidth, () => [props.content, props.rows, props.position]], calcEllipsised);
- useExpose({
- toggle
- });
- return () => _createVNode("div", {
- "ref": root,
- "class": bem()
- }, [expanded.value ? props.content : text.value, hasAction.value ? renderAction() : null]);
- }
- });
- export {
- stdin_default as default,
- textEllipsisProps
- };
|