Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 99久久免费观看,亚洲欧美啪啪,久久成人国产精品二三区

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          使用vue實(shí)現(xiàn)排序算法演示動(dòng)畫

          最近做的一個(gè)小需求涉及到排序,界面如下所示:

          因?yàn)轫?xiàng)目是使用vue的,所以實(shí)現(xiàn)方式很簡(jiǎn)單,視圖部分不用管,本質(zhì)上就是操作數(shù)組,代碼如下:

          {
              // 上移
              moveUp (i) {
                  // 把位置i的元素移到i-1上
                let tmp = this.form.replayList.splice(i, 1)
                this.form.replayList.splice(i - 1, 0, tmp[0])
              },
          
              // 下移
              moveDown (i) {
                  // 把位置i的元素移到i+1上
                let tmp = this.form.replayList.splice(i, 1)
                this.form.replayList.splice(i + 1, 0, tmp[0])
              }
          }

          這樣就可以正常的交換位置了,但是是突變的,沒(méi)有動(dòng)畫,所以不明顯,于是一個(gè)碼農(nóng)的自我修養(yǎng)(實(shí)際上是太閑)讓我打開了vue的網(wǎng)站,看到了這個(gè)示例:https://cn.vuejs.org/v2/guide/transitions.html#%E5%88%97%E8%A1%A8%E7%9A%84%E6%8E%92%E5%BA%8F%E8%BF%87%E6%B8%A1

          這個(gè)示例我已看過(guò)多遍,但是一直沒(méi)用過(guò),這里剛好就是我要的效果,于是一通復(fù)制粘貼大法:

          <template>
              <transition-group name="flip-list" tag="p">
                  <!--循環(huán)生成列表部分,略-->
              </transition-group>
          </template>
          
          <style>
          .flip-list-move {
            transition: transform 0.5s;
          }
          </style>

          這樣就有交換的過(guò)渡效果了,如下:

          嗯,舒服了很多,這個(gè)需求到這里就完了,但是事情并沒(méi)有結(jié)束,我突然想到了以前看一些算法文章的時(shí)候通常會(huì)配上一些演示的動(dòng)畫,感覺(jué)跟這個(gè)很類似,那么是不是可以用這個(gè)來(lái)實(shí)現(xiàn)呢,當(dāng)然是可以的。

          實(shí)現(xiàn)算法演示動(dòng)畫

          先寫一下基本的布局和樣式:

          <template>
            <div class="sortList">
                <transition-group name="flip-list" tag="p">
                  <div
                    class="item"
                    v-for="item in list"
                    :key="item.index"
                    :style="{height: (item.value / max * 100) + '%'}"
                  >
                    <span class="value">{{item.value}}</span>
                  </div>
                </transition-group>
              </div>
          </template>
          
          <style>
          .flip-list-move {
            transition: transform 0.5s;
          }
          </style>

          list是要排序的數(shù)組,當(dāng)然是經(jīng)過(guò)處理的,在真正的源數(shù)組上加上了唯一的index,因?yàn)橐苷_^(guò)渡的話列表的每一項(xiàng)需要一個(gè)唯一的key:

          const arr = [10, 43, 23, 65, 343, 75, 100, 34, 45, 3, 56, 22]
          
          export default {
            data () {
              return {
                list: arr.map((item, index) => {
                  return {
                    index,
                    value: item
                  }
                })
              }
            }
          }

          max是這個(gè)數(shù)組中最大的值,用來(lái)按比例顯示高度:

          {
              computed: {
                  max () {
                      let max = 0
                      arr.forEach(item => {
                          if (item > max) {
                              max = item
                          }
                      })
                      return max
                  }
            }
          }

          其他樣式可以自行發(fā)揮,顯示效果如下:

          簡(jiǎn)約而不簡(jiǎn)單~,現(xiàn)在萬(wàn)事俱備,只欠讓它動(dòng)起來(lái),排序算法有很多,但是本人比較菜,所以就拿冒泡算法來(lái)舉例,最最簡(jiǎn)單的冒泡排序算法如下:

          {
              mounted(){
                  this.bubbleSort()
              },
              methods: {
                  bubbleSort() {
                    let len = this.list.length
          
                    for (let i = 0; i < len; i++) {
                      for (let j = 0; j < len - i - 1; j++) {
                        if (this.list[j] > this.list[j + 1]) {  // 相鄰元素兩兩對(duì)比
                          let tmp = this.list[j]        // 元素交換
                          this.$set(this.list, j, this.list[j + 1])
                          this.$set(this.list, j + 1, tmp)
                        }
                      }
                    }
                  }
              }
          }

          但是這樣寫它是不會(huì)動(dòng)的,瞬間就給你排好了:

          試著加個(gè)延時(shí):

          {
              mounted () {
                  setTimeout(() => {
                      this.bubbleSort()
                  }, 1000)
              }
          }

          刷新看效果:

          有動(dòng)畫了,不過(guò)這種不是我們要的,我們要的應(yīng)該是下面這樣的才對(duì):

          所以來(lái)改造一下,因?yàn)閒or循環(huán)是只要開始執(zhí)行就不會(huì)停的,所以需要把兩個(gè)for循環(huán)改成兩個(gè)函數(shù),這樣可以控制每個(gè)循環(huán)什么時(shí)候執(zhí)行:

          {
              bubbleSort () {
                let len = this.list.length
                let i = 0
                let j = 0
                // 內(nèi)層循環(huán)
                let innerLoop = () => {
                  // 每個(gè)內(nèi)層循環(huán)都執(zhí)行完畢后再執(zhí)行下一個(gè)外層循環(huán)
                  if (j >= (len - 1 - i)) {
                    j = 0
                    i++
                    outLoop()
                    return false
                  }
                  if (this.list[j].value > this.list[j + 1].value) {
                    let tmp = this.list[j]
                    this.$set(this.list, j, this.list[j + 1])
                    this.$set(this.list, j + 1, tmp)
                  }
                  // 動(dòng)畫是500毫秒,所以每隔800毫秒執(zhí)行下一個(gè)內(nèi)層循環(huán)
                  setTimeout(() => {
                    j++
                    innerLoop()
                  }, 800)
                }
                // 外層循環(huán)
                let outLoop = () => {
                  if (i >= len) {
                    return false
                  }
                  innerLoop()
                }
                outLoop()
              }
          }

          這樣就實(shí)現(xiàn)了每一步的動(dòng)畫效果:

          但是這樣不太直觀,因?yàn)橛行┫噜彶挥媒粨Q的時(shí)候啥動(dòng)靜也沒(méi)有,不知道當(dāng)前具體排到了哪兩個(gè),所以需要突出當(dāng)前正在比較交換的兩個(gè)元素,首先模板部分給當(dāng)前正在比較的元素加一個(gè)類名,用來(lái)高亮顯示:

          <div
               :class="{sortingHighlight: sorts.includes(item.index)}"
               >
              <span class="value">{{item.value}}</span>
          </div>

          js部分定義一個(gè)數(shù)組sorts來(lái)裝載當(dāng)前正在比較的兩個(gè)元素的唯一的index值:

          {
              data() {
                  return {
                      sorts: []
                  }
              },
              methods: {
                  bubbleSort () {
                      // ...
                      // 內(nèi)層循環(huán)
                      let innerLoop = () => {
                          // 每個(gè)內(nèi)層循環(huán)都執(zhí)行完畢后再執(zhí)行下一個(gè)外層循環(huán)
                          if (j >= (len - 1 - i)) {
                              // 清空數(shù)組
                              this.sorts = []
                              j = 0
                              i++
                              outLoop()
                              return false
                          }
                          // 將當(dāng)前正在比較的兩個(gè)元素的index裝到數(shù)組里
                          this.sorts = [this.list[j].index, this.list[j + 1].index]
                          // ...
                      }
                      // 外層循環(huán)
                      // ...
                  }
              }
          }

          修改后效果如下:

          最后,再參考剛才別人的示例把已排序的元素也加上高亮:

          {
              data() {
                  return {
                      sorted: []
                  }
              },
              methods: {
                  bubbleSort () {
                      // ...
                      // 內(nèi)層循環(huán)
                      let innerLoop = () => {
                          // 每個(gè)內(nèi)層循環(huán)都執(zhí)行完畢后再執(zhí)行下一個(gè)外層循環(huán)
                          if (j >= (len - 1 - i)) {
                              this.sorts = []
                              // 看這里,把排好的元素加到數(shù)組里就ok了
                              this.sorted.push(this.list[j].index)
                              j = 0
                              i++
                              outLoop()
                              return false
                          }
                          // ...
                      }
                      // 外層循環(huán)
                      // ...
                  }
              }
          }

          最終效果如下:

          接下來(lái)看一下選擇排序,這是選擇排序的算法:

          {
              selectSort() {
                  for (let i = 0; i < len - 1; i++) {
                      minIndex = i
                      for (let j = i + 1; j < len; j++) {
                          if (this.list[j].value < this.list[minIndex].value) {
                              minIndex = j
                          }
                      }
                      tmp = this.list[minIndex]
                      this.$set(this.list, minIndex, this.list[i])
                      this.$set(this.list, i, tmp)
                  }
              }
          }

          選擇排序涉及到一個(gè)當(dāng)前最小元素,所以需要新增一個(gè)高亮:

          <div
               :class="{minHighlight: min === item.index , sortingHighlight: sorts.includes(item.index), sortedHighlight: sorted.includes(item.index)}"
               >
              <span class="value">{{item.value}}</span>
          </div>
          {
              data () {
                  return {
                      min: 0
                  }
              },
              methods: {
                  selectSort () {
                      let len = this.list.length
                      let i = 0; let j = i + 1
                      let minIndex, tmp
                      // 內(nèi)層循環(huán)
                      let innerLoop = () => {
                          if (j >= len) {
                              // 高亮最后要交換的兩個(gè)元素
                              this.sorts = [this.list[i].index, this.list[minIndex].index]
                              // 延時(shí)是用來(lái)給高亮一點(diǎn)時(shí)間
                              setTimeout(() => {
                                  // 交換當(dāng)前元素和比當(dāng)前元素小的元素的位置
                                  tmp = this.list[minIndex]
                                  this.$set(this.list, minIndex, this.list[i])
                                  this.$set(this.list, i, tmp)
                                  this.sorted.push(this.list[i].index)
                                  i++
                                  j = i + 1
                                  outLoop()
                              }, 1000)
                              return false
                          }
                          // 高亮當(dāng)前正在尋找中的元素
                          this.sorts = [this.list[j].index]
                          // 找到比當(dāng)前元素小的元素
                          if (this.list[j].value < this.list[minIndex].value) {
                              minIndex = j
                              this.min = this.list[j].index
                          }
                          setTimeout(() => {
                              j++
                              innerLoop()
                          }, 800)
                      }
                      let outLoop = () => {
                          if (i >= len - 1) {
                              this.sorted.push(this.list[i].index)
                              return false
                          }
                          minIndex = i
                          this.min = this.list[i].index
                          innerLoop()
                      }
                      outLoop()
                  }
              }
          }

          效果如下:

          其他的排序也是同樣的套路,將for循環(huán)或while循環(huán)改寫成可以控制的函數(shù)形式,然后可能需要稍微修改一下顯示邏輯,如果你也有打算寫排序文章的話現(xiàn)在就可以給自己加上動(dòng)圖展示了!

          總結(jié)

          之前看到這些動(dòng)圖的時(shí)候也有想過(guò)怎么實(shí)現(xiàn),但是都沒(méi)有深究,這次業(yè)務(wù)開發(fā)無(wú)意中也算找到了其中的一種實(shí)現(xiàn)方式,其實(shí)核心邏輯很簡(jiǎn)單,關(guān)鍵是很多時(shí)候沒(méi)有想到可以這么做,這也許是框架帶給我們的另一些好處吧。

          天我們學(xué)習(xí)的內(nèi)容有:過(guò)渡,動(dòng)畫,轉(zhuǎn)換,伸縮盒子。

          可以說(shuō)今天學(xué)習(xí)的內(nèi)容都是重量級(jí)的大佬,學(xué)好了,使用css3做出酷炫的效果 So Easy!~~

          1.過(guò)渡

          在css3中,有一個(gè)屬性可以設(shè)置過(guò)渡效果。

          它就是transition,所謂的過(guò)渡效果,指的就是以動(dòng)畫的形式慢慢演化樣式屬性變化的過(guò)程。

          A.案例:通過(guò)transition設(shè)置焦點(diǎn)過(guò)渡效果

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{width: 200px;height: 200px;margin:200px;background: url(girl.jpg);border-radius:50%;transition:all 1s linear 0.3s;cursor: pointer;}div:hover{box-shadow: 0px 0px 20px blue;}</style></head><body><div></div></body></html>

          注意頁(yè)面中的代碼:

          第一,我們給div添加了一個(gè)hover偽類樣式,當(dāng)我們鼠標(biāo)懸停在div上方的時(shí)候,會(huì)給div盒子添加一個(gè)藍(lán)色的盒子陰影。

          第二,我們給div盒子添加了一個(gè)transition樣式,設(shè)置的值為:all 1s linear 0.3s;

          這四個(gè)數(shù)據(jù)分別對(duì)應(yīng)

          transition-property(需要過(guò)渡的屬性):如果設(shè)置為all表示所有樣式屬性都需要過(guò)渡。

          transition-duration(過(guò)渡的時(shí)間):以秒作為單位,設(shè)置過(guò)渡的時(shí)間

          transition-timing-function(過(guò)渡的方式):常用的有l(wèi)inear(勻速),ease(先慢后快),ease-in,ease-out,ease-in-out等

          transition-delay(延遲的時(shí)間):以秒作為單位進(jìn)行延遲,延遲之后開始進(jìn)行過(guò)渡效果。

          所以,我們通過(guò)transition這個(gè)復(fù)合屬性設(shè)置的過(guò)渡效果為:

          all:需要過(guò)渡所有的屬性

          1s:過(guò)渡的時(shí)間為1秒

          linear:勻速過(guò)渡

          0.3s:在延遲0.3秒之后開始過(guò)渡動(dòng)畫。

          如果大家理解了上面的描述,那么也就不難理解咱們鼠標(biāo)放到div上之后,為啥會(huì)慢慢出現(xiàn)藍(lán)色的光暈了,就是因?yàn)樵蹅兲砑恿诉^(guò)渡,所以,慢慢的就會(huì)給盒子添加陰影效果。

          2.動(dòng)畫:

          在學(xué)習(xí)完了過(guò)渡之后,發(fā)現(xiàn)咱們可以使用transition去以動(dòng)畫的形式展示樣式的改變以及變化的過(guò)程,這可以幫助我們來(lái)實(shí)現(xiàn)一些過(guò)渡的動(dòng)畫。

          但是,有的時(shí)候,我們的需求會(huì)更加的復(fù)雜,要求會(huì)更加的多變,那么,transition可能就無(wú)法滿足我們的需要了,我們需要有更加炫酷,復(fù)雜的效果呈現(xiàn)。

          那么,動(dòng)畫animation就可以滿足我們的需要。

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>@keyframes moveAndChange{0%{left:0px;top:0px;}25%{left:200px;top:200px;background:green;border-radius: 0;}50%{left:400px;top:200px;background:blue;border-radius: 50%;}75%{left:400px;top:0px;background:#ccc;border-radius: 0;}100%{left:0px;top:0px;background:red;border-radius: 50%;}}div{margin:200px;width: 200px;height: 200px;position: absolute;background:red;border-radius:50%;animation: moveAndChange 5s linear 0.5s infinite normal;}</style></head><body><div></div></body></html>

          代碼效果如下:

          同樣,讓我們來(lái)關(guān)注編寫的代碼:

          1.在樣式中,首先我們使用@keyframes 來(lái)定義了一個(gè)復(fù)雜的動(dòng)畫,在css3中,新增了@keyframes可以來(lái)幫助我們添加動(dòng)畫。代碼如下:

          /*動(dòng)畫的名字叫做moveAndChange*/

          @keyframes moveAndChange{

          /*動(dòng)畫最初的時(shí)候,將left設(shè)置為0px,top設(shè)置為0px*/

          0%{

          left:0px;

          top:0px;

          }

          /*當(dāng)動(dòng)畫進(jìn)行到25%的時(shí)候,使用動(dòng)畫將left過(guò)渡到200px,top過(guò)渡到200px,

          背景顏色過(guò)渡為綠色,圓角過(guò)渡為0(無(wú)圓角)*/

          25%{

          left:200px;

          top:200px;

          background:green;

          border-radius: 0;

          }

          /*當(dāng)動(dòng)畫進(jìn)行到50%的時(shí)候,使用動(dòng)畫將left過(guò)渡到400px,top過(guò)渡到200px,

          背景顏色過(guò)渡為藍(lán)色,圓角過(guò)渡為50%(正圓)*/

          50%{

          left:400px;

          top:200px;

          background:blue;

          border-radius: 50%;

          }

          /*當(dāng)動(dòng)畫進(jìn)行到75%的時(shí)候,使用動(dòng)畫將left過(guò)渡到400px,top過(guò)渡到0,

          背景顏色過(guò)渡為灰色,圓角過(guò)渡為0(無(wú)圓角)*/

          75%{

          left:400px;

          top:0px;

          background:#ccc;

          border-radius: 0;

          }

          /*當(dāng)動(dòng)畫結(jié)束的時(shí)候,使用動(dòng)畫將left過(guò)渡到0x,top過(guò)渡到0px,

          背景顏色過(guò)渡為紅色,圓角過(guò)渡為50%(正圓)*/

          100%{

          left:0px;

          top:0px;

          background:red;

          border-radius: 50%;

          }

          }

          這是一個(gè)比較復(fù)雜的動(dòng)畫效果,可以發(fā)現(xiàn),它通過(guò)百分比的形式將一個(gè)完整的動(dòng)畫拆分成了5個(gè)部分,每個(gè)部分都有不同的樣式效果,而當(dāng)我們采用該動(dòng)畫的元素就會(huì)按照設(shè)置的順序和樣式效果進(jìn)行動(dòng)畫的過(guò)渡和展示。

          2.上面我們只是通過(guò)@keyframes創(chuàng)建了一個(gè)動(dòng)畫,我們還需要通過(guò)特定的語(yǔ)法來(lái)使用這個(gè)動(dòng)畫。

          就是下面這句代碼了:

          animation: moveAndChange 5s linear 0.5s infinite normal;

          它是一個(gè)復(fù)合屬性,設(shè)置了6個(gè)值,分別對(duì)應(yīng):

          animation-name(設(shè)置動(dòng)畫的名稱):用來(lái)設(shè)置動(dòng)畫的名字,我們這里寫的是moveAndChange ,也就是說(shuō)我們就是要使用我們剛剛創(chuàng)建的動(dòng)畫。

          animation-duration(設(shè)置整個(gè)動(dòng)畫的時(shí)間):以秒作為單位,我們這里寫的是5s,表示整個(gè)動(dòng)畫的時(shí)間為5秒

          animation-timing-function(設(shè)置播放動(dòng)畫的方式):播放動(dòng)畫的方式,常用的有l(wèi)inear(勻速),ease(先慢后快),ease-in,ease-out,ease-in-out等,我們使用的是linear勻速播放動(dòng)畫。

          animation-delay(設(shè)置動(dòng)畫的延遲):以秒作為單位,我們寫的是0.5s,表示延遲0.5秒之后開始播放動(dòng)畫。

          animation-iteration-count(設(shè)置動(dòng)畫播放的次數(shù)):播放動(dòng)畫的次數(shù),我們這里寫的是infinite ,表示動(dòng)畫將會(huì)被播放無(wú)限次,如果寫數(shù)字,那么就會(huì)播放數(shù)字對(duì)應(yīng)的次數(shù)。

          animation-direction(設(shè)置是否反向播放動(dòng)畫):我們寫的是normal,表示正常播放動(dòng)畫,如果寫的是

          alternate則表示要反向播放動(dòng)畫,大家也可以自己試一試這個(gè)效果。

          最終,我們通過(guò)@keyframes創(chuàng)建動(dòng)畫,通過(guò)animation設(shè)置動(dòng)畫,成功完成了這個(gè)復(fù)雜的動(dòng)畫效果。

          3.轉(zhuǎn)換

          在css3中,我們通過(guò)transform屬性可以設(shè)置元素的轉(zhuǎn)換效果,具體的效果如下:

          A.平移

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body{background:pink;}div{width: 200px;height: 200px;position: absolute;background: green;left:0px;top:0px;transform: translate(300px,300px);}</style></head><body><div></div></body></html>

          代碼效果如下:

          如上圖所示,本來(lái)div盒子的位置是left:0,top:0;

          但是我們通過(guò)transform: translate(300px,300px);將盒子進(jìn)行了偏移,所以,盒子的位置發(fā)生了改變。

          B.旋轉(zhuǎn)

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: rotate(45deg);}</style></head><body><div></div></body></html>

          代碼效果如下:

          如上圖所示,本來(lái)div盒子應(yīng)該是四四方方的。

          但是,經(jīng)過(guò)我們的代碼transform: rotate(45deg); //deg為單位,表示度數(shù)。

          進(jìn)行了45度的旋轉(zhuǎn)之后,呈現(xiàn)出來(lái)的就是一個(gè)菱形的盒子了,旋轉(zhuǎn)的正方向?yàn)轫槙r(shí)針,負(fù)方向?yàn)槟鏁r(shí)針。

          C.縮放

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: scale(0.5,0.25);}</style></head><body><div></div></body></html>

          代碼效果如下:

          如上圖所示,本來(lái)盒子的寬高為200*200,而我們通過(guò)transform: scale(0.5,0.25);進(jìn)行的縮放

          scale的第一個(gè)參數(shù)為0.5,表示橫向縮小為0.5倍

          scale的第二個(gè)參數(shù)為0.25,表示縱向縮小為0.25倍。

          scale的參數(shù)如果為1,則表示不進(jìn)行任何縮放,小于1就是做縮小,而大于1表示做放大。

          小結(jié):transform轉(zhuǎn)換中其實(shí)還包含了skew(傾斜),matrix(矩陣轉(zhuǎn)換),相對(duì)來(lái)說(shuō)用到的不是特別多,所以在本文中我們便不再做介紹。

          4.flex布局

          Flex布局,可以簡(jiǎn)便、完整、響應(yīng)式地實(shí)現(xiàn)各種頁(yè)面布局。

          Flex是Flexible Box的縮寫,翻譯成中文就是“彈性盒子”,用來(lái)為盒裝模型提供最大的靈活性。任何一個(gè)容器都可以指定為Flex布局。

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: flex-start}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>

          代碼效果如下:

          如圖所示,咱們通過(guò)display:flex將.parent元素設(shè)置為了flex盒子,那么子元素將會(huì)按照justify-content設(shè)置的方式進(jìn)行元素的排列,目前看來(lái),和我們沒(méi)有設(shè)置flex盒子的效果是一致的。

          接下來(lái)我們更改一下,將justify-content設(shè)置為flex-end,效果如下圖所示:

          所以我們就應(yīng)該發(fā)現(xiàn),flex-start是讓所有的子元素從父元素的左側(cè)開始排列

          而flex-end是讓所有的子元素從元素的右側(cè)開始排列。

          我們?cè)賮?lái)更改一下,將justify-content設(shè)置為center,效果如下圖所示:

          更厲害了,子元素在父盒子的中央位置排列顯示了。

          然后,我們?cè)賹ustify-content設(shè)置為space-around,效果如下圖所示:

          它是平均分配的形式為每一個(gè)子元素設(shè)置了間距,但是看起來(lái)有點(diǎn)變扭。

          所以我們推薦將justify-content設(shè)置為space-between,效果如下圖:

          我們還可以通過(guò)flex-wrap來(lái)設(shè)置子元素是否換行顯示,以及flex-direction設(shè)置子元素排列的順序。

          這兩個(gè)屬性可以設(shè)置的值如下:

          flex-wrap: nowrap;//不換行,會(huì)自動(dòng)收縮

          flex-wrap: warp;//換行,會(huì)自動(dòng)收縮

          flex-wrap: warp-reverse;//反轉(zhuǎn),從默認(rèn)的從上到下排列反轉(zhuǎn)為從下到上。

          flex-direction:row; //從左至右一行一行進(jìn)行子元素的排列

          flex-direction:column; //從上到下一列一列進(jìn)行子元素的排列

          flex-direction:row-reverse; //從右至左一行一行進(jìn)行子元素的排列

          flex-direction:column-reverse; //從下到上一列一列進(jìn)行子元素的排列

          案例代碼如下:

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;flex-wrap: nowrap;flex-direction: row-reverse;}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div></div></body></html>

          我們?cè)O(shè)置了flex-wrap: nowrap;(不換行,壓縮所有的子元素在一行中顯示),以及flex-direction: row-reverse;(反向排列)

          代碼效果如下:

          如果設(shè)置為flex-wrap: warp(換行顯示無(wú)法在一行顯示的子元素),則效果如下:

          如果將flex-direction: column;,則會(huì)縱向排列元素,效果如下圖:

          除了上面的這些給伸縮盒子父元素設(shè)置的樣式之外,我們還可以可以伸縮盒子的子元素設(shè)置flex屬性,用來(lái)設(shè)置平均分配整個(gè)父盒子的空間。

          代碼如下:

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div{flex:1;width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>

          效果如下:

          如上圖所示,每個(gè)盒子平均分配了父盒子的空間,原本寬度為20%,現(xiàn)在被拉伸了。

          除此之外,咱們還可以使用flex屬性進(jìn)行進(jìn)一步的設(shè)置,代碼如下:

          <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div:nth-of-type(1){flex:1;border:1px solid #ccc;background:red;}.parent div:nth-of-type(2){flex:2;border:1px solid #ccc;background:green;}.parent div:nth-of-type(3){flex:2;border:1px solid #ccc;background:blue;}.parent div:nth-of-type(4){flex:1;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>

          效果如下圖:

          我們分別給四個(gè)子盒子設(shè)置了flex:1 , flex:2, flex:2 ,flex:1.

          這是什么意思呢?

          四個(gè)flex加起來(lái)一共是6.那么第一個(gè)盒子就占據(jù)整個(gè)父盒子的1/6寬度。

          同理,另外三個(gè)盒子分別占據(jù)2/6,2/6,1/6的寬度,所以就形成了我們現(xiàn)在看到的效果。

          原文來(lái)源于:黑馬程序員社區(qū)


          學(xué)習(xí)資源:

          想學(xué)習(xí)css,可以關(guān)注:黑馬程序員頭條號(hào),后臺(tái)回復(fù):css

          眨眼的工夫,很快就又到了新一年的七夕節(jié)了,正好碰到今天公司搞了一個(gè)七夕小活動(dòng)的工夫,就用JS寫了一個(gè)冒泡排序算法,順便寫了動(dòng)畫排序過(guò)程。

          其實(shí)這種算法動(dòng)畫效果網(wǎng)上有很多例子,但今天興趣使然,就抽空想自己實(shí)現(xiàn)一下。

          代碼的優(yōu)化這里就不做討論了,完全是為了實(shí)現(xiàn)自己小小的滿足感,感興趣的童鞋可以自己在電腦上做一下代碼優(yōu)化。

          下面是效果圖(部分):


          動(dòng)態(tài)渲染移動(dòng)元素


          廢話不多說(shuō),直接上代碼(大佬會(huì)做的比我更好):

          // 渲染容器
          <div id="container"></div>
          // 要排序的數(shù)組
          let arr = [27, 37, 2, 50, 10, 5, 41, 12, 41, 6, 4, 24, 47, 31, 12];
          // 每個(gè)dom元素的左邊距單位
          let posLeft = 57;
          
          // 獲取渲染容器
          const container = document.getElementById('container');
          
          /**
           * @description 動(dòng)態(tài)渲染移動(dòng)元素
           * @param { Object } elem 渲染容器
           * @param { Array } arr 數(shù)據(jù)列表
           * @return { Void }
           */
          const renderHTML = (elem, arr) => {
              let html = '',
                  className = '',
                  totalWidth = 0;
              arr.forEach((item, index) => {
                  if (item * 3 < 18) className = 'out';
                  else className = '';
                  totalWidth = index;
                  html += `<li class="item" data-index="${ index }" style="height: ${ item * 3 }px; left: ${ posLeft * index }px;">
                              <span class="${ className }">${ item }</span>
                          </li>`;
              });
              elem.innerHTML = `<ul class="list" style="width: ${ posLeft * totalWidth + 48 }px;">${ html }</ul>`;
          }
          
          renderHTML(container, arr);
          html, body {
              margin: 0;
              padding: 0;
          }
          #container,
          h1 {
              height: 100%;
              display: flex;
              justify-content: center;
              align-items: center;
          }
          h1 {
              height: auto;
              margin: 6% 0;
          }
          .list {
              position: relative;
              display: flex;
              align-items: flex-end;
              list-style: none;
              padding: 0;
              margin: 0;
              margin-top: 10%;
          }
          .item {
              width: 45px;
              margin-right: 12px;
              display: inline-flex;
              justify-content: center;
              align-items: center;
              background-color: rgb(173, 216, 230);
              font-size: 20px;
              color: #333;
              pointer-events: none;
              transition: all .3s ease;
              position: absolute;
          }
          .item:last-child {
              margin-right: 0;
          }
          .item.left,
          .item.right {
              background-color: rgb(0, 128, 0);
          }
          .item.left::before,
          .item.right::before {
              content: "";
              position: absolute;
              left: -4px;
              top: -4px;
              width: calc(100% + 4px);
              height: calc(100% + 4px);
              border: 2px solid red;
          }
          .item.left::after,
          .item.right::after {
              content: "";
              position: absolute;
              left: 50%;
              bottom: -20px;
              width: 0;
              height: 0;
              border: 10px solid transparent;
              border-bottom-color: red;
              transform: translateX(-50%);
          }
          .item.success {
              background-color: rgb(255, 165, 0);
          }
          .out {
              position: absolute;
              bottom: calc(100% + 2px);
              left: 50%;
              transform: translateX(-50%);
              color: #333;
          }

          在上面的代碼中,className = 'out'是用來(lái)判斷數(shù)字是否已超出元素內(nèi)部,如果超出,則顯示在元素外部,而非內(nèi)部。防止字體與元素顯示交叉感。

          ${ item * 3 },乘以3完全是為了元素看起來(lái)更高大一些,要不然,當(dāng)要排序的數(shù)值中包括<10的數(shù)字時(shí),元素的高度就會(huì)幾乎看不見(jiàn)。

          ${ posLeft * index },會(huì)隨著元素的渲染,left值會(huì)隨著index索引值的增大而改變。

          • 57 * 0 = 0
          • 57 * 1 = 57
          • 57 * 2 = 114
          • ...

          ${ posLeft * totalWidth + 48 },根據(jù)子元素渲染個(gè)數(shù)設(shè)置父元素的總寬度,因?yàn)樽釉夭捎昧硕ㄎ徊季郑愿冈負(fù)尾婚_,需要?jiǎng)討B(tài)設(shè)置寬度,以適配頁(yè)面的居中顯示。

          當(dāng)然不設(shè)置父元素的寬度也不影響執(zhí)行,只是會(huì)在一定程度上,列表會(huì)不方便居中在視窗的水平垂直居中位置。

          此時(shí)已經(jīng)渲染出列表了,但是沒(méi)有執(zhí)行排序算法,下面添加排序算法。



          冒泡排序算法


          const bubbleSort = arr => {
              const len = arr.length;
              for (let i = 0; i < len; i ++) {
                  for (let j = i + 1; j < len; j ++) {
                      if (arr[i] > arr[j]) {
                          [arr[i], arr[j]] = [arr[j], arr[i]];
                      }
                  }
              }
              return arr;
          }
          
          // 原數(shù)組:[27, 37, 2, 50, 10, 5, 41, 12, 41, 6, 4, 24, 47, 31, 12]
          bubbleSort(arr);

          冒泡排序算法有很多種方法,這里只介紹了一種,就是:套用兩層循環(huán),一個(gè)一個(gè)對(duì)比,如果找到符合的元素,就通過(guò)[arr[i], arr[j]] = [arr[j], arr[i]]數(shù)組解構(gòu)的方式,調(diào)換兩個(gè)元素的位置。

          也許這樣表達(dá)大家有些難以理解,當(dāng)然高手飄過(guò)哈。其實(shí)我也當(dāng)初不理解,不過(guò)通過(guò)自己摸索再結(jié)合動(dòng)畫的形式來(lái)看,對(duì)理解算法的過(guò)程會(huì)更加明確。

          結(jié)果是已經(jīng)排好了,但是還不能讓它們動(dòng)起來(lái),想要?jiǎng)悠饋?lái),繼續(xù)和我一步一步做下去。



          讓元素動(dòng)起來(lái)


          想要讓元素動(dòng)起來(lái)前,我們需要有兩個(gè)標(biāo)識(shí),一個(gè)左一個(gè)右。

          左稱為:.item.left 左邊界元素。右稱為:.item.right 右邊界元素。我在這里用了這兩個(gè)元素,完全是為了在執(zhí)行動(dòng)畫的時(shí)候方便區(qū)分理解。

          代表:左邊界元素需要每次和右邊界元素去對(duì)比,如果有小于左元素的,則進(jìn)行調(diào)換,否則不動(dòng)。

          比如這樣:

          動(dòng)的一直是右邊界,而非左邊界,左邊界在這里只是充當(dāng)一個(gè)基點(diǎn)的角色,用來(lái)和其它元素進(jìn)行對(duì)比。

          改造一下:

          const list = document.getElementsByClassName('list')[0];
          // 這里需要擴(kuò)展字符串把元素列表擴(kuò)展成真正的dom數(shù)組,否則不能進(jìn)行下面的filter語(yǔ)法
          const items = [...document.getElementsByClassName('item')];
          
          const setPos = (left, right) => {
              // 獲取左、右邊界元素
              let eleLeft = items.filter(item => item.getAttribute('data-index') == left);
              let eleRight = items.filter(item => item.getAttribute('data-index') == right);
          
              let leftInfo = {
                  pos: eleLeft[0].offsetLeft,
                  index: eleLeft[0].getAttribute('data-index')
              };
              let rightInfo = {
                  pos: eleRight[0].offsetLeft,
                  index: eleRight[0].getAttribute('data-index')
              };
          
              // 設(shè)置左、右邊界元素的距離與高亮
              // 因?yàn)橐Q位置,所以class類名要互相調(diào)換
              eleLeft[0].style.left = rightInfo.pos + 'px';
              eleLeft[0].className = 'item right';
              eleRight[0].style.left = leftInfo.pos + 'px';
              eleRight[0].className = 'item left';
          }
          
          // 小于左邊界索引的元素,全部設(shè)置成高亮,代表已經(jīng)排序完成的元素
          const setSuccess = (arr, index) => {
              for (let i = 0, len = arr.length; i < len; i ++) {
                  if (i < index) arr[i].className = 'item success';
              }
          }
          
          // type未傳值,或,className包含right時(shí),清空所有高亮
          const clearClass = type => {
              for (let i = 0, len = items.length; i < len; i ++) {
                  if (!type || items[i].className.includes(type)) {
                      items[i].className = 'item';
                      break;
                  }
              }
          }
          
          const bubbleSort = arr => {
              const len = arr.length;
              for (let i = 0; i < len; i ++) {
                  // 重新獲取列表元素
                  const items = document.getElementsByClassName('item');
                  // 清空樣式
                  clearClass();
                  // 設(shè)置完成排序的高亮元素
                  setSuccess(items, i);
                  items[i].className = 'item left';
                  if (!items[i + 1]) {
                      // 如果后面已經(jīng)沒(méi)有元素了,則停止排序,完成操作,高亮最后一個(gè)元素
                      setSuccess(items, i + 1);
                      break;
                  }
                  // 依次用左邊界元素對(duì)比右界所有元素
                  for (let j = i + 1; j < len; j ++) {
                      // 只清空包含右邊界元素的高亮
                      clearClass('right');
                      items[j].className = 'item right';
                      // 如果左邊界比右邊界大
                      if (arr[i] > arr[j]) {
                          // 則調(diào)換兩個(gè)元素的位置
                          setPos(i, j);
                          // 調(diào)換數(shù)組中兩個(gè)值的位置
                          [arr[i], arr[j]] = [arr[j], arr[i]];
                      }
                  }
              }
          }

          此時(shí)刷新頁(yè)面,好吧,我傻眼了。。。都亂了。

          因?yàn)槲以谏厦娴?/span>CSS中加了300毫秒的元素動(dòng)畫時(shí)間transition: all .3s ease

          但是循環(huán)太快了,還來(lái)不及做動(dòng)畫,元素在運(yùn)動(dòng)的過(guò)程中又再次執(zhí)行下次渲染,就造成了這種無(wú)腦局面。。。

          想要解決這個(gè)問(wèn)題,需要有一種可以讓循環(huán)慢下來(lái)的辦法才行,下面我們可以這樣做,想讓它多慢,就有多慢。

          const sleep = time => {
              return new Promise(resolve => setTimeout(resolve, time));
          }
          
          const bubbleSort = async arr => {
              const len = arr.length;
              for (let i = 0; i < len; i ++) {
                  // 重新獲取列表元素
                  const items = document.getElementsByClassName('item');
                  // 清空樣式
                  clearClass();
                  // 設(shè)置完成排序的高亮元素
                  setSuccess(items, i);
                  items[i].className = 'item left';
                  // 隔600毫秒后再執(zhí)行后續(xù)操作
                  await sleep(600);
                  if (!items[i + 1]) {
                      // 如果后面已經(jīng)沒(méi)有元素了,則停止排序,完成操作,高亮最后一個(gè)元素
                      setSuccess(items, i + 1);
                      break;
                  }
                  // 依次用左邊界元素對(duì)比右界所有元素
                  for (let j = i + 1; j < len; j ++) {
                      // 只清空包含右邊界元素的高亮
                      clearClass('right');
                      items[j].className = 'item right';
                      // 隔600毫秒
                      await sleep(600);
                      // 如果左邊界比右邊界大
                      if (arr[i] > arr[j]) {
                          // 則調(diào)換兩個(gè)元素的位置
                          setPos(i, j);
                          // 調(diào)換數(shù)組中兩個(gè)值的位置
                          [arr[i], arr[j]] = [arr[j], arr[i]];
                          // 保證移動(dòng)動(dòng)畫執(zhí)行完成后,再次進(jìn)行下一輪比較
                          await sleep(800);
                      }
                  }
              }
          }

          我們可以使用asyncpromise語(yǔ)法搭配來(lái)模擬異步操作過(guò)程,在上面的例子中,循環(huán)的過(guò)程必須要等到sleep方法有返回值后,才可以進(jìn)行后面的循環(huán),采用傳入的時(shí)間參數(shù)毫秒,來(lái)生成一個(gè)設(shè)置在時(shí)間范圍內(nèi)的定時(shí)器,直至等待返回。

          這是怎么回事,雖然在有條理的做著動(dòng)畫,但是明顯不對(duì)吧。都亂套了。。。

          const setPos = (left, right) => {
              // ...
              // 需要加個(gè)延遲,等動(dòng)畫特效執(zhí)行完成后,再去設(shè)置調(diào)換元素的索引值與實(shí)際位置
              setTimeout(() => {
                  // 因?yàn)榇藭r(shí)元素的位置已經(jīng)改變,所以需要重新獲取元素列表
                  const items = document.getElementsByClassName('item');
                  // 設(shè)置左邊界元素的索引值為右邊界元素的索引值
                  eleLeft[0].setAttribute('data-index', rightInfo.index);
                  // 把左邊界元素插入到右邊界元素的下一個(gè)兄弟元素的前面
                  list.insertBefore(eleLeft[0], items[right].nextElementSibling);
                  // 設(shè)置右邊界元素的索引值為左邊界元素的索引值
                  eleRight[0].setAttribute('data-index', leftInfo.index);
                  // 把右邊界元素插入到左邊界元素的前面
                  list.insertBefore(eleRight[0], items[left]);
              }, 400);
          }

          那是因?yàn)檫\(yùn)動(dòng)元素動(dòng)畫完成后,只是視圖上更新而已,視覺(jué)上看確實(shí)變了,但變的是元素的left值,而非真實(shí)的dom列表位置。

          所以我們需要在每次調(diào)換元素位置后,需要重新獲取一下dom列表,因?yàn)榇藭r(shí)的元素位置已經(jīng)發(fā)生變化,需要重新更新此列表。

          然后再設(shè)置一下調(diào)換元素的索引值,保證新設(shè)置的索引和調(diào)換后的索引是一一對(duì)應(yīng)的。

          最后需要list.insertBefore(eleLeft[0], items[right].nextElementSibling);,把左邊界元素,插入到右邊界下一個(gè)兄弟元素的前面。

          if (!items[i + 1]) {
              // 如果后面已經(jīng)沒(méi)有元素了,則停止排序,完成操作,高亮最后一個(gè)元素
              setSuccess(items, i + 1);
              break;
          }

          在循環(huán)的時(shí)候,我這里做了判斷后面是否還有其它元素。

          如果沒(méi)有,則不會(huì)執(zhí)行調(diào)換元素的函數(shù),否則當(dāng)循環(huán)到最后一個(gè)元素,后面再?zèng)]有元素的時(shí)候,執(zhí)行items[right].nextElementSibling會(huì)報(bào)錯(cuò)。

          list.insertBefore(eleRight[0], items[left]);,把右邊界元素插入到左邊界元素的前面。

          這樣再看的話,是不是就沒(méi)有問(wèn)題啦!

          其實(shí)這個(gè)demo其實(shí)哪有完美的,如果追求完美,需要優(yōu)化的地方還有很多,比如:代碼復(fù)用性代碼不簡(jiǎn)潔命名是否規(guī)范兼容性是否可行等等。

          感興趣的小伙伴可以自己去試試做下優(yōu)化,我相信你們肯定比我強(qiáng)。



          最后


          感謝您抽出寶貴的時(shí)間閱讀本文,希望對(duì)您有所幫助。

          如果您遇到什么疑問(wèn)或者建議,歡迎多多交流,大家共同進(jìn)步。

          在閱讀過(guò)程中,如果有不正確的地方,希望您能提出來(lái),我會(huì)努力改正并提供更優(yōu)質(zhì)的文章。


          主站蜘蛛池模板: 国产一区二区三区在线电影| 无码人妻精品一区二区三区久久久| 日韩精品无码一区二区三区| 亚洲熟女www一区二区三区| 波多野结衣中文字幕一区 | 国产一区二区免费视频| 一区二区不卡在线| 久久精品亚洲一区二区| 国产精品免费大片一区二区| 国产在线无码视频一区| 2022年亚洲午夜一区二区福利 | 日本精品一区二区三区视频| 一区二区三区精品| 99精品高清视频一区二区| 精品国产亚洲一区二区三区在线观看 | 国模吧一区二区三区精品视频| 亚洲AV色香蕉一区二区| 国产精品毛片一区二区| 欲色影视天天一区二区三区色香欲 | 中文字幕一精品亚洲无线一区| 在线精品自拍亚洲第一区| 精品香蕉一区二区三区| 伊人久久一区二区三区无码| 亚洲AV美女一区二区三区| 国产一区二区三区在线看| 成人免费一区二区三区| 亚洲AⅤ无码一区二区三区在线| 无码国产精品一区二区高潮| 女人18毛片a级毛片一区二区| 日韩中文字幕精品免费一区| 人妖在线精品一区二区三区| 日韩av无码一区二区三区| 日韩AV无码久久一区二区| 免费无码一区二区三区| 久久久久人妻一区二区三区| 亚洲狠狠久久综合一区77777 | 亚洲AV无码一区二区三区性色| 国产精品高清一区二区人妖| 中文字幕日韩丝袜一区| 99国产精品欧美一区二区三区| 国产精品久久久久久一区二区三区 |