Skip to content

Instantly share code, notes, and snippets.

@wenshin
Last active January 20, 2022 10:10
Show Gist options
  • Save wenshin/9d9a1ed839f635a261bf5713ed4e51fd to your computer and use it in GitHub Desktop.
Save wenshin/9d9a1ed839f635a261bf5713ed4e51fd to your computer and use it in GitHub Desktop.
<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