/* Movable/Components/View.vue */ <script> const MovableView = {
props: {
height : {
type: Number, required: true }, width : {
type: Number, required: true }, left : {
type: Number, required: true }, top : {
type: Number, required: true }, overflow: {
type: Boolean }, ratio : {
type: Boolean }, minSize : {
type: Number, default: 40 }, maxSize : {
type: Number }, imgSrc : {
type: String }, styles : {
type: Object, default: () => ({
) },
resize : {
type: Boolean },
onChange: {
type: Function },
visible: {
type: Boolean, default: true }
},
methods: {
handleMoveMouseDown(e) {
this.parseMove(e, (val) => {
let top = val.y
let left = val.x
if (!this.$props.overflow) {
const parentWidth = parseFloat(this.$refs.viewDomRef.parentElement.style.width)
const parentHeight = parseFloat(this.$refs.viewDomRef.parentElement.style.height)
top = Math.max(0, top)
top = Math.min(top, parentHeight - this.$props.height)
left = Math.max(0, left)
left = Math.min(left, parentWidth - this.$props.width)
}
this.$props.onChange && this.$props.onChange({
width: this.$props.width,
height: this.$props.height,
top,
left
})
})
},
handleResizeMouseDown(e) {
e.stopPropagation()
this.parseMove(e, (val) => {
let width = val.x + 12
let height = val.y + 12
// 是否允许超出
if (!this.$props.overflow) {
const parentWidth = parseFloat(this.$refs.viewDomRef.parentElement.style.width)
const parentHeight = parseFloat(this.$refs.viewDomRef.parentElement.style.height)
width = Math.min(width, parentWidth - this.$props.left)
height = Math.min(height, parentHeight - this.$props.top)
}
// 等比缩放
if (this.$props.ratio) {
height = width = Math.min(width, height)
}
// 最小缩放值
width = Math.max(width, this.$props.minSize)
height = Math.max(height, this.$props.minSize)
// 最大缩放值
if (this.$props.maxSize) {
width = Math.min(width, this.$props.maxSize)
height = Math.min(height, this.$props.maxSize)
}
this.$props.onChange && this.$props.onChange({
width,
height,
top: this.$props.top,
left: this.$props.left
})
})
},
parseMove(e, cb) {
const x = e.clientX - e.currentTarget.offsetLeft
const y = e.clientY - e.currentTarget.offsetTop
this.moveEventcache = document.onmousemove
document.onmousemove = (ee) => {
cb && cb({
x: ee.clientX - x, y: ee.clientY - y })
}
document.onmouseup = () => {
document.onmousemove = this.moveEventcache
}
}
},
render() {
if (this.$props.visible === false) return null
const styles = {
position: 'absolute',
width: this.$props.width + 'px',
height: this.$props.height + 'px',
top: this.$props.top + 'px',
left: this.$props.left + 'px',
cursor: 'grab',
userSelect: 'none',
backgroundImage: 'url("' + this.$props.imgSrc + '")',
backgroundSize: 'contain',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
...(this.$props.styles)
}
const resizeStyle = {
position: 'absolute',
right: 0,
bottom: 0,
width: 12 + 'px',
height: 12 + 'px',
opacity: '0.9',
cursor: 'nwse-resize',
backgroundSize: '100%',
userSelect: 'none',
backgroundImage: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAVFBMVEUAAADd3d3b29vd3d3e3t7k5OT19fXd3d3n5+eZmZnHx8e4uLioqKjv7++urq7z8/Ps7OzX19e0tLSrq6vk5OTi4uLQ0NCwsLDp6enKysq/v7++vr57c1IlAAAABnRSTlMAf4D2qROyT4+oAAABJElEQVRYw6XV3U7CUBBFYVvQOadAEQF/3/89NTayEieZKXv2/bc6aS/6UNxY9Vbzg1nVW9FfreZbs5p/IqB5AponoHkCmiegeQKaJ6B5AponIHoCoicgegKC1wJ4LYDXAngtgNcCeC2A1wJ4LYAXA3g9MOKFAF4I4LUAXgvgtQBeDHjf5s8kkPh9n+4LDKknkPtnvAus8Yc/38gQyP3x5vfdsgCe3fy5Bxfk/h1PYJX/WF7kjCewxr/+87uvMDCmvk8EUn/up+VDvjlPIPBz4H3A+1O3xb94T8B7tjz/6D0BhmeBJ5D6nfcEcg/DE/Deb3KeQOQZPggMgicgegL5/Q3vAvhoFvwXuH/tCODFAPdLu1jNH2zz669N28Vs++ML22wfvwHZ2TVJ7XC9dwAAAABJRU5ErkJggg==")'
}
return (
<div style={
styles} ref="viewDomRef" onmousedown={
this.handleMoveMouseDown.bind(this)}>
{
this.$slots?.default}
{
this.$props.resize && <div style={
resizeStyle} onmousedown={
this.handleResizeMouseDown.bind(this)} />}
</div>
)
}
}
export default MovableView
</script>
/* Movable/Components/Area.vue */
<script>
const MovableArea = {
props: {
width: {
type: Number,
default: '100%'
},
height: {
type: Number,
default: '100%'
},
imgSrc: {
type: String,
default: ''
}
},
render() {
const styles = {
position: 'relative',
width: this.width ? this.width + 'px' : '100%',
height: this.height ? this.height + 'px' : '100%',
backgroundImage: 'url(' + this.imgSrc + ')',
backgroundSize: '100%'
}
return (
<div className="movable-area-block" style={
styles}>
{
this.$slots?.default}
</div>
)
}
}
export default MovableArea
</script>