<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                數據驅動是 Vue 框架的核心特性之一,也是 Vue 響應式原理的具體體現,相信大家對其應該深有體會,尤其是在操作數據來觸發頁面更新的時候。 為了讓大家更加了解數據驅動的理念,并解決使用過程中可能出現的一系列問題,本文將結合比較常見和簡單的 “拼圖游戲” 來展示 Vue 數據驅動的魅力所在。 ## 效果展示 首先我們先來看一下實現的 “拼圖游戲” 的動態效果: ![](https://img.kancloud.cn/a5/7f/a57f4c797e4e005a6f8570e28fccbdde_360x240.gif) 在不操作 `DOM` 的情況下實現以上功能其實需要我們對 Vue 數據驅動及數據可視化有一個非常清楚的認知,在操作數據的同時驅動可視化界面的還原。 ## 關鍵代碼 接下來我們來看一下實現該拼圖游戲的功能點及關鍵代碼: ### 游戲面板的構建 ``` <!-- HTML 部分 --> <ul class="puzzle-wrap"> <li :class="{'puzzle': true, 'puzzle-empty': !puzzle}" v-for="(puzzle, index) in puzzles" :key="index" v-text="puzzle" ></li> </ul> ``` ``` // 數據部分 export default { data() { return { puzzles: Array.from({ length: 15 }, (value, index) => index + 1) } }, } ``` 上方我們使用 `v-for` 循環構建了從 1 ~ 15 按順序排列的方塊格子,也就是拼圖完成時候的順序,但是拼圖游戲一開始數字的順序應該是無序的,也是隨機打亂的,那么我們怎么實現呢?可以使用下方的隨機排列函數: ``` function shuffle(arr) { let len = arr.length for (let i = 0; i < len - 1; i++) { let idx = Math.floor(Math.random() * (len - i)) let temp = arr[idx] arr[idx] = arr[len - i - 1] arr[len - i - 1] = temp } return arr } ``` 該函數中我們使用 `Math.random()` 來返回 0 和 1 之間的偽隨機數,可能為 0,但總是小于1,\[0, 1),而通過這一特性我們可以實現生成 n-m,包含 n 但不包含 m 的整數,具體步驟如下: * 第一步算出 `m-n` 的值,假設等于 w * 第二步 `Math.random() * w` * 第三步 `Math.random() * w + n` * 第四步 `Math.floor(Math.random() * w + n)` 在 `shuffle` 函數中 n 值永遠是 0,而 w(即 len - i) 值隨著循環 i 值的變大而不斷減小。 > 在上面的算法里,我們每一次循環從前 len - i 個元素里隨機一個位置,將這個元素和第 len - i 個元素進行交換,迭代直到 i = len - 1 為止。 這一便實現了數組的隨機打亂。最后我們需要在數組末尾追加一個空值來顯示唯一一個空白格子: ``` this.puzzles.push(''); ``` ### 交換方塊位置 實現隨機數字后,當我們點擊方塊,如果其上下左右存在為空的格子就需要將其進行交換,而由于是數據驅動界面,這里我們便需要交換兩者在數組中的位置來實現: ``` export default { methods: { // 點擊方塊 moveFn(index) { let puzzles = this.puzzles // 獲取點擊位置上下左右的值 let leftNum = this.puzzles[index - 1], rightNum = this.puzzles[index + 1], topNum = this.puzzles[index - 4], bottomNum = this.puzzles[index + 4] // 和為空的位置交換數值 if (leftNum === '' && index % 4) { this.setPuzzle(index, -1) } else if (rightNum === '' && 3 !== index % 4) { this.setPuzzle(index, 1) } else if (topNum === '') { this.setPuzzle(index, -4) } else if (bottomNum === '') { this.setPuzzle(index, 4) } }, // 設置數組值 setPuzzle(index, num) { let curNum = this.puzzles[index] this.$set(this.puzzles, index + num, curNum) this.$set(this.puzzles, index, '') }, } } ``` 由于是 16 宮格的拼圖,所以我們在點擊獲取位置的時候需要考慮邊界情況,比如第 4 個格子為空,我們點擊第 5 個格子不應該交換它們,因為在界面上第 4 個格子不在第 5 個格子的左側,所以我們使用 `index % 4` 的方法來進行邊界的判斷,同時使用 Vue 提供的 `$set` 方法來將響應屬性添加到數組上。 ### 校驗是否過關 最后我們需要校驗游戲是否過關,我們只需要在最后一個格子為空時去進行校驗即可: ``` if (this.puzzles[15] === '') { const newPuzzles = this.puzzles.slice(0, 15) const isPass = newPuzzles.every((e, i) => e === i + 1) if (isPass) { alert ('恭喜,闖關成功!') } } ``` 我們使用數組的 `every` 方法來簡化代碼的復雜度,當所有數字大小和對應的數組下標 + 1 相吻合時即會返回 `true`。 如此我們便完成了一個簡單拼圖游戲的功能。 ## 盲點及誤區 在實現拼圖游戲后,有些同學可能會存在一些疑惑,比如:數組賦值為什么要用 $set 方法?數組隨機打亂為什么不用 sort 排序呢?下面便來進行講解: ### 為什么要用 $set 方法 大家應該都知道如果不用 `$set` 方法我們可以直接通過操作數組索引的形式對數組進行賦值,從而交換拼圖的中兩者的數據: ``` // 設置數組值 setPuzzle(index, num) { let curNum = this.puzzles[index] this.puzzles[index + num] = curNum this.puzzles[index] = '' // this.$set(this.puzzles, index + num, curNum) // this.$set(this.puzzles, index, '') } ``` 但是你會發現這樣做數據是改變了,但是頁面并沒有因此重新渲染,這是為什么呢?其實 Vue 官方已經給出了明確的答案: > 由于 JavaScript 的限制,Vue 不能檢測以下變動的數組: > > * 當你利用索引直接設置一個項時,例如:vm.items\[indexOfItem\] = newValue > * 當你修改數組的長度時,例如:vm.items.length = newLength 我們這里使用的便是第一種利用索引的方式,由于 Vue 檢測不到數組變動,因此頁面便無法重繪。同樣 Vue 也不能檢測對象屬性的添加或刪除,需要使用 `Vue.set(object, key, value)` 方法來實現。 其實還有一種比較取巧的方式便是強制重新渲染 Vue 實例來解決這一問題: ``` // 設置數組值 setPuzzle(index, num) { let curNum = this.puzzles[index] this.puzzles[index + num] = curNum this.puzzles[index] = '' this.$forceUpdate() // 迫使 Vue 實例重新渲染 // this.$set(this.puzzles, index + num, curNum) // this.$set(this.puzzles, index, '') } ``` 上方我們使用了 Vue 提供的 `$forceUpdate` 方法迫使 Vue 實例重新渲染,這樣改變的數據就會被更新的頁面中去。但是最好不要這樣操作,因為這會導致 Vue 重新遍歷此對象所有的屬性,一定程度上會影響頁面的性能。 ### 為什么不用 sort 排序 其實 sort 方法也能夠實現數組的隨機排序,代碼如下: ``` let puzzleArr = Array.from({ length: 15 }, (value, index) => index + 1); // 隨機打亂數組 puzzleArr = puzzleArr.sort(() => { return Math.random() - 0.5 }); ``` 我們通過使用 `Math.random()` 的隨機數減去 0.5 來返回一個大于、等于或小于 0 的數,sort 方法會根據接收到的值來對相互比較的數據進行升序或是降序排列。 但是由于 JavaScript 內置排序算法的缺陷性,使用 sort 排序的結果并不隨機分布,經過大量的測試你會發現**越大的數字出現在越后面的概率越大**。 由于本文并非是一篇介紹 sort 排序的文章,關于論證其缺陷性的話題這里就不進行詳細展開了,感興趣的同學可以進一步進行探究。 ## 結語 本文實例是基于我之前寫的一篇關于利用 Vue.js 實現拼圖游戲的文章上進行了改進和優化,希望通過這樣一個小游戲來強化大家對于 Vue 數據驅動的理解。相比操作 DOM 元素,操作數據其實更加的便捷和快速,可以使用較少的代碼來實現一些較為復雜的邏輯。 具體實例代碼可以參考:[puzzle](https://github.com/luozhihao/vue-project-code/blob/ea7294370af888084be41c10c914b4fedbf3f400/ui-framework-project/src/views/demo/puzzle.vue) ## 思考 & 作業 * Vue 中監聽數據變化的原理是什么?是通過何種方式實現的? * 如何論證原生 JS 中 sort 排序后越大的數字出現在越后面的概率越大? * 如何使用 `Math.random()` 生成 n-m,不包含 n 但包含 m 的整數?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看