я получил один раньшекоманда копирования, на этот раз с другой командой перетаскивания. .
Что это за змеиная кожа? Наверное, как Джи:
Поскольку в нашем проекте используетсяelement-ui, вся эта директива нацелена только наelement-uiДиалоговый компонент Ha, если вы используете другиеuiБиблиотека также имеет это требование, и ее также можно использовать для редактирования. .
На самом деле принцип перетаскивания очень прост:
- Первый щелчок мыши (
onmousedown)- записать текущий
leftиtopценность
- записать текущий
- движение мыши (
onmousemove)- Вычислите боковое расстояние для каждого движения (
disX) и продольное расстояние (disY) - и измените элемент
left(left = left + disX)иtop(top = top + disY)ценность
- Вычислите боковое расстояние для каждого движения (
- отпустить мышь (
onmouseup)- Завершите перетаскивание и сделайте несколько последних штрихов
leftиtopЗначение легко получить, ключdisXиdisYКак его рассчитать?
Сначала популяризирую:
Тогда псевдокод:
-
disX= когда нажата мышьclientX- когда мышь отпущенаclientX -
disY= когда нажата мышьclientY- когда мышь отпущенаclientY
Это так просто, хорошо, давайте начнем кодировать.
// 这个助手方法下面会用到,用来获取 css 相关属性值
const getAttr = (obj, key) => (
obj.currentStyle
? obj.currentStyle[key]
: window.getComputedStyle(obj, false)[key]
);
const vDrag = {
inserted(el) {
/**
* 这里是跟据 dialog 组件的 dom 结构来写的
* target: dialog 组件的容器元素
* header:dialog 组件的头部区域,也是就是拖拽的区域
*/
const target = el.children[0];
const header = target.children[0];
// 鼠标手型
header.style.cursor = 'move';
header.onmousedown = (e) => {
// 记录按下时鼠标的坐标和目标元素的 left、top 值
const currentX = e.clientX;
const currentY = e.clientY
const left = parseInt(getAttr(target, 'left'));
const top = parseInt(getAttr(target, 'top'));
document.onmousemove = (event) => {
// 鼠标移动时计算每次移动的距离,并改变拖拽元素的定位
const disX = event.clientX - currentX;
const disY = event.clientY - currentY;
target.style.left = `${left + disX}px`;
target.style.top = `${top + disY}px`;
// 阻止事件的默认行为,可以解决选中文本的时候拖不动
return false;
}
// 鼠标松开时,拖拽结束
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
};
}
},
// 每次重新打开 dialog 时,要将其还原
update(el) {
const target = el.children[0];
target.style.left = '';
target.style.top = '';
},
// 最后卸载时,清除事件绑定
unbind(el) {
const header = el.children[0].children[0];
header.onmousedown = null;
},
};
export default vDrap;
Вот и всесамый легкийтащил, так чтоokПока что? Конечно нет, так в чем проблема? То есть, если вы со слишком большим усилием вытащите всю рамку пули из видимой области, вы не сможете ее вытащить.
Так что мы должны улучшить его, судить о границах четырех направлений, и если он превышает граничное значение, он не будет двигаться. Граничное значение на самом деле является максимальным расстоянием, которое можно перетащить на экране, т.е.disXиdisYмаксимальное значение
- Верхняя граница:
target.offsetTop-
offsetTop: Здесь вы можете представить целевой элемент (target) расстояние верхней границы от верха страницы
-
- Нижняя граница:
body.height - target.offsetTop - header.height-
header.height: Зарезервируйте высоту, что означает, что ее можно перетащить вниз, чтобы оставить только перетаскиваемую область снаружи.
-
- Левая граница:
target.offsetLeft + target.width - 50-
offsetLeft: Здесь вы можете указать расстояние между левой границей целевого элемента и левой стороной страницы. -
50: Указывает зарезервированную ширину, вы можете установить ее самостоятельно, если она больше, чем0Вот именно, это значит, что сколько ни тяни влево, оно останется50pxширина снаружи
-
- Правая граница:
body.width - target.offsetLeft - 50- здесь
50То же, что и выше, это означает, что независимо от того, сколько вы перетащите влево, он останется50pxширина снаружи
- здесь
Здесь есть много способов расчета граничного значения, вы можете попробовать свои собственные идеи. Затем я нарисовал грубую картину, чтобы помочь понять это, хотя мне казалось, что только я могу это понять. Ха-ха. . .
okохватывать
// ...
// 以上代码省略
header.onmousedown = (e) => {
// ...
// 以上代码省略
// 分别计算四个方向的边界值
const minLeft = target.offsetLeft + parseInt(getAttr(target, 'width')) - 50;
const maxLeft = parseInt(getAttr(document.body, 'width')) - target.offsetLeft - 50;
const minTop = target.offsetTop;
const maxTop = parseInt(getAttr(document.body, 'height'))
- target.offsetTop - parseInt(getAttr(header, 'height'));
document.onmousemove = (event) => {
// 鼠标移动时计算每次移动的距离,并改变拖拽元素的定位
const disX = event.clientX - currentX;
const disY = event.clientY - currentY;
// 判断左、右边界
if (disX < 0 && disX <= -minLeft) {
target.style.left = `${left - minLeft)}px`;
} else if (disX > 0 && disX >= maxLeft) {
target.style.left = `${left + maxLeft}px`;
} else {
target.style.left = `${left + disX}px`;
}
// 判断上、下边界
if (disY < 0 && disY <= -minTop) {
target.style.top = `${top - minTop)}px`;
} else if (disY > 0 && disY >= maxTop) {
target.style.top = `${top + maxTop}px`;
} else {
target.style.top = `${top + disY}px`;
}
return false;
};
}
После регистрации вы можете использовать его:
<el-dialog v-drag title="对话框" :visible.sync="dialogVisible"></el-dialog>
Я не буду вводить хук-функцию инструкции и как ее прописать глобально, если вам интересно, вы можете взглянуть на меня.Предыдущийстатья.