123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- <template >
- <div class="luojigou-board" >
- <!-- navbar -->
- <div class="navbar" >
- <div class="" ></div>
- </div>
- <!-- 操作题卡区域 -->
- <div class="opra" >
- <div class="board" :style="{background: `url(${boardUrl})`}">
- <div class="card" >
- <div class="ques" >
- <img :src="props.card.quesUrl" alt="">
- </div>
- <div class="ans" ref="ansEl" >
- <div
- class="ans-item"
- :style="{height: ansItemHeight + 'px'}"
- v-for="item in props.card.ans"
- :key="item.color"
- >
- <img :src="item.url" alt="">
- </div>
- </div>
- </div>
- <div class="buttons" id="ans" ref="buttonEl" >
- <img
- :name="item.color"
- v-for="(item, index) in buttons"
- :key="item.url"
- :src="item.url"
- :cusAttr="JSON.stringify({
- x: VSpace * index,
- y: 426,
- color: item.color
- })"
- :style="{
- width: '46px',
- height: '46px',
- transform: `translate(${VSpace * index}px, 426px)`
- }"
- />
- <!-- transform: `translate(${VSpace * index}px, ${426}px)` -->
- </div>
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- /* eslint-disable vue/require-prop-type-constructor */
- import { defineProps, ref, onMounted, reactive } from 'vue'
- import { useDrag } from '@/hook/index'
- type Colors = 'red' | 'orange' | 'green' | 'purple' | 'blue' | 'yellow'
- interface IProps {
- platform: 'h5' | 'miniProgram',
- formwork: 'four' | 'six',
- card: {
- quesUrl: string,
- ans: {url: string, color: Colors, button: string}[]
- buttonsPos: {x: number, y: number, color: Colors}[]
- }
- }
- const initProps: IProps = {
- platform: 'h5',
- formwork: "six",
- card: {
- quesUrl: 'https://app-resources-luojigou.luojigou.vip/FqGOmqXFXSp8D-PsxpbrmFTi5O-m',
- ans: [
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FjLia9g1_NqKW0dzozRZPA-BOryq', color: 'red' },
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FubYgi_og7RI23MHPVhtm9kl-STW', color: 'green' },
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FlASX6RW3JFb9-FrBzLWPSHYuMGo', color: 'orange' },
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FtBZMPDRLLsIBQrTdTjtjPxI-rma', color: 'purple' },
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FtBZMPDRLLsIBQrTdTjtjPxI-rma', color: "yellow" },
- {button: '', url: 'https://app-resources-luojigou.luojigou.vip/FtBZMPDRLLsIBQrTdTjtjPxI-rma', color: 'blue' }
- ],
- buttonsPos: [{ x: 0, y: 0, color: 'blue' }]
- }
- }
- const staticImg = {
- boardBg: require('@/assets/component/LuojigouBoard/board-bg.png'),
- boardFour: require('@/assets/component/LuojigouBoard/board-four.png'),
- boardSix: require('@/assets/component/LuojigouBoard/board-six.png'),
- blue: require('@/assets/component/LuojigouBoard/blue.png'),
- green: require('@/assets/component/LuojigouBoard/green.png'),
- orange: require('@/assets/component/LuojigouBoard/orange.png'),
- red: require('@/assets/component/LuojigouBoard/red.png'),
- yellow: require('@/assets/component/LuojigouBoard/yellow.png'),
- purple: require('@/assets/component/LuojigouBoard/purple.png')
- }
- const reg = new RegExp(/(-\d+)|(\d+)/g)
- const props = initProps
- // 答案区的份数
- const copies = props.formwork === 'four' ? 4 : 6
- // 按钮横向距离
- const VSpace = props.formwork === 'four' ? 27 : 53
- // 答案纵向高度
- const ansItemHeight = props.formwork === 'four' ? 95 : 64
- const buttons = ref([
- { x: 0, y: 0, url: staticImg.red, color: 'red' },
- { x: 0, y: 200, url: staticImg.blue, color: 'blue' },
- { x: 0, y: 200, url: staticImg.green, color: 'green' },
- { x: 0, y: 200, url: staticImg.orange, color: 'orange' },
- { x: 0, y: 200, url: staticImg.yellow, color: "yellow" },
- { x: 0, y: 200, url: staticImg.purple, color: 'purple' },
- ])
- const boardUrl = props.formwork === 'four' ? staticImg.boardFour : staticImg.boardSix
- const ansEl = ref()
- const buttonEl = ref()
- const state = reactive({
- cacheButtonPos: {x: 0, y: 0, copies: 0}
- })
- const getTransform = (ev: TouchEvent) => {
- const target = ev.target as HTMLElement
- if (!target) return {x: 0, y: 0}
- const [x, y] = target.style.transform.match(reg)!
- return {x: Number(x), y: Number(y)}
- }
- const onDragStart = (ev: TouchEvent) => {
- const { x, y }= getTransform(ev)
- const curCopies = Math.floor(y / ansItemHeight)
- state.cacheButtonPos = {x, y, copies: curCopies >= 6 ? 5 : curCopies}
- }
- const getEleByColor = (color: Colors): HTMLElement => {
- return Array.from(buttonEl.value.children).find( item => item.name == color ) as HTMLElement
- }
- /**
- * 存在五种拖拽情况
- * 1. 答案区为空, 按钮直接放在答案区
- * 2. 答案区存在按钮 , 两个按钮互换位置
- * 3. 直接点击答案区的按钮,答案区按钮回到初始位置
- * 4. 没有放在答案区, 按钮回到初始位置
- * 5. 两个按钮都在答案区, 直接进行按钮之间的交换
- * 6. 将在答案区的按钮直接拖动到另外一个答案区
- * 7. 按钮没在答案区, 但是目标区域已经有按钮了
- * @param ev
- * @param setPos
- */
- const onDragEnd = (ev: TouchEvent, setPos: any) => {
- const target = ev.target as HTMLElement
- const { x, y } = getTransform(ev)
- console.log(x, y);
-
- const cusAttr = JSON.parse(target.attributes.getNamedItem('cusattr')!.value!)
- // 3. 直接点击答案区的按钮,答案区按钮回到初始位置
- if ( state.cacheButtonPos.x == x && state.cacheButtonPos.y == y) {
- setPos(target, { x: cusAttr.x, y: cusAttr.y }, 0.2)
- return
- }
-
- let curCopies = Math.floor( y < 0 ? 0 / ansItemHeight : y / ansItemHeight)
-
- console.log(curCopies);
-
- // 按钮放置判断
- if (ansEl.value.offsetLeft - 23 < x && curCopies < 6 && curCopies >= 0) {
- curCopies = curCopies > 5 ? 5 : curCopies
- // 拖拽的按钮已经在答案区了
- if ( props.card.ans[curCopies].button ) {
- // 5. true 两个按钮都在答案区, 直接进行按钮之间的交换 false 7. 按钮没在答案区, 但是目标区域已经有按钮了
- const flag =props.card.ans[state.cacheButtonPos.copies].button
- const oldTarget = getEleByColor(props.card.ans[curCopies].button as Colors)
- const oldCurAttr = JSON.parse(oldTarget.attributes.getNamedItem('cusattr')!.value!)
- let pos = {x: 0, y : 0}
- if (flag) {
- pos = {x: state.cacheButtonPos.x, y: state.cacheButtonPos.y}
- } else {
- pos = {x: oldCurAttr.x, y: oldCurAttr.y}
- }
- setPos(
- oldTarget,
- pos,
- 0.2
- )
- }
-
-
- // 按钮直接放在答案区
- setPos(
- target,
- { x: ansEl.value.offsetLeft + ansEl.value.offsetWidth - 23,
- y: curCopies * ansItemHeight + ansItemHeight / 2 - 20
- },
- 0.2
- )
- props.card.ans[curCopies].button = cusAttr.color
- } else {
- setPos(target, { x: cusAttr.x, y: cusAttr.y }, 0.2)
- }
- }
- onMounted(() => {
- useDrag(buttonEl.value, { onDragEnd: onDragEnd, onDragStart: onDragStart})
- })
- </script>
- <style lang="scss" scoped>
- .luojigou-board {
- width: 100vw;
- height: 100vh;
- overflow: hidden;
- .navbar {
- width: 100vw;
- height: 104px;
- background: #F9BF4F;
- }
- .opra {
- width: 100vw;
- height: 708px;
- background: url('../../assets/component/LuojigouBoard/board-bg.png');
- display: flex;
- justify-content: center;
- padding-top: 23px;
- .board {
- width: 357px;
- height: 617px;
- position: relative;
- .card {
- width: 303px;
- height: 386px;
- border-radius: 20px;
- overflow: hidden;
- display: flex;
- justify-content: space-between;
- position: absolute;
- top: 103px;
- left: 13px;
- }
- .ques {
- width: 225px;
- height: 386px;
- border-right: 1px solid #006CAA;
- // position: absolute;
- // top: 103px;
- // left: 13px;
- img {
- width: 100%;
- height: 100%;
- display: block;
- }
- }
- .ans {
- width: 85px;
- height: 100%;
- display: flex;
- flex-direction: column;
- border-top-right-radius: 20px;
- border-bottom-right-radius: 20px;
- overflow: hidden;
- background-color: #fff;
- .ans-item {
- border-bottom: 1px solid #006CAA;
- box-sizing: border-box;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- }
- }
- .ans .ans-item:last-child {
- border-bottom: none
- }
- .buttons {
- position: relative;
- top: 100px;
- left: 10px;
- width: 340px;
- height: 500px;
- img {
- position: absolute;
- left: 0;
- top: 0;
- }
- }
- }
- }
- }
- </style>
|