未使用过但是很好用的工具。

37 阅读2分钟

钱的千分,方法 new Intl.NumberFormat

const number = 123456.789;
const formatter = new Intl.NumberFormat('en-US');
console.log(formatter.format(number)); // 输出: "123.456,789"

JSON存储map数据

//存储
content = JSON.stringify(
  { product_marketing: state.product_marketing, is_finished: state.is_finished },
  // 优化Map存储
  (key: string, value: any) => {
    // 直接检查值是否为Map实例,而不依赖于key名
    if (value instanceof Map) {
      return {
        _type: 'Map',
        data: Array.from(value)
      };
    }
    return value;
  }
);

//解析
JSON.parse(content, (key: string, value: any) => {
  // 检查是否是之前序列化的Map对象
  if (
    value &&
    typeof value === 'object' &&
    value._type === 'Map' &&
    Array.isArray(value.data)
  ) {
    // 凑合着用吧
    const map = new Map(value.data);
    return map;
  }
  return value;
})

文字打印效果,mardown文本格式,富含代码块。

<style lang="scss" scoped>
.cursor {
	content: "";
	position: absolute;
	width: 10px;
	height: 16px;
	background: #ff0000;
	animation: toggle 0.6s infinite;
	opacity: 0;
	transform: translateY(3px);
	left: calc(v-bind("pos.x") * 1px);
	top: calc(v-bind("pos.y") * 1px);
}
@keyframes toggle {
	30% {
		opacity: 1;
	}
}
</style>
<template>
	<div
		v-html="html"
		v-highlight
		ref="contentRef"
		class="chat-content-container"
	></div>
	<div
		v-show="showCursor"
		class="cursor"
		ref="cursorRef"
	></div>
</template>

<script setup>
// 闪烁光标,追加字符!markdown转html后不好追加(html也不好追加)

import { marked } from "marked";
import hljs from "highlight.js";
import "highlight.js/styles/googlecode.css";
import { onMounted, reactive, ref, watch, nextTick } from "vue";

const contentRef = ref(null);
const cursorRef = ref(null);
const html = ref("");

const vHighlight = {
	mounted: (el) => {
		let blocks = el.querySelectorAll("pre code");
		blocks.forEach((block) => {
			hljs.highlightElement(block);
		});
	},
	updated: (el) => {
		let blocks = el.querySelectorAll("pre code");
		blocks.forEach((block) => {
			hljs.highlightElement(block);
		});
	},
};

const props = defineProps({
	str: {
		type: String,
		default: "",
	},
});

const showCursor = ref(false);
const pos = reactive({
	x: 0,
	y: 0,
});

onMounted(() => {
	html.value = marked.parse(props.str);
	showCursor.value = false;
});

function getLastTextNode(dom) {
	const children = dom.childNodes;
	for (let i = children.length - 1; i >= 0; i--) {
		const node = children[i];
		if (node.nodeType == Node.TEXT_NODE && /\S/.test(node.nodeValue)) {
			node.nodeValue = node.nodeValue.replace(/\s+$/, "");
			return node;
		} else if (node.nodeType == Node.ELEMENT_NODE) {
			const last = getLastTextNode(node);
			if (last) {
				return last;
			}
		}
	}
	return null;
}

async function updateCursorPosition() {
	await nextTick(); // 等待DOM更新
	
	const contentDom = contentRef.value;
	if (!contentDom) return;
	
	// 创建临时光标元素
	const cursorElement = document.createElement('span');
	cursorElement.textContent = '|';
	cursorElement.style.position = 'absolute';
	cursorElement.style.visibility = 'hidden';
	cursorElement.style.whiteSpace = 'pre';
	
	// 添加到容器末尾
	contentDom.appendChild(cursorElement);
	
	// 获取光标位置
	const rect = cursorElement.getBoundingClientRect();
	const containerRect = contentDom.getBoundingClientRect();
	
	// 计算相对位置
	pos.x = rect.left - containerRect.left;
	pos.y = rect.top - containerRect.top + contentDom.scrollTop;
	
	// 移除临时元素
	contentDom.removeChild(cursorElement);
}

watch(
	() => props.str,
	(val, oldVal) => {
		if (oldVal) {
			return;
		} else {
			markdownToHtmlDom(val);
		}
	}
);

const markdownToHtmlDom = (markdown) => {
	showCursor.value = true;
	let index = 0;
	const interval = setInterval(async () => {
		if (index <= markdown.length) {
			html.value = marked.parse(markdown.substring(0, index));
			await nextTick(); // 等待DOM更新后再更新光标位置
			updateCursorPosition();
		}
		
		if (index >= markdown.length) {
			showCursor.value = false;
			clearInterval(interval);
		}
		index++;
	}, 100);
};
</script>

获取指定坐标最上层的元素

document.elementFromPoint(x,y)

table表格border合并问题,css解决

border-collapse: collapse;

浏览器自带生成唯一UID

crypto.randomUUID()