Explorar o código

1.重构拖拽英雄棋子相关逻辑
2.增加拖拽元素附着到棋子上的逻辑

fenggang %!s(int64=5) %!d(string=hai) anos
pai
achega
267a8d5c9c

+ 5 - 1
2019专题/云顶之弈模拟器/src/components/equipment.vue

@@ -1,6 +1,6 @@
 <template>
     <div :class="['equipment', className, flexible ? 'flexible' : '']" @click.stop="selectEquipment">
-      <img :src="equipment.img" alt="" v-if='equipment'>
+      <img :src="equipment.img" alt="" v-if='equipment' :title="equipment.skill">
     </div>
 </template>
 
@@ -26,6 +26,10 @@ export default {
   },
   methods: {
     selectEquipment(){
+      // 元素装备不允许修改
+      if(this.equipment && this.equipment.effectType === 'element') {
+        return
+      }
       this.$emit('selectEquipment', this.equipmentIndex)
     }
   }

+ 0 - 1
2019专题/云顶之弈模拟器/src/components/hero.vue

@@ -54,7 +54,6 @@ export default {
       } else {
         // 此时为阵容中的英雄,此时用户想要 删除英雄 或者 移动英雄 或者 交换英雄
         ev.dataTransfer.setData('heroIndex', this.heroIndex)
-        ev.dataTransfer.setData('moveHero', JSON.stringify(hero))
       }
     },
     handleHeroSelectEquipment(equipmentIndex) {

+ 156 - 63
2019专题/云顶之弈模拟器/src/components/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="app">
-    <div class="container" @dragover="allowDrop" @drop="cancelHeroSelected">
+    <div class="container">
       <div class="title" ></div>
       <div class="guide">
         <a href="http://lol.duowan.com/1908/429554416930.html" target="_blank">>>使用指南<<</a>
@@ -68,20 +68,18 @@
                 @addHero="addHero"/>
             </div>
           <div class="element-box">
-            <div class="element-wrapper" title="火" draggable="true" @dragstart="selectElement($event, 'fire')" >
+            <div :class="['element-wrapper', currentElement === 'fire' ? 'active' : '']" title="火"  @click="currentElement = 'fire'">
                 <div class="element fire"></div>
             </div>
-            <div class="element-wrapper" title="水" draggable="true" @dragstart="selectElement($event, 'water')" >
+            <div :class="['element-wrapper', currentElement === 'water' ? 'active' : '']" title="水" @click="currentElement = 'water'">
                 <div class="element water"></div>
             </div>
-            <div class="element-wrapper" title="风" draggable="true" @dragstart="selectElement($event, 'wind')" >
+            <div :class="['element-wrapper', currentElement === 'wind' ? 'active' : '']" title="风"  @click="currentElement = 'wind'">
                 <div class="element wind"></div>
             </div>
-            <div class="element-wrapper" title="土" draggable="true" @dragstart="selectElement($event, 'earth')" >
+            <div :class="['element-wrapper', currentElement === 'earth' ? 'active' : '']" title="土" @click="currentElement = 'earth'">
                 <div class="element earth"></div>
             </div>
-
-
           </div>
           </div>
         </div>
@@ -144,6 +142,7 @@
                   @heroSelectEquipment="handleHeroSelectEquipment"
                   @deleteHero="handleDeleteHero"
                 />
+                <div :class="['element-bg', currentElement]" v-if="memoElementsIndexes.includes(index)" draggable="true" @dragstart="handleDragElementStart"></div>
               </div>
               <transition name="slide-fade">
                 <div
@@ -336,6 +335,8 @@ const MAX_HEROES_COUNT = 28 // 棋盘所能容纳的最大英雄上限
 const MAX_PLAYER_LEVEL = 9 // 玩家最大等级
 const MIN_PLAYER_LEVEL = 1 // 玩家最小等级
 const LOCALSTORAGE_KEY = '__ydzySimulatorUserInfo'
+const elements = ['fire', 'water', 'wind', 'earth'] // 元素属性
+const elementEquipmentsMap = {}  // 元素属性与元素装备的映射
 
 let fetters
 const original = {}
@@ -349,6 +350,15 @@ function duplicateHeroes(heroes) {
   return Object.values(map)
 }
 
+function initElementsIndexes (){
+  const ret = []
+  while(ret.length < 2) {
+    let n = genRandomInteger(0, MAX_HEROES_COUNT - 1)
+    !ret.includes(n) && ret.push(n)
+  }
+  return ret
+}
+
 export default {
   data() {
     return {
@@ -361,7 +371,8 @@ export default {
       goals: [], // 待激活的羁绊
       extra_population: 0, // 通过装备额外增加的人口
       level: 1, // 当前玩家等级
-      currentElement: '', // 当前格子元素
+      currentElement: elements[genRandomInteger(0, elements.length - 1)], // 当前格子元素
+      memoElementsIndexes: initElementsIndexes(), // 记录带元素格子的索引
       starSelectorVisiable: false, // 控制小小英雄选星级的对话框的显隐
       littleHeroSelectorVisiable: false, // 小小英雄选择框的显隐
       sharingPopupVisiable: false, // 分享对话框显隐
@@ -402,48 +413,7 @@ export default {
     }
   },
   methods: {
-    // 拖拽取消英雄选择 / 移动棋盘内英雄
-    cancelHeroSelected(ev) {
-      const classList = ev.target.classList
-      if (classList.contains('board-grid')) {
-        // 此时用户为想从棋盘上移动该英雄
-        const heroIndex = ev.dataTransfer.getData('heroIndex')
-
-        if (heroIndex !== '') {
-          const targetIndex = Array.from(document.querySelectorAll('.board-grid')).indexOf(ev.target)
-          const hero = JSON.parse(ev.dataTransfer.getData('moveHero'))
-          this.selectedHeroes.splice(Number(heroIndex), 1, null)
-          this.selectedHeroes.splice(targetIndex, 1, hero)
-        }
-        return
-      }
-
-      if (classList.contains('hero') || classList.contains('item-hero') || classList.contains('equipment')) {
-        // 此时代表棋盘上有英雄, 用户想要交换两英雄位置
-        const heroIndex = ev.dataTransfer.getData('heroIndex')
-        if (heroIndex) {
-          // 对用户拖拽时的容错处理
-          const targetNode = ev.target.parentNode.classList.contains('board-grid') ? ev.target.parentNode : 
-            ev.target.parentNode.parentNode.classList.contains('board-grid') ? ev.target.parentNode.parentNode : null
-          if(!targetNode) { return }
-          
-          const targetIndex = Array.from(
-            document.querySelectorAll('.board-grid')
-          ).indexOf(targetNode)
-
-          const hero = JSON.parse(ev.dataTransfer.getData('moveHero'))
-          this.selectedHeroes.splice(Number(heroIndex),1,this.selectedHeroes[targetIndex])
-          this.selectedHeroes.splice(targetIndex, 1, hero)
-        }
-        return
-      }
 
-      // 此时用户为想从棋盘上删除该英雄
-      const heroIndex = ev.dataTransfer.getData('heroIndex')
-      if (heroIndex !== '') {
-        this.selectedHeroes.splice(Number(heroIndex), 1, null)
-      }
-    },
     // 点击取消英雄选择
     handleDeleteHero(heroIndex) {
       this.selectedHeroes.splice(heroIndex, 1, null)
@@ -491,28 +461,66 @@ export default {
       this.extra_population = 0
       this.level = 1
     },
-    selectElement(ev, element){
-      this.currentElement = element
-      ev.dataTransfer.setData('element', element)
+    handleDragElementStart(ev){
+      const parentNode = ev.target.parentNode
+      const targetIndex = Array.from(document.querySelectorAll('.board-grid')).indexOf(parentNode)
+      ev.dataTransfer.setData('elementIndex', targetIndex)
     },
-    // 拖拽添加英雄到阵容中 或者 拖拽元素到格子里
-    handleDrop(ev, heroIndex) {
+    // 拖拽添加英雄到阵容中
+    handleDrop(ev, targetIndex) {
       ev.preventDefault()
+      ev.stopPropagation()
+      const classList = ev.target.classList
+      const elementIndex = ev.dataTransfer.getData('elementIndex') ? Number(ev.dataTransfer.getData('elementIndex')) : -1
+      const heroIndex = ev.dataTransfer.getData('heroIndex') ? Number(ev.dataTransfer.getData('heroIndex')) : -1
+      const hero = this.selectedHeroes[heroIndex]
       // 拖拽添加英雄
       if (ev.dataTransfer.getData('hero')) {
         if (this.currentPopulation < this.currentMaxHero) {
           const hero = JSON.parse(ev.dataTransfer.getData('hero'))
-          this.selectedHeroes.splice(heroIndex, 1, hero)
+          this.selectedHeroes.splice(targetIndex, 1, hero)
         } else {
           alert('你该升级啦~点击小小英雄下方的升级按钮提升你的等级吧~')
         }
+        return
+      }
+
+
+      if (classList.contains('board-grid')) {
+        if(elementIndex > -1) {
+          // 此时为用户将元素移动到空棋子上
+          this.memoElementsIndexes.splice(this.memoElementsIndexes.indexOf(elementIndex), 1, targetIndex)
+        } else {
+        // 此时用户为想从棋盘上移动该英雄
+          if (heroIndex > -1 && hero) {
+            this.selectedHeroes.splice(heroIndex, 1, null)
+            this.selectedHeroes.splice(targetIndex, 1, hero)
+          }
+        }
+        return
+      }
+      
+      if (classList.contains('hero') || classList.contains('item-hero') || classList.contains('equipment')) {
+        if(elementIndex > -1) {
+          // 此时为用户将元素移动到有英雄棋子的位置上
+          this.memoElementsIndexes.splice(this.memoElementsIndexes.indexOf(elementIndex), 1, targetIndex)
+        } else {
+          // 此时为用户想要交换棋子位置
+          if (heroIndex > -1 && hero) {
+            this.selectedHeroes.splice(heroIndex,1,this.selectedHeroes[targetIndex])
+            this.selectedHeroes.splice(targetIndex, 1, hero)
+          }
+        }
+        return
       }
 
-      // 拖拽添加元素
-      if(ev.dataTransfer.getData('element')) {
-        if(!this.selectedHeroes[heroIndex]) {
-          console.log('空格子')
+      if(classList.contains('element-bg')){
+        // 此时为用户想要将英雄棋子移动到有元素的空位上
+        if(elementIndex === -1) {
+          this.selectedHeroes.splice(heroIndex, 1, null)
+          this.selectedHeroes.splice(targetIndex, 1, hero)
         }
+        // 另外一种情况为用户将带有元素的棋子拖拽到另一带有元素的棋子,这种情况不需要处理。
       }
     },
     // 选择小小英雄星级
@@ -538,6 +546,9 @@ export default {
     },
     // 点击添加英雄到阵容中
     addHero(_hero){
+      if(_hero.name === '大元素使 拉克丝' && this.selectedHeroes.find(h => h && h.name === '大元素使 拉克丝')) {
+        return alert('场上只能存在一个拉克丝。')
+      }
       if (this.currentPopulation < this.currentMaxHero) {
         const positon = this.selectedHeroes.findIndex(el => !el)
         this.selectedHeroes.splice(positon, 1, JSON.parse(JSON.stringify(_hero)))
@@ -671,19 +682,38 @@ export default {
         let duplicatedHeroes = duplicateHeroes(filteredHero)
 
         duplicatedHeroes.forEach(hero => {
-          // 拉克丝特殊处理一下
+          // 拉克丝特殊处理
           if (hero.name === '大元素使 拉克丝') {
             hero.sort.forEach(job => {
               heroCount[job] += 2
             })
-          } else {
-            hero.sort.forEach(job => {
+            hero.job.forEach(job => {
+              heroCount[job]++
+            })
+            return
+          }
+
+          // 元素女皇特殊处理
+          if(hero.name === '元素女皇 琪亚娜') {
+            const elementToFetter = {
+              water: 'heroSort7',
+              fire: 'heroSort5',
+              wind: 'heroSort2',
+              earth: 'heroSort11'
+            }
+            heroCount[ elementToFetter[this.currentElement] ]++
+            hero.job.forEach(job => {
               heroCount[job]++
             })
+            return
           }
+          hero.sort.forEach(job => {
+            heroCount[job] ++
+          })
           hero.job.forEach(job => {
             heroCount[job]++
           })
+
         })
 
         // 重复的英雄带的装备只有自然之力不是唯一被动
@@ -788,6 +818,19 @@ export default {
         this.$off('selectEquipment')
         this.$off('cancelEquipmentSelected')
       }
+    },
+    currentElement(newVal){
+      // 这里的逻辑针对琪亚娜这个英雄做特殊处理
+      const heroIndex = this.selectedHeroes.findIndex(h => h.name === '元素女皇 琪亚娜')
+      if(heroIndex !== -1) {
+        const elementToFetter = {
+          water: 'heroSort7',
+          fire: 'heroSort5',
+          wind: 'heroSort2',
+          earth: 'heroSort11'
+        }
+        this.selectedHeroes[heroIndex].sort = [elementToFetter[newVal]]
+      }
     }
   },
   mounted() {
@@ -815,8 +858,14 @@ export default {
 
       initData()
 
+      const simulatorEquipment = []
+
+      data.simulatorEquipment.forEach(eq => {
+        eq.effectType !== 'element' ? simulatorEquipment.push(eq) : elementEquipmentsMap[eq.effectJob] = eq
+      })
+
       fetters = data.fetters
-      this.simulatorEquipment = data.simulatorEquipment
+      this.simulatorEquipment = simulatorEquipment
       this.heroes = data.hero.data
       this.littleHeroes = data.littleHero.data
     })
@@ -968,6 +1017,42 @@ export default {
             &.filled {
               background: none;
             }
+            // &.withElement{
+            //   background-color: red;
+            // }
+            .element-bg{
+              width: 81px;
+              height: 92px;
+              position: absolute;
+              left: 2px;
+              top: 2px;
+              opacity: 0.6;
+              transition: all 0.3s ease;
+              z-index: -1;
+              clip-path: polygon(
+                    50% 0%,
+                    100% 25%,
+                    100% 75%,
+                    50% 100%,
+                    0% 75%,
+                    0% 25%
+              );
+              &.fire{
+                background: url('../assets/images/fire.png') no-repeat 100% / 100%;
+              }
+              &.water{
+                background: url('../assets/images/water.png') no-repeat 100% / 100%;
+              }
+              &.earth{
+                background: url('../assets/images/earth.png') no-repeat 100% / 100%;
+              }
+              &.wind{
+                background: url('../assets/images/wind.png') no-repeat 100% / 100%;
+              }
+              &:hover{
+                opacity: 0.8;
+              }
+            }
           }
           &.small {
             &:nth-child(n + 4) {
@@ -1295,6 +1380,8 @@ export default {
         .element-box {
           display: flex;
           justify-content: space-evenly;
+          border: 1px solid #635d60;
+          padding: 10px 0;
           .element-wrapper{
             width: 70px;
             height: 81px;
@@ -1303,6 +1390,12 @@ export default {
             background: url("../assets/images/icon-colorful.png") no-repeat 100% / 100%;
             position: relative;
             z-index: 1;
+            cursor: pointer;
+            transition: all 0.3s cubic-bezier(.06,1.45,.46,1.6);
+            &.active{
+              transform: translateY(-10px);
+              filter: brightness(1.3);
+            }
           }
           .element {
             position: absolute;