Last active
January 20, 2022 10:10
-
-
Save wenshin/9d9a1ed839f635a261bf5713ed4e51fd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="topic-set"> | |
<a-divider | |
orientation="left" | |
class="divider-corss" | |
> | |
<span class="title">题目设置</span> | |
</a-divider> | |
<a-form-model-item | |
v-for="(subjectItem,index) in form.subject" | |
:key="index" | |
class="drag-item" | |
> | |
<div | |
v-if="subjectItem.region && subjectItem.region.length !== 0" | |
class="clickElement" | |
> | |
<a-form-model-item | |
label="题干" | |
class="topic" | |
> | |
<div class="topic-box"> | |
<a-form-model-item label="音频"> | |
<uploads | |
v-model="subjectItem.audio" | |
type="audio/mp3,audio/wav" | |
:delete-upload="true" | |
/> | |
</a-form-model-item> | |
<a-form-model-item | |
label="文字" | |
class="topic-distrub" | |
:prop="'subject.0.detail'" | |
:rules="{validator: handleValidator}" | |
> | |
<a-textarea | |
v-model="subjectItem.detail" | |
:auto-size="{ minRows: 1, maxRows: 4 }" | |
/> | |
</a-form-model-item> | |
</div> | |
</a-form-model-item> | |
<div> | |
<a-form-model-item | |
label="点击元素数量" | |
:prop="'subject.0.number'" | |
:rules="{ | |
required: true, | |
message: '请输入元素数量!', | |
trigger: 'blur', | |
}" | |
class="number-blur" | |
> | |
<a-input-number | |
v-model="subjectItem.number" | |
:min="1" | |
:max="10" | |
@blur="handleNumber" | |
/> | |
</a-form-model-item> | |
<h3>拖拽区块设置点击位置</h3> | |
<div class="element-one"> | |
<div | |
ref="container" | |
class="click-container" | |
@mousemove="handleMouseMove($event)" | |
@mouseup="stopDragBlock($event)" | |
@mouseout="stopDragBlock($event)" | |
@dragstart="disableEvent($event)" | |
> | |
<img | |
:src="subjectItem.imageOne" | |
width="100%" | |
@load="handleImageLoad()" | |
> | |
<div | |
v-for="(rectItem, idx) in subjectItem.rect" | |
:id="`small${idx}${index}`" | |
:key="idx" | |
ref="box" | |
class="box" | |
:style="getBoxStyle(subjectItem.rect, rectItem, idx)" | |
@mousedown="startDragBlock($event, idx)" | |
> | |
<div | |
:id="`small${idx}${index}`" | |
:style="coorStyle(idx)" | |
class="littleBR little-drag" | |
/> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</a-form-model-item> | |
</div> | |
</template> | |
<script> | |
import Uploads from '@/components/upload'; | |
const COLORS = [ | |
'rgba(220,20,60, 0.4)', | |
'rgba(255,255,0, 0.4)', | |
'rgba(65,105,225, 0.4)', | |
'rgba(0,250,154, 0.4)', | |
'rgba(255,0,255, 0.4)', | |
'rgba(255,127,80, 0.4)', | |
'rgba(255,140,0, 0.4)', | |
'rgba(255,20,147, 0.4)', | |
'rgba(32,178,170, 0.4)', | |
'rgba(112,128,144, 0.4)', | |
]; | |
const DEFAULT_BLOCK_SIZE = 50; | |
export default { | |
components: { | |
Uploads, | |
}, | |
props: { | |
isEn: { | |
type: Boolean, | |
default: false, | |
}, | |
form: { | |
type: Object, | |
default: ()=>({}), | |
}, | |
formmodel: { | |
type: Function, | |
default: ()=>{}, | |
}, | |
subjectCheck: { | |
type: Boolean, | |
default: false, | |
}, | |
}, | |
data() { | |
return { | |
dragType: '', | |
draggingBlockIdx: -1, | |
dragStartCoor: [0, 0], | |
blockSize: DEFAULT_BLOCK_SIZE, | |
}; | |
}, | |
computed: { | |
}, | |
created() { | |
this.createRect(); | |
}, | |
updated() { | |
this.createRect(); | |
}, | |
methods: { | |
disableEvent(evt) { | |
evt.preventDefault(); | |
evt.stopPropagation(); | |
}, | |
handleImageLoad() { | |
const subject = (this.form.subject || [])[0]; | |
if (!subject) return; | |
if (this.$refs.container && this.$refs.container.length) { | |
subject.containerRect = [this.$refs.container[0].clientWidth, this.$refs.container[0].clientHeight]; | |
} | |
}, | |
getBoxStyle(element, item, idx) { | |
const [x, y, width, height] = item || [0, 0, DEFAULT_BLOCK_SIZE, DEFAULT_BLOCK_SIZE]; | |
const style = {}; | |
style.background = COLORS[idx]; | |
style.left= x + 'px'; | |
style.top = y + 'px'; | |
style.width= width + 'px'; | |
style.height= height + 'px'; | |
return style; | |
}, | |
coorStyle(item) { | |
return { | |
background: COLORS[item], | |
}; | |
}, | |
createRect(num) { | |
const subject = (this.form.subject || [])[0]; | |
if (!subject) return; | |
const number = num || subject.number; | |
if (subject.rect.length === number) { | |
return; | |
} | |
if (subject.rect.length > number) { | |
subject.rect = subject.rect.slice(0, number); | |
} else { | |
for (let i = 0; i < number - subject.rect.length; i++) { | |
const idx = subject.rect.length + i; | |
subject.rect.push([idx * 60, 0, DEFAULT_BLOCK_SIZE, DEFAULT_BLOCK_SIZE]); | |
} | |
} | |
}, | |
handleNumber(e) { | |
const val = e && e.target && e.target.value; | |
if (!val) return; | |
this.createRect(Number(e.target.value)); | |
}, | |
handleMouseMove(evt) { | |
evt.preventDefault(); | |
evt.stopPropagation(); | |
if (this.dragType === 'block') { | |
this.moveBlock(evt); | |
} | |
if (this.dragType === 'blocksize') { | |
this.resizeBlock(evt); | |
} | |
}, | |
moveBlock(evt) { | |
if (this.draggingBlockIdx === -1) { | |
return; | |
} | |
const rect = this.form.subject[0].rect[this.draggingBlockIdx]; | |
let x = evt.x - this.dragStartCoor[0] + rect[0]; | |
let y = evt.y - this.dragStartCoor[1] + rect[1]; | |
if (x < 0) { | |
x = 0; | |
} | |
if (x > evt.currentTarget.clientWidth - DEFAULT_BLOCK_SIZE) { | |
x = evt.currentTarget.clientWidth - DEFAULT_BLOCK_SIZE; | |
} | |
if (y < 0) { | |
y = 0; | |
} | |
if (y > evt.currentTarget.clientHeight - DEFAULT_BLOCK_SIZE) { | |
y = evt.currentTarget.clientHeight - DEFAULT_BLOCK_SIZE; | |
} | |
const box = this.$refs.box[this.draggingBlockIdx]; | |
box.style.left = `${x}px`; | |
box.style.top = `${y}px`; | |
}, | |
resizeBlock(evt) { | |
if (this.draggingBlockIdx === -1) { | |
return; | |
} | |
const rect = this.form.subject[0].rect[this.draggingBlockIdx]; | |
let width = evt.x - this.dragStartCoor[0] + rect[2]; | |
let height = evt.y - this.dragStartCoor[1] + rect[3]; | |
if (width < DEFAULT_BLOCK_SIZE) { | |
width = DEFAULT_BLOCK_SIZE; | |
} | |
if (height < DEFAULT_BLOCK_SIZE) { | |
height = DEFAULT_BLOCK_SIZE; | |
} | |
const maxSize = Math.min(evt.currentTarget.clientWidth, evt.currentTarget.clientHeight); | |
if (width > maxSize) { | |
width = maxSize; | |
} | |
if (height > maxSize) { | |
height = maxSize; | |
} | |
const box = this.$refs.box[this.draggingBlockIdx]; | |
box.style.width = `${width}px`; | |
box.style.height = `${height}px`; | |
}, | |
startDragBlock(evt, rectIdx) { | |
if (evt.currentTarget === evt.target) { | |
// 拖拽 block | |
this.dragType = 'block'; | |
} else { | |
// 改变 block 大小 | |
this.dragType = 'blocksize'; | |
} | |
this.draggingBlockIdx = rectIdx; | |
this.dragStartCoor = [evt.x, evt.y]; | |
}, | |
stopDragBlock(evt) { | |
if (this.draggingBlockIdx === -1) { | |
return; | |
} | |
// block 本身的 mouseout 事件不停止拖拽,防止误操作 | |
if (evt.type === 'mouseout' && evt.currentTarget !== evt.target) { | |
return; | |
} | |
console.log('stopDragBlock', evt.type); | |
const rect = this.form.subject[0].rect[this.draggingBlockIdx]; | |
const box = this.$refs.box[this.draggingBlockIdx]; | |
rect[0] = parseFloat(box.style.left); | |
rect[1] = parseFloat(box.style.top); | |
rect[2] = parseFloat(box.style.width); | |
rect[3] = parseFloat(box.style.height); | |
this.draggingBlockIdx = -1; | |
this.dragStartCoor = [0, 0]; | |
}, | |
strlen(str) { | |
let len = 0; | |
for (let i=0; i<str.length; i++) { | |
let c = str.charCodeAt(i); | |
//单字节加1 | |
if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) { | |
len++; | |
} else { | |
len+=2; | |
} | |
} | |
return len; | |
}, | |
handleValidator(rule, value, callback) { | |
if (value && this.strlen(value) > 50) { | |
callback('题干文字不超过50个字符!'); | |
} | |
callback(); | |
}, | |
}, | |
}; | |
</script> | |
<style lang="scss"> | |
.topic-set { | |
.ant-col-20 { | |
width: 100%; | |
} | |
} | |
</style> | |
<style lang="scss" scoped> | |
.topic-set { | |
margin-top: 20px; | |
.divider-corss{ | |
position: relative; | |
.add-btn{ | |
padding: 0 10px; | |
top: -5px; | |
position: absolute; | |
right: 20px; | |
z-index: 3; | |
border: none; | |
color: #1890ff; | |
font-size: 16px; | |
box-shadow: none; | |
} | |
} | |
.drag-item { | |
flex-direction: row; | |
margin: 15px 0; | |
.drag-item-title { | |
width: 80px; | |
text-align: center; | |
} | |
.drag-item-title:first-child { | |
font-size: 16px; | |
} | |
.drag-box { | |
flex: 1; | |
border: 1px dashed #999; | |
padding: 10px; | |
.ant-form-item{ | |
margin-bottom: 0px; | |
} | |
} | |
} | |
.drag-item-box { | |
display: flex; | |
justify-content: space-between; | |
} | |
} | |
.translate-icons a{ | |
display: inline-block; | |
width: 20px; | |
height: 20px; | |
&.up-icon{ | |
background: url(~@/assets/image/empty-up.png) no-repeat center/contain; | |
&.first{ | |
background-image: url(~@/assets/image/xiangshangbeifen.png); | |
} | |
&:not(.first):hover{ | |
background-image: url(~@/assets/image/full-up.png); | |
} | |
} | |
&.down-icon{ | |
background: url(~@/assets/image/empty-down.png) no-repeat center/contain; | |
&.last{ | |
background: url(~@/assets/image/xiangxiabeifen.png) no-repeat center/contain; | |
} | |
&:not(.last):hover{ | |
background-image: url(~@/assets/image/full-down.png); | |
} | |
} | |
} | |
.explain{ | |
color: #999; | |
} | |
// 去【新增】除按钮点击动画 | |
button[ant-click-animating-without-extra-node]:after { | |
border: 0 none; | |
opacity: 0; | |
animation:none 0 ease 0 1 normal; | |
} | |
.element-one { | |
.click-container { | |
position: relative; | |
margin: 0 auto; | |
} | |
.box { | |
width: 50px; | |
height: 50px; | |
cursor: move; | |
position: absolute; | |
} | |
.little-drag { | |
width: 10px; | |
height: 10px; | |
position: absolute; | |
} | |
.littleTL { | |
left: 0; | |
top: 0; | |
cursor: nwse-resize; | |
} | |
.littleTR { | |
right: 0; | |
top: 0; | |
cursor: nesw-resize; | |
} | |
.littleBL { | |
left: 0; | |
bottom: 0; | |
cursor: nesw-resize; | |
} | |
.littleBR { | |
right: 0; | |
bottom: 0; | |
cursor: nwse-resize; | |
} | |
.empty { | |
width: 740px; | |
height: 440px; | |
position: relative; | |
margin: 0 auto; | |
top: 0; | |
left: 0; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
border: 1px solid #1890ff; | |
box-shadow: 0 0 2px 2px rgba(0,0,255,0.3); | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment