特性:
- 可以自定义拖拽过程鼠标样式
- 可以禁止拖拽
- 动态设置拖拽和滚动区域元素
- 支持监听滚动条@scroll事件
sgDragMoveTile源码
<template>
<div :class="$options.name"></div>
</template>
<script>
export default {
name: "sgDragMoveTile",
data() {
return {
scrollContainer: null,
dragContainer: null,
};
},
props: [
"data",
/*data格式:{
scrollContainer:滚动条容器的element,
dragContainer:拖拽的element,
}*/
"disabled", //是否禁用
"cursor", //鼠标样式
/*cursor格式说明:{
grab:'default',//移入可拖拽区域的鼠标样式
grabbing:'default',//拖拽过程中鼠标样式
}*/
],
watch: {
data: {
handler(newValue, oldValue) {
if (newValue && Object.keys(newValue).length) {
newValue.scrollContainer && (this.scrollContainer = newValue.scrollContainer);
newValue.dragContainer && (this.dragContainer = newValue.dragContainer);
this.addEvents();
} else {
this.removeEvents();
}
},
deep: true, //深度监听
immediate: true, //立即执行
},
disabled: {
handler(newValue, oldValue) {
newValue ? this.removeEvents() : this.addEvents();
},
deep: true,
immediate: true,
},
},
mounted() {
this.$parent.$el.style.setProperty(
"--sgDragMoveTile-grab",
(this.cursor || {}).grab || "grab"
); //js往css传递局部参数
this.$parent.$el.style.setProperty(
"--sgDragMoveTile-grabbing",
(this.cursor || {}).grabbing || "grabbing"
); //js往css传递局部参数
},
methods: {
addEvents(d) {
this.removeEvents();
if (this.dragContainer) {
this.dragContainer.setAttribute("sgDragMoveTile_grab", "ready");
this.dragContainer.addEventListener("mousedown", this.mousedown);
}
if (this.scrollContainer) {
this.scrollContainer.addEventListener("scroll", this.scroll);
}
},
removeEvents(d) {
if (this.dragContainer) {
this.dragContainer.removeAttribute("sgDragMoveTile_grab");
this.dragContainer.removeEventListener("mousedown", this.mousedown);
}
if (this.scrollContainer) {
this.scrollContainer.removeEventListener("scroll", this.scroll);
}
removeEventListener("mouseup", this.mouseup);
},
scroll(e) {
this.$emit(`scroll`, e);
},
mousedown(e) {
this.$emit(`dragStart`, e);
if (!this.isNotAllowedDrag()) return;
this.dragContainer.setAttribute("sgDragMoveTile_grab", "down");
let scrollContainer = this.scrollContainer;
let dragContainer = this.dragContainer;
//鼠标按下那一刻,滚动条的位置
let mouseDownScrollPosition = {
scrollLeft: scrollContainer.scrollLeft,
scrollTop: scrollContainer.scrollTop,
};
//鼠标按下的位置坐标
let mouseDownPoint = {
x: e.clientX,
y: e.clientY,
};
dragContainer.onmousemove = (e) => {
//鼠标滑动的实时距离
let dragMoveDiff = {
x: mouseDownPoint.x - e.clientX,
y: mouseDownPoint.y - e.clientY,
};
scrollContainer.scrollLeft = mouseDownScrollPosition.scrollLeft + dragMoveDiff.x;
scrollContainer.scrollTop = mouseDownScrollPosition.scrollTop + dragMoveDiff.y;
this.$emit(`dragMove`, e, {
scrollLeft: scrollContainer.scrollLeft,
scrollTop: scrollContainer.scrollTop,
});
};
addEventListener("mouseup", this.mouseup);
},
mouseup(e) {
this.dragContainer.onmousemove = null;
removeEventListener("mouseup", this.mouseup);
this.isNotAllowedDrag();
this.$emit(`dragEnd`, e);
},
isNotAllowedDrag(d) {
let scrollContainer = this.scrollContainer,
rect_scrollContainer = scrollContainer.getBoundingClientRect();
let dragContainer = this.dragContainer,
rect_dragContainer = dragContainer.getBoundingClientRect();
// 滚动区域不小于拖拽区域
if (
rect_scrollContainer.width >= rect_dragContainer.width &&
rect_scrollContainer.height >= rect_dragContainer.height
) {
this.dragContainer.setAttribute("sgDragMoveTile_grab", "not-allowed");
return false;
} else {
this.dragContainer.setAttribute("sgDragMoveTile_grab", "ready");
return true;
}
},
},
destroyed() {
this.removeEvents();
},
};
</script>
<style lang="scss">
[sgDragMoveTile_grab="ready"] {
/*禁止选中文本*/
user-select: none;
cursor: var(--sgDragMoveTile-grab); //css获取js传递的参数
* {
cursor: var(--sgDragMoveTile-grab); //css获取js传递的参数
}
}
[sgDragMoveTile_grab="down"] {
/*禁止选中文本*/
user-select: none;
cursor: var(--sgDragMoveTile-grabbing); //css获取js传递的参数
* {
cursor: var(--sgDragMoveTile-grabbing); //css获取js传递的参数
}
}
[sgDragMoveTile_grab="not-allowed"] {
/*禁止选中文本*/
user-select: none;
cursor: not-allowed;
* {
cursor: not-allowed;
}
}
</style>
用例
<template>
<div :class="$options.name">
<div class="sg-ctrl">
<label>缩放百分比</label>
<el-input-number style="width: 150px;" v-model.trim="scaleValue" :precision="0" :step="10" :min="10" :max="100"
:controls-position="`left`" />
</div>
<div class="sg-tile-img" ref="scrollContainer">
<div ref="dragContainer" :style="{ width: `${tileSize * colCount}px` }">
<img v-for="(a, i) in tiles" :key="i" :loading="a.loading" :width="tileSize" :height="tileSize">
</div>
</div>
<sgDragMoveTile :data="dragMoveTileData" />
</div>
</template>
<script>
import sgDragMoveTile from "@/vue/components/admin/sgDragMoveTile";
export default {
name: 'sgTileImage',
components: {
sgDragMoveTile
},
data() {
return {
dragMoveTileData: {},
scaleValue: 100,
orginTileSize: 0,
tileSize: 0,
colCount: 0,
rowCount: 0,
tiles: [],//瓦片图数组
}
},
watch: {
data: {
handler(newValue, oldValue) {
let len = 144;//瓦片图数量
this.tiles = [...Array(len)].map(v => ({
loading: false,
}));
this.orginTileSize = 500
this.colCount = Math.sqrt(len)
this.rowCount = Math.sqrt(len)
console.log(this.tiles)
},
deep: true,//深度监听
immediate: true,//立即执行
},
scaleValue: {
handler(newValue, oldValue) {
this.tileSize = this.orginTileSize * newValue / 100;
},
deep: true,//深度监听
immediate: true,//立即执行
},
},
mounted() {
this.dragMoveTileData = {
scrollContainer: this.$refs.scrollContainer,
dragContainer: this.$refs.dragContainer,
}
},
};
</script>
<style lang="scss" scoped>
.sgTileImage {
.sg-ctrl {
position: absolute;
right: 0;
top: 0;
z-index: 1;
box-sizing: border-box;
padding: 10px 20px;
background-color: white;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: flex-end;
label {
margin-right: 10px;
}
}
.sg-tile-img {
position: absolute;
left: 0;
top: 0;
overflow: auto;
width: 100%;
height: 100%;
div {
display: flex;
flex-wrap: wrap;
img {
border: none;
}
}
}
}
</style>