整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          「實戰」蘑菇街 PC 端首頁,瀑布流布局的實現原理與

          「實戰」蘑菇街 PC 端首頁,瀑布流布局的實現原理與細節技巧

          菇街PC首頁瀑布流實踐

          作者:蘑菇街前端團隊

          鏈接:https://juejin.im/post/5e05acf0f265da33d158a1b1


          零、介紹

          這篇文章主要是介紹網站頁面瀑布流布局的實現,主要包括:

          1. 瀑布流是什么
          2. 瀑布流的實現原理
          3. 瀑布流的使用場景
          4. 實現中有哪些問題 & 如何解決
          5. 可擴展的使用場景

          一、瀑布流是什么

          瀑布流, 又稱瀑布流式布局,是比較流行的一種網站頁面布局。視覺表現為寬度相等高度不定的元素組成的參差不齊的多欄布局,隨著頁面向下滾動,新的元素附加到最短的一列而不斷向下加載。

          二、瀑布流的實現原理

          瀑布流本質上就是尋找各列之中高度最小的一列,并將新的元素添加到該列后面,只要有新的元素需要排列,就繼續尋找所有列中的高度最小列,把后來的元素添加到高度最小列上。

          圖解基礎瀑布流

          我們接下來看下為什么要永遠尋找最小列?

          先看圖1的排列順序,第一排元素的頂部會處于同一個高度,依次排列在頂端,第一排排滿之后,第二排從左往右排列。然而這種排列方式很容易出現其中一列過長或其中一列過短的情況。

          為了解決 圖1 中列可能過長或者過短的問題,我們按照 圖2 的方式將元素放在最短的一列進行排列。

          三、瀑布流的使用場景

          瀑布流滑動的時候會不停的出現新的東西,吸引你不斷向下探索,巧妙的利用視覺層級、視線的任意流動來緩解視覺的疲勞,采用這種方案可以延長用戶停留視覺,提高用戶粘度,適合那些隨意瀏覽,不帶目的性的使用場景,就像逛街一樣,邊走邊看,所以比較適合圖片、商品、資訊類的場景,很多電商相關的網站都使用了瀑布流進行承載。

          上圖的蘑菇街 PC 瀑布流效果是在基礎瀑布流的基礎上做了擴展改造, 在瀑布流頂部某一列或某幾列插入其他非瀑布流內容。

          本文將介紹這種擴展瀑布流的四列實現場景,適用基礎場景如下:

          四、瀑布流的的實現有哪些問題&如何解決

          1. 非瀑布流內容如何插入?
          2. 如何尋找所有列的高度最小者?
          3. 如何渲染瀑布流?

          Vue 實現瀑布流

          我們采用 Vue 框架來實現瀑布流,其一些自帶屬性使我們的瀑布流實現更加簡單。

          • 通過 ref 可以很方便的獲取每列高度,通過比較算法算出高度最小列。
          • 拿到高度最小列之后,將下個要插入的元素數據放到最小列的數據列表(columnList)中,通過操作數據完成元素渲染。
          • 利用 Vue 的具名插槽在瀑布流頂部插入其他非瀑布內容。
          • 通過 watch 監測元素渲染,判斷是否繼續進行渲染和請求更多元素數據。

          非瀑布流內容如何插入

          通過 Vue 的具名插槽(slot),將非瀑布流元素作為父組件的內容傳遞給瀑布流子組件。

          • 父組件通過 HTML 模板上的槽屬性關聯具名插槽,非瀑布流內容作為具名插槽的內容提供給子組件。
          • 具名插槽有:first-col、second-col、 third-col、 last-col、 merge-slot,分別代表第一、二、三、四、合并列。
          • 子組件通過插槽名字判斷將非瀑布流內容放在哪一列。如果插槽存在,則將其所攜帶的內容插入到置頂位置。
          • 因為合并列的特殊性,如果包含合并列,則將合并列絕對定位到頂部,合并列占的瀑布流對應的列進行下移。父組件傳合并列相關的參數給子組件:merge(判斷是否包含合并列), mergeHeight(合并列的高度),mergeColunms(合并的是哪 2 列)。

          代碼實現

          <!-- 父組件 -->
          <div class="parent">
              <Waterfall :merge=true :mergeHeight=800 mergeColumns=[2,3]>
                  <template slot="first-col">
                      <!-- 第一列內容...      -->
                  </template>
                  <template slot="second-col">
                      <!-- 第二列內容...     -->
                  </template>
                  <template slot="third-col">
                      <!-- 第三列內容...      -->
                  </template>
                  <template slot="last-col">
                      <!-- 第四列內容...      -->
                  </template>
                  <template slot="merge-col">
                      <!-- 合并內容...     -->
                  </template>
              </Waterfall>
          </div>
          <!-- 子組件(waterfall) -->
          <div class="child">
              <!-- 第一列 -->
              <div ref="column1" :style="{marginTop: merge && mergeColumns.indexOf(1) > -1 ? mergeHeight + 'px':''}">
                  <template v-if="$slots['first-col']">
                      <slot name="first-col"></slot>
                  </template>
                  <template v-for="(item, index) in columnList1">
                      <!-- 第一列瀑布流內容... -->
                  </template>
              </div>
              <!-- 第二列 -->
              <div ref="column2" :style="{marginTop: merge && mergeColumns.indexOf(2) > -1 ? mergeHeight + 'px':''}">
                  <template v-if="$slots['second-col']">
                      <slot name="second-col"></slot>
                  </template>
                  <template v-for="(item, index) in columnList2">
                      <!-- 第二列瀑布流內容... -->
                  </template>
              </div>
              <!-- 第三列 -->
              <div ref="column3" :style="{marginTop: merge && mergeColumns.indexOf(3) > -1 ? mergeHeight + 'px':''}">
                  <template v-if="$slots['third-col']">
                      <slot name="third-col"></slot>
                  </template>
                  <template v-for="(item, index) in columnList3">
                      <!-- 第三列瀑布流內容... -->
                  </template>
              </div>
              <!-- 第四列 -->
              <div ref="column4" v-if="is4Columns">
                  <template v-if="$slots['last-col']">
                      <slot name="last-col"></slot>
                  </template>
                  <template v-for="(item, index) in columnList4">
                      <!-- 第四列瀑布流內容... -->
                  </template>
              </div>
              <!-- 合并塊非瀑布流內容 -->
              <div class="column-merge" v-if="merge" :style="{left: (mergeColumns[0] - 1)*330 + 'px'}">
                  <slot name="merge-col"></slot>
              </div>
          </div>

          如何尋找所有列的高度最小者

          每一列都定義一個 ref,通過 ref 獲取當前列的高度,如果該列上方有合并塊,則高度要加上合并塊的高度,然后比較 4 列高度取到最小高度,再通過最小高度算出其對應的列數。

          代碼實現

          // 通過ref獲取每列高度,column1,column2,column3,column4分別代表第一、二、三、四列
          let columsHeight=[this.$refs.column1.offsetHeight, this.$refs.column2.offsetHeight, this.$refs.column3.offsetHeight, this.$refs.column4.offsetHeight]
          
          // 如果包含合并塊, 則更新高度,合并塊下的列高要增加合并塊的高度
          if(this.merge){
              // 如果有合并列,則合并列下的列高度要加合并內容的高度。
              columsHeight[0]=this.mergeColumns.indexOf(1) > -1 ? columsHeight[0] + this.mergeHeight : columsHeight[0];
              columsHeight[1]=this.mergeColumns.indexOf(2) > -1 ? columsHeight[1] + this.mergeHeight : columsHeight[1];
              columsHeight[2]=this.mergeColumns.indexOf(3) > -1 ? columsHeight[2] + this.mergeHeight : columsHeight[2];
          		columsHeight[3]=this.mergeColumns.indexOf(4) > -1 ? columsHeight[3] + this.mergeHeight : columsHeight[3];
          }
          
          // 獲取各列最小高度
          let minHeight=Math.min.apply(null, columsHeight);
          
          // 通過最小高度,得到第幾列高度最小
          this.getMinhIndex(columsHeight, minHeight).then(minIndex=> {
          	 // 渲染加載邏輯
          });
          
          // 獲取高度最小索引函數
          getMinhIndex(arr, value){
              return new Promise((reslove)=> {
                  let minIndex=0;
                  for(let i in arr){
                      if(arr[i]==value){
                          minIndex=i;
                          reslove(minIndex);
                      }
                  }
              });
          }

          如何渲染瀑布流

          瀑布流常用在無限下拉加載或者加載數據量很大、且包含很多圖片元素的情景,所以通常不會一次性拿到所有數據,也不會一次性將拿到的數據全部渲染到頁面上,否則容易造成頁面卡頓影響用戶體驗,所以何時進行渲染、何時繼續請求數據就很關鍵。

          何時渲染

          選擇渲染的區域為滾動高度 + 可視區域高度的 1.5 倍,既可以防止用戶滾動到底部的時候白屏,也可以防止渲染過多影響用戶體驗。如果 最小列的高度 - 滾動高度 < 可視區域高 * 1.5 ,則繼續渲染元素,否則不再繼續渲染。

          何時請求數據

          當已渲染的元素+可視區域可以展示的預估元素個數 > 已請求到的個數 的時候才去繼續請求更多數據,防止請求浪費。 如果 已加載的元素個數 + 一屏可以展示的元素預估個數 > 所有請求拿到的元素個數 ,則觸發下一次請求去獲取更多數據。

          瀑布流渲染核心思路

          • 監測滾動,判斷是否符合渲染條件,如果符合條件則開始渲染。
          • 定義一個渲染索引 renderIndex,每渲染一個元素后 renderIndex + 1, 實時監測 renderIndex 的變化, 判斷是否符合渲染和數據請求條件。
          • 拿到最小高度列索引后,將下一個元素插入到該列中,并觸發 renderIndex + 1 進行下一輪渲染判斷。

          代碼實現

          data() {
              return {
                  columnList1: [], // 第一列元素列表
                  columnList2: [],
                  columnList3: [],
                  columnList4: [],
                  renderIndex: -1, // 渲染第幾個item
                  isRendering: false, // 是否正在渲染
                  itemList: [], // 所有元素列表
                  isEnd: false
              };
          }
          
          watch: {
              renderIndex(value) {
          
                  // 當前滾動條高度
                  const scrollTop=document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
          
                  // 最小列高度 - 滾動高度 < 可視區域高的的1.5倍
                  if (renderMinTop - scrollTop < winHeight * 1.5) {
                      this.renderWaterfall();
                  }
          
                  // 已加載的元素個數 + 一屏可以展示元素預估個數 > 所有請求拿到的元素個數
                  if (loadedItemNum + canShowItemNum > this.itemList.length && !this._requesting && !this.isEnd) {
                      // 請求瀑布流數據
                      this.getData();
                  }
              }
          }
          
          scroll() {
          
              // 當前滾動條高度
              const scrollTop=document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
          
              // 底部檢測高度
              const bottomDetectionTop=this.$refs.bottomDetection.offsetTop;
          
              const tempLastScrollTop=lastScrollTop; // lastScrollTop:上次一滾動高度
              lastScrollTop=scrollTop;
          
              if (tempLastScrollTop===-1) {
                  this.renderWaterfall();
              }
          
              // 如果是向下滾動則判斷是否需要繼續渲染
              if (scrollTop > tempLastScrollTop) {
                  if (bottomDetectionTop - tempLastScrollTop < winHeight * 1.5 && !this.isRendering) {
                      this.renderWaterfall();
                  }
              }
          
          }
          
          renderWaterfall() {
          
              // 如果還沒有數據、所有數據已經渲染完成、正在渲染則不進行渲染計算操作
              if (this.itemList.length===0 || this.renderIndex >=this.itemList.length - 1 || this.isRendering) {
                  if (this.renderIndex===this.feedList.length - 1 && !this._requesting && !this.isEnd) {
                      this.getData();
                  }
                  return;
              }
              this.isRendering=true;
          
              /***
              *** 獲取最小高度代碼
              ***/
          
              this.getMinhIndex(columnsHeight, minHeight).then(minIndex=> {
          
                  const key=`columnList${minIndex + 1}`;
                  let itemData=this.itemList[this.renderIndex + 1];
                  this[key]=this[key].concat(itemData);
                  this.$nextTick(()=> {
                      this.renderIndex=this.renderIndex + 1;
                      this.isRendering=false;
                  });
              });
          }

          五、可擴展的使用場景

          為了靈活使用瀑布流,在設計的時候就做好了擴展準備,通過 HTML 模板代碼可以看出來,具名插槽的內容可以放在任意列,并沒有限制死,所以可以擴展使用到以下各個場景。

          關注我

          大家好,這里是 FEHub,每天早上 9 點更新,為你分享優質精選文章,與你一起進步。

          如果喜歡這篇文章,希望大家點贊,評論,轉發。你的支持,是我最大的動力,咱們明天見 :)

          關注公眾號 「FEHub」,每天進步一點點

          周末福利

          感謝大家的支持,周末領紅包,加雞腿。

          公眾號后臺回復關鍵字:「雞腿」,即可參與紅包抽獎。

          者 | 木易揚

          責編 | 伍杏玲

          本人是去年 7-8月開始準備面試,過五關斬六將,最終在年末抱得網易歸,深深感受到高級前端面試的套路。以下是自己整理的面試題匯總,不敢藏私,統統貢獻出來。

          面試的公司分別是:阿里、網易、滴滴、、有贊、挖財、滬江、餓了么、攜程、喜馬拉雅、兌吧、微醫、寺庫、寶寶樹、海康威視、蘑菇街、酷家樂、百分點和海風教育。

          以下是面試題匯總,后續階段會持續深入更新面試題解,共勉!

          阿里

          • 使用過的Koa2中間件
          • Koa-body原理
          • 介紹自己寫過的中間件
          • 有沒有涉及到Cluster
          • 介紹Pm2
          • Master掛了的話Pm2怎么處理
          • 如何和MySQL進行通信
          • React聲明周期及自己的理解
          • 如何配置React-Router
          • 路由的動態加載模塊
          • 服務端渲染SSR
          • 介紹路由的History
          • 介紹Redux數據流的流程
          • Redux如何實現多個組件之間的通信,多個組件使用相同狀態如何進行管理
          • 多個組件之間如何拆分各自的State,每塊小的組件有自己的狀態,它們之間還有一些公共的狀態需要維護,如何思考這塊
          • 使用過的Redux中間件
          • 如何解決跨域的問題
          • 常見Http請求頭
          • 移動端適配1px的問題
          • 介紹Flex布局
          • 其他CSS方式設置垂直居中
          • 居中為什么要使用Transform(為什么不使用MarginLeft/Top)
          • 使用過Webpack里面哪些Plugin和Loader
          • Webpack里面的插件是怎么實現的
          • Dev-Server是怎么跑起來
          • 項目優化
          • 抽取公共文件是怎么配置的
          • 項目中如何處理安全問題
          • 怎么實現this對象的深拷貝

          網易

          • 介紹Redux,主要解決什么問題
          • 文件上傳如何做斷點續傳
          • 表單可以跨域嗎
          • Promise、Async有什么區別
          • 搜索請求如何處理(防抖)
          • 搜索請求中文如何請求
          • 介紹觀察者模式
          • 介紹中介者模式
          • 觀察者和訂閱-發布的區別,各自用在哪里
          • 介紹React優化
          • 介紹Http2.0
          • 通過什么做到并發請求
          • Hhttp1.1時如何復用Tcp連接
          • 介紹Service Worker
          • 介紹CSS3中Position:sticky
          • Redux請求中間件如何處理并發
          • 介紹Promise,異常捕獲
          • 介紹position屬性包括CSS3新增
          • 瀏覽器事件流向
          • 介紹事件代理以及優缺點
          • React組件中怎么做事件代理
          • React組件事件代理的原理
          • 介紹This各種情況
          • 前端怎么控制管理路由
          • 使用路由時出現問題如何解決
          • React怎么做數據的檢查和變化

          滴滴

          • React-Router怎么實現路由切換
          • React-Router里的<Link>標簽和<a>標簽有什么區別
          • <a>標簽默認事件禁掉之后做了什么才實現了跳轉
          • React層面的性能優化
          • 整個前端性能提升大致分幾類
          • import { Button } from 'antd',打包的時候只打包button,分模塊加載,是怎么做到的
          • 使用import時,Webpack對node_modules里的依賴會做什么
          • JS異步解決方案的發展歷程以及優缺點
          • Http報文的請求會有幾個部分
          • Cookie放哪里,Cookie能做的事情和存在的價值
          • Cookie和Token都存放在Header里面,為什么只劫持前者
          • Cookie和Session有哪些方面的區別
          • React中Dom結構發生變化后內部經歷了哪些變化
          • React掛載的時候有3個組件,TextComponent、ComposeComponent、DomComponent,區別和關系,Dom結構發生變化時怎么區分Data的變化,怎么更新,更新怎么調度,如果更新的時候還有其他任務存在怎么處理
          • Key主要是解決哪一類的問題,為什么不建議用索引index(重繪)
          • Redux中異步的請求怎么處理
          • Redux中間件是什么東西,接受幾個參數(兩端的柯里化函數)
          • 柯里化函數兩端的參數具體是什么東西
          • 中間件是怎么拿到Store和Action,然后怎么處理
          • State是怎么注入到組件的,從Reducer到組件經歷了什么樣的過程
          • Koa中response.send、Response.rounded、Response.json發生了什么事,瀏覽器為什么能識別到它是一個json結構或是html
          • Koa-bodyparser怎么來解析Request
          • Webpack整個生命周期,Loader和Plugin有什么區別
          • 介紹AST(Abstract Syntax Tree)抽象語法樹
          • 安卓Activity之間數據是怎么傳遞的
          • 安卓4.0到6.0過程中WebView對JS兼容性的變化
          • WebView和原生是如何通信
          • 跨域怎么解決,有沒有使用過Apache等方案

          • 對Async、Await的理解,內部原理
          • 介紹下Promise,內部實現
          • 清除浮動
          • 定位問題(絕對定位、相對定位等)
          • 從輸入URL到頁面加載全過程
          • TCP3次握手
          • TCP屬于哪一層(1 物理層 -> 2 數據鏈路層 -> 3 網絡層(IP)-> 4 傳輸層(TCP) -> 5 應用層(Http))
          • Redux的設計思想
          • 接入Redux的過程
          • 綁定Cconnect的過程
          • Cconnect原理
          • Webpack介紹
          • ==和===的區別,什么情況下用相等==
          • Bind、Call、Apply的區別
          • 動畫的了解
          • 介紹下原型鏈(解決的是繼承問題嗎)
          • 對跨域的了解

          有贊

          • Linux 754 介紹
          • 介紹冒泡排序,選擇排序,冒泡排序如何優化
          • Transform動畫和直接使用Left、Top改變位置有什么優缺點
          • 如何判斷鏈表是否有環
          • 介紹二叉搜索樹的特點
          • 介紹暫時性死區
          • ES6中的Map和原生的對象有什么區別
          • 觀察者和發布-訂閱的區別
          • React異步渲染的概念,介紹Time Slicing 和 Suspense
          • 16.X聲明周期的改變
          • 16.X中Props改變后在哪個生命周期中處理
          • 介紹純函數
          • 前端性能優化
          • PureComponent和FunctionComponent區別
          • 介紹JSX
          • 如何做RN在安卓和iOS端的適配
          • RN為什么能在原生中繪制成原生組件(bundle.js)
          • 介紹虛擬DOM
          • 如何設計一個localStorage,保證數據的實效性
          • 如何設計Promise.all()
          • 介紹高階組件
          • sum(2, 3)實現sum(2)(3)的效果
          • react性能優化
          • 兩個對象如何比較

          挖財

          • JS的原型
          • 變量作用域鏈
          • call、apply、bind的區別
          • 防抖和節流的區別
          • 介紹各種異步方案
          • React生命周期
          • 介紹Fiber
          • 前端性能優化
          • 介紹DOM樹對比
          • React中的key的作用
          • 如何設計狀態樹
          • 介紹CSS,Xsrf
          • Http緩存控制
          • 項目中如何應用數據結構
          • Native提供了什么能力給RN
          • 如何做工程上的優化
          • shouldComponentUpdate是為了解決什么問題
          • 如何解決Props層級過深的問題
          • 前端怎么做單元測試
          • Webpack生命周期
          • Webpack打包的整個過程
          • 常用的Plugins
          • Pm2怎么做進程管理,進程掛掉怎么處理
          • 不用Pm2怎么做進程管理

          滬江

          • 介紹下瀏覽器跨域
          • 怎么去解決跨域問題
          • Jsonp方案需要服務端怎么配合
          • Ajax發生跨域要設置什么(前端)
          • 加上CORS之后從發起到請求正式成功的過程
          • Xsrf跨域攻擊的安全性問題怎么防范
          • 使用Async會注意哪些東西
          • Async里面有多個await請求,可以怎么優化(請求是否有依賴)
          • Promise和Async處理失敗的時候有什么區別
          • Redux在狀態管理方面解決了React本身不能解決的問題
          • Redux有沒有做過封裝
          • React生命周期,常用的生命周期
          • 對應的生命周期做什么事
          • 遇到性能問題一般在哪個生命周期里解決
          • 怎么做性能優化(異步加載組件)
          • 寫React有哪些細節可以優化
          • React的事件機制(綁定一個事件到一個組件上)
          • 介紹下事件代理,主要解決什么問題
          • 前端開發中用到哪些設計模式
          • React/Redux中哪些功能用到了哪些設計模式
          • JS變量類型分為幾種,區別是什么
          • JS里垃圾回收機制是什么,常用的是哪種,怎么處理的
          • 一般怎么組織CSS(Webpack)

          餓了么

          • 小程序里面開頁面最多是多少
          • React子父組件之間如何傳值
          • Emit事件怎么發,需要引入什么
          • 介紹下React高階組件,和普通組件有什么區別
          • 一個對象數組,每個子對象包含一個ID和Name,React如何渲染出全部的Name
          • 在哪個生命周期里寫
          • 其中有幾個Name不存在,通過異步接口獲取,如何做
          • 渲染的時候Key給什么值,可以使用Index嗎?用ID好還是Index好
          • Webpack如何配Sass,需要配哪些Loader
          • 配CSS需要哪些Loader
          • 如何配置把JS、CSS、Html單獨打包成一個文件
          • Div垂直水平居中(Flex、絕對定位)
          • 兩個元素塊,一左一右,中間相距10像素
          • 上下固定,中間滾動布局如何實現
          • [1, 2, 3, 4, 5]變成[1, 2, 3, a, b, 5]
          • 取數組的最大值(ES5、ES6)
          • apply和call的區別
          • ES5和ES6有什么區別
          • some、every、find、filter、map、forEach有什么區別
          • 上述數組隨機取數,每次返回的值都不一樣
          • 如何找0-5的隨機數,95-99呢
          • 頁面上有1萬個Button如何綁定事件
          • 如何判斷是Button
          • 頁面上生成一萬個Button,并且綁定事件,如何做(JS原生操作DOM)
          • 循環綁定時的Index是多少,為什么,怎么解決
          • 頁面上有一個input,還有一個p標簽,改變input后p標簽就跟著變化,如何處理
          • 監聽input的哪個事件,在什么時候觸發

          攜程

          • 對React看法,有沒有遇到一些坑
          • 對閉包的看法,為什么要用閉包
          • 手寫數組去重函數
          • 手寫數組扁平化函數
          • 介紹下Promise的用途和性質
          • Promise和Callback有什么區別
          • React生命周期
          • 兩道手寫算法題

          喜馬拉雅

          • ES6新的特性
          • 介紹Promise
          • Promise有幾個狀態
          • 說一下閉包
          • React的生命周期
          • ComponentWillReceiveProps的觸發條件是什么
          • React16.3對生命周期的改變
          • 介紹下React的Filber架構
          • 畫Filber渲染樹
          • 介紹React高階組件
          • 父子組件之間如何通信
          • Redux怎么實現屬性傳遞,介紹下原理
          • React-Router版本號
          • 網站SEO怎么處理
          • 介紹下HTTP狀態碼
          • 403、301、302是什么
          • 緩存相關的HTTP請求頭
          • 介紹HTTPS
          • HTTPS怎么建立安全通道
          • 前端性能優化(JS原生和React)
          • 用戶體驗做過什么優化
          • 對PWA有什么了解
          • 對安全有什么了解
          • 介紹下數字簽名的原理
          • 前后端通信使用什么方案
          • RESTful常用的Method
          • 介紹下跨域
          • Access-Control-Allow-Origin在服務端哪里配置
          • csrf跨站攻擊怎么解決
          • 前端和后端怎么聯調

          兌吧

          • LocalStorage和Cookie有什么區別
          • CSS選擇器有哪些
          • 盒子模型,以及標準情況和IE下的區別
          • 如何實現高度自適應
          • Prototype和Proto區別
          • _construct是什么
          • new是怎么實現的
          • promise的精髓,以及優缺點
          • 如何實現H5手機端的適配
          • Rrem、Flex的區別(Root em)
          • em和px的區別
          • React聲明周期
          • 如何去除url中的#號
          • Redux狀態管理器和變量掛載到Window中有什么區別
          • Webpack和Gulp的優缺點
          • 如何實現異步加載
          • 如何實現分模塊打包(多入口)
          • 前端性能優化(1JS、CSS;2 圖片;3 緩存預加載; 4 SSR; 5 多域名加載;6 負載均衡)
          • 并發請求資源數上限(6個)
          • base64為什么能提升性能,缺點
          • 介紹Webp這個圖片文件格式
          • 介紹Koa2
          • Promise如何實現的
          • 異步請求,低版本Fetch如何低版本適配
          • Ajax如何處理跨域
          • CORS如何設置
          • Jsonp為什么不支持Post方法
          • 介紹同源策略
          • React使用過的一些組件
          • 介紹Immuable
          • 介紹下Redux整個流程原理
          • 介紹原型鏈
          • 如何繼承

          微醫

          • 介紹JS數據類型,基本數據類型和引用數據類型的區別
          • Array是Object類型嗎
          • 數據類型分別存在哪里
          • var a={name: "前端開發"}; var b=a; a=null那么b輸出什么
          • var a={b: 1}存放在哪里
          • var a={b: {c: 1}}存放在哪里
          • 棧和堆的區別
          • 垃圾回收時棧和堆的區別
          • 數組里面有10萬個數據,取第一個元素和第10萬個元素的時間相差多少
          • 棧和堆具體怎么存儲
          • 介紹閉包以及閉包為什么沒清除
          • 閉包的使用場景
          • JS怎么實現異步
          • 異步整個執行周期
          • Promise的三種狀態
          • Async/Await怎么實現
          • Promise和setTimeout執行先后的區別
          • JS為什么要區分微任務和宏任務
          • Promise構造函數是同步還是異步執行,then呢
          • 發布-訂閱和觀察者模式的區別
          • JS執行過程中分為哪些階段
          • 詞法作用域和this的區別
          • 平常是怎么做繼承
          • 深拷貝和淺拷貝
          • loadsh深拷貝實現原理
          • ES6中let塊作用域是怎么實現的
          • React中setState后發生了什么
          • setState為什么默認是異步
          • setState什么時候是同步的
          • 為什么3大框架出現以后就出現很多Native(RN)框架(虛擬DOM)
          • 虛擬DOM主要做了什么
          • 虛擬DOM本身是什么(JS對象)
          • 304是什么
          • 打包時Hash碼是怎么生成的
          • 隨機值存在一樣的情況,如何避免
          • 使用Webpack構建時有無做一些自定義操作
          • Webpack做了什么
          • a,b兩個按鈕,點擊aba,返回順序可能是baa,如何保證是aba(Promise.then)
          • Node接口轉發有無做什么優化
          • Node起服務如何保證穩定性,平緩降級,重啟等
          • RN有沒有做熱加載
          • RN遇到的兼容性問題
          • RN如何實現一個原生的組件
          • RN混原生和原生混RN有什么不同
          • 什么是單頁項目
          • 遇到的復雜業務場景
          • Promise.all實現原理

          寺庫

          • 介紹Promise的特性,優缺點
          • 介紹Redux
          • RN的原理,為什么可以同時在安卓和IOS端運行
          • RN如何調用原生的一些功能
          • 介紹RN的缺點
          • 介紹排序算法和快排原理
          • 堆和棧的區別
          • 介紹閉包
          • 閉包的核心是什么
          • 網絡的五層模型
          • HTTP和HTTPS的區別
          • HTTPS的加密過程
          • 介紹SSL和TLS
          • 介紹DNS解析
          • JS的繼承方法
          • 介紹垃圾回收
          • Cookie的引用為了解決什么問題
          • Cookie和localStorage的區別
          • 如何解決跨域問題
          • 前端性能優化

          寶寶樹

          • 使用Canvas繪圖時如何組織成通用組件
          • formData和原生的Ajax有什么區別
          • 介紹下表單提交,和FormData有什么關系
          • 介紹Redux接入流程
          • Rudux和全局管理有什么區別(數據可控、數據響應)
          • RN和原生通信
          • 介紹MVP怎么組織
          • 介紹異步方案
          • Promise如何實現Then處理
          • Koa2中間件原理
          • 常用的中間件
          • 服務端怎么做統一的狀態處理
          • 如何對相對路徑引用進行優化
          • Node文件查找優先級
          • Npm2和Npm3+有什么區別

          海康威視

          • Knex連接數據庫響應回調
          • 介紹異步方案
          • 如何處理異常捕獲
          • 項目如何管理模塊
          • 前端性能優化
          • JS繼承方案
          • 如何判斷一個變量是不是數組
          • 變量a和b,如何交換
          • 事件委托
          • 多個<li>標簽生成的Dom結構是一個類數組
          • 類數組和數組的區別
          • dom的類數組如何轉成數組
          • 介紹單頁面應用和多頁面應用
          • Redux狀態樹的管理
          • 介紹Localstorage的API

          蘑菇街

          • Html語義化的理解
          • <b>和<strong>的區別
          • 對閉包的理解
          • 工程中閉包使用場景
          • 介紹this和原型
          • 使用原型最大的好處
          • React設計思路
          • 為什么虛擬DOM比真實DOM性能好
          • React常見的通信方式
          • Redux整體的工作流程
          • Redux和全局對象之間的區別
          • Redux數據回溯設計思路
          • 單例、工廠、觀察者項目中實際場景
          • 項目中樹的使用場景以及了解
          • 工作收獲

          酷家樂

          • React生命周期
          • React性能優化
          • 添加原生事件不移除為什么會內存泄露
          • 還有哪些地方會內存泄露
          • setInterval需要注意的點
          • 定時器為什么是不精確的
          • setTimeout(1)和setTimeout(2)之間的區別
          • 介紹宏任務和微任務
          • Promise里面和then里面執行有什么區別
          • 介紹pureComponet
          • 介紹Function Component
          • React數據流
          • props和state的區別
          • 介紹React context
          • 介紹class和ES5的類以及區別
          • 介紹箭頭函數和普通函數的區別
          • 介紹defineProperty方法,什么時候需要用到
          • for..in 和 object.keys的區別
          • 介紹閉包,使用場景
          • 使用閉包特權函數的使用場景
          • Get和Post有什么區別

          百分點

          • React15/16.x的區別
          • 重新渲染Render會做些什么
          • 哪些方法會觸發React重新渲染
          • state和props觸發更新的生命周期分別有什么區別
          • setState是同步還是異步
          • 對無狀態組件的理解
          • 介紹Redux工作流程
          • 介紹ES6的功能
          • let、const以及var的區別
          • 淺拷貝和深拷貝的區別
          • 介紹箭頭函數的this
          • 介紹Promise和then
          • 介紹快速排序
          • 算法:前K個最大的元素

          海風教育

          • 對React看法,它的優缺點
          • 使用過程中遇到的問題,如何解決的
          • React的理念是什么(拿函數式編程來做頁面渲染)
          • JS是什么范式語言(面向對象還是函數式編程)
          • Koa原理,為什么要用Koa(Express和Koa對比)
          • 使用的Koa中間件
          • ES6使用的語法
          • Promise 和 async/await 和 Callback的區別
          • Promise有沒有解決異步的問題(Promise鏈是真正強大的地方)
          • Promise和setTimeout的區別(Event Loop)
          • 進程和線程的區別(一個Node實例就是一個進程,Node是單線程,通過事件循環來實現異步)
          • 介紹下DFS深度優先
          • 介紹下觀察者模式
          • 觀察者模式里面使用的數據結構(不具備順序 ,是一個List)

          作者簡介:木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。讓我帶你走進高級前端的世界,在進階的路上,共勉!

          聲明:本文系作者投稿,版權歸作者所有。

          先,我們來看一下什么是瀑布流布局效果,比如電商網站 蘑菇街

          原理圖:

          在一個大盒子里,放置多個小盒子,小盒子的大小可以不一致,長短不一樣,呈現一種瀑布流的效果。

          使用CSS3S實現只需要如下4步:

          1. 準備圖片素材

          2. 書寫相應HTML結構

          3. 了解CSS 多欄(Multi-column) 屬性

          4. 使用CSS 多欄屬性完成瀑布流布局


          主站蜘蛛池模板: 日韩人妻无码一区二区三区久久| 久久国产一区二区三区| 日本香蕉一区二区三区| 亚洲一区二区三区写真 | 精品国产一区二区三区免费看| 亚洲综合无码精品一区二区三区| 国产乱码精品一区二区三区香蕉| 一本AV高清一区二区三区| 久久99精品免费一区二区| 久久免费区一区二区三波多野| 无码人妻啪啪一区二区| 精品国产一区二区三区AV性色| 波多野结衣一区二区三区| 国精品无码一区二区三区在线蜜臀| 亚洲中文字幕一区精品自拍| 国产一区二区四区在线观看| 国产一区二区三区亚洲综合| 欧美激情一区二区三区成人| 欧美日韩精品一区二区在线视频| 久久综合精品不卡一区二区| 精品国产一区二区三区四区| 海角国精产品一区一区三区糖心| 曰韩精品无码一区二区三区| 亚洲欧美成人一区二区三区| 99久久精品国产免看国产一区| 无码国产精品一区二区免费vr | 亚洲变态另类一区二区三区 | 精品一区二区91| 亚洲一区二区三区精品视频| 国产凸凹视频一区二区| 国产一区二区精品久久岳√| 国产一区三区三区| 色噜噜狠狠一区二区| 久久影院亚洲一区| 成人H动漫精品一区二区| 欧美激情一区二区三区成人| 午夜性色一区二区三区免费不卡视频| 国产午夜三级一区二区三| 中文字幕一区二区三区有限公司 | 免费无码毛片一区二区APP| 国产乱码精品一区二区三区中文 |