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