前言
接到公司一个内部需求,实现在网页任意位置添加一个标注框,用户可以自由输入文字,自由拖拽文本框,类似于PDF的标注功能。需求很简单,主要是通过这个需求掌握VUE3创建动态节点、Vue3的自定义指令,也可以扩展实现自己的对话框
创建动态节点
// createNode.ts
import { createApp, Component, onUnmounted } from 'vue'
function create(selector: string ,component: Component, props?: Object) {
var divEle: HTMLElement,
ele: HTMLElement | null;
const app = createApp(component, { ...props })
divEle = document.createElement("div")
ele = document.querySelector(selector)
ele?.appendChild(divEle)
app.mount(divEle)
onUnmounted(()=>{
app.unmount()
ele?.removeChild(divEle)
})
}
export default create
标注控件(简单对话框)
// postilModal.uve
<template>
<div class="postil" v-drag>
<textarea placeholder="请添加批注" />
</div>
</template>
<script lang="ts" setup>
const vDrag = {
mounted(el: HTMLDivElement) {
el.onmousedown = (ev) => {
// ev.stopPropagation()
// 鼠标按下的位置
const mouseXStart = ev.clientX;
const mouseYStart = ev.clientY;
// 当前滑块位置
const rectLeft = el.offsetLeft;
const rectTop = el.offsetTop;
el.onmousemove = (e) => {
// 鼠标移动的位置
// e.stopPropagation()
const mouseXEnd = e.clientX;
const mouseYEnd = e.clientY;
const moveX = mouseXEnd - mouseXStart + rectLeft;
const moveY = mouseYEnd - mouseYStart + rectTop;
el.style["top"] = moveY + "px";
el.style["left"] = moveX + "px";
};
el.onmouseup = (e) => {
// e.stopPropagation()
// 取消事件
el.onmousemove = null;
};
};
}
}
</script>
<style lang="scss" scoped>
.postil {
position: absolute;
top: 0;
left: 0;
textarea {
background-color: #D9EDFF;
border: 1px solid #40A9FF;
min-width: 160px;
width: auto;
padding: 8px 24px;
box-shadow: 0px 0px 0px 2px rgba(24, 144, 255, 0.2);
border-radius: 0px 20px 20px 20px;
border: none;
outline: none;
resize: none;
}
}
</style>
使用
// index.vue
import postilModal from './components/postilModal.vue';
import create from '@/utils/createNode'
<template>
<a-button @click="createPostil">添加批注</a-button>
<!-- 标注的位置 -->
<div id="preview-pdf">
...
</div>
</template>
<script setup lang="ts">
createPostil = () => {
create('#preview-pdf', postilModal)
}
<script>