摘要:設計本次留言墻分為兩部分。活動展示部分為匿名留言墻形式后改為實名制,需要根據收到的留言墻進行向上平滑滾動,如果沒有消息接收則停止在最后一條消息上。主要為處理數據的數據層。
背景
由于某事業群需要留言墻用于年會,同時需要調用大象公眾號服務器接口,所以在今年年初開發了留言墻用于活動現場交流。
設計本次留言墻分為兩部分。一部分為活動展示部分,另一部分為后臺審批部分。
活動展示部分為匿名留言墻形式(后改為實名制),需要根據收到的留言墻進行向上平滑滾動,如果沒有消息接收則停止在最后一條消息上。
后臺審批部分為管理人員對用戶像某個特定公眾號發送的特定格式消息進行審核,符合上墻要求的消息則通過審核,通過活動展示頁面進行展示。
技術方案 React該項目采用了React作為View層的渲染框架。關于React的簡單介紹,大家可以戳阮一峰的博客React 入門實例教程, 需要系統學習的同學可以戳React的官方網站React英文版,React中文版。建議大家閱讀React英文版網站,中文版網站相對于英文版網站來說缺少了一部分內容,例如React的children部分,可能是由于英文文檔更新導致的翻譯不太及時的原因。
ReduxRedux的學習可以通過Redux中文文檔來進行。里面有很多的示例能夠輔助進行學習。具體使用方法會通過后面的步驟進行介紹。
實現 React在View層中,有兩個組件。
Message
{this.props.flag === false ? : ""}{this.props.uname} [{this.parseDate(this.props.sendTime)}] {this.props.text} {this.props.flag === true ? this.props.approve === 0 ? : "已通過" : ""}
MsgList
{this.props.msgs.map((message, index) =>
{this.props.approveMsg(index, message.id)}}/> )}
其中Message為每條消息的組件,MsgList為整個消息列表的組件。
Redux ActionAction主要為處理數據的數據層。大部分的數據操作都放在Action中,通過dispatch(Action)的方法來通知readucer進行數據更新,從而通過react-redux來通知組件更新。
首先,會定義一些Action常量,用于操作命名。
export const WALL_REQUEST = "WALL_REQUEST"; export const WALL_REQUEST_SUCCESS = "WALL_REQUEST_SUCCESS"; export const WALL_REQUEST_FAIL = "WALL_REQUEST_FAIL"; export const CHECK_MSGS = "CHECK_MSGS"; export const CHECK_MSGS_SUCCESS = "CHECK_MSGS_SUCCESS"; export const CHECK_MSGS_FAIL = "CHECK_MSGS_FAIL"; export const MSG_REQUEST = "MSG_REQUEST"; export const MSG_REFUSE = "MSG_REFUSE"; export const MSG_PASS = "MSG_PASS";
同時,會定義一些函數,用于View層中與Action部分進行通信,從而觸發某些操作。
export function fetchMsgs(number) { const path = "/nh/show/msg"; return dispatch=> { dispatch(requestMsgs(number)); return window.fetch(URL + path).then(response=>response.json()).then(json=>dispatch(receiveMsgs(json.data))); } }
在reducer中使用了window變量中的fetch接口用于數據獲取,有關于此接口的使用我后面會寫另一篇文章來進行介紹,大家如果需要資料可以先戳此處,需要中文版的童鞋可以戳此處。
Reducer在Reducer中,會對當前state中的所有數據進行處理,改變state中的全局數據從而驅動組件重新渲染。
function msgsReducer(state = [], action) { switch(action.type) { case WALL_REQUEST: { return state.slice(action.number) } case WALL_REQUEST_SUCCESS: { return [ ...state, ...action.data ] } default: { return state; } } }
在reducer中一般通過Action中聲明的操作和action所帶來的參數對state進行操作。每次都需要返回一個新的對象或者數組,而不能再原有數據上進行修改,從而避免數據更新后組件不更新的問題。
Serverserver端返回的數據為一次性數據,即數據取過后就不會再返回,因此需要在前端Reducer里面對數據進行存儲。由于數據為滾動顯示,因此需要一個隊列來進行控制。
難點 滾動問題 scrollTop+setInterval最開始的滾動方案選擇此方案。此方案在實現上也最為簡單。但是,當消息數目到達1K量級時,能夠明顯的感覺到有卡頓的現象發生,滾動很不流暢,因此拋棄了此方法。
transform+setInterval由于上一個方案中scrollTop在節點數過多的情況下會導致卡頓的問題,因此在滾動上采用了transform的方法,但是由于setInterval粒度不夠小,因此對其進行了替換。
transform+window.requestAnimationFramewindow.requestAnimationFrame是瀏覽器接口,被調用的頻率是每秒60次,但是一般會遵循W3C標準規定的頻率。使用此接口可以保證調用頻率,同時能夠配合transform的變化數字來進行速度控制。因此采用了此方法。
節點刪除功能由于在留言墻的使用過程中,會有不斷的新的節點產生并且滾動出視口,因此為了節省內存,需要將滾動出視口的節點刪除,從而避免整個網頁消耗的內存越來越大。
由于滾動方式確定為transform的滾動方式,因此選擇了在請求調用返回數據后同時觸發刪除代碼,對當前消息節點進行判斷,對已經滾動到視口外的數據節點進行刪除,并重置transform值,從而達到刪除節點的目的。
componentWillReceiveProps(nextProps) { if(this.props.flag === false && this.props.msgs.length !== nextProps.msgs.length) { let number = Math.floor((-this.y) / this.msgHeight), element = document.getElementById("wall").getElementsByTagName("ul")[0]; if(number > 0) { this.y = this.y + number * this.msgHeight; element.style.transform = "translateY(" + (this.y) + "px)"; return; } window.cancelAnimationFrame(this.animationId); this.animationId = window.requestAnimationFrame(this.scroll.bind(this)); } }
通過組件接收新數據渲染時來重置transform值,完成節點刪除工作。
不足如果消息并發數量較多,會導致消息堆積在視口下方等待向上滾動,由此可能消耗大量的內存,后續仍然需要優化,避免所有接受到的未展示的數據都渲染出來堆積在下方。
總結在剛開始設計時至少考慮到了滾動的情況,并沒有考慮到消息越來越多導致頁面占用內存越來越大的問題。當完成最初版本的消息滾動時,在自己測試的過程中因為消息數量過大導致卡頓,所以考慮到了滾動方面的優化與節點刪除的問題。transform的效率優于scrollTop,而window.requestAnimationFrame的性能又優于setInterval,但是在開發時間上不是特別充足,因此選擇了性能最好的技術方案,但是舍棄了一部分優化的方案。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78908.html
摘要:最佳實踐一個文件一個組件。,這是包含的是無副作用的純函數式計算狀態操作的函數。,的啟動腳本,啟動開發模式,項目打包,運行單元測試等等。每次代碼推送到之前也會執行所有單元測試用例,全部通過才可以繼續推送。,首次安裝依賴包之后生成的文件。 前段時間 React license 的問題鬧的沸沸揚揚,搞得 React 社區人心惶惶,好在最終 React 團隊聽取了社區意見把 license 換...
摘要:譯者按最近依舊如火如荼相信大家都躍躍欲試我們團隊也開始在領域有所嘗試年應該是逐漸走向成熟的一年讓我們一起來看看國外的開發者們都總結了哪些最佳實踐年在全世界都有很多關于新的更新和開發者大會的討論關于去年的重要事件請參考那么年最有趣的問題來了我 譯者按:最近React(web/native)依舊如火如荼,相信大家都躍躍欲試,我們團隊也開始在React領域有所嘗試. 2016年應該是Reac...
摘要:前言一直混跡社區突然發現自己收藏了不少好文但是管理起來有點混亂所以將前端主流技術做了一個書簽整理不求最多最全但求最實用。 前言 一直混跡社區,突然發現自己收藏了不少好文但是管理起來有點混亂; 所以將前端主流技術做了一個書簽整理,不求最多最全,但求最實用。 書簽源碼 書簽導入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...
摘要:隔壁老王今日行程不同的內容使用這種方法就可以將我們得所有路由寫在一起了,可能有人覺得每次都要寫引入很麻煩,有沒有其他更好用的辦法,在講的時候會說到這里就先跳過。 前言 距離上篇文章已經好長一段時間了,這兩個星期公司派駐到京東方這邊出差負責入駐項目團隊的前端工作。這段時間從零搭建一下前端項目,這次給的時間比較充裕,思考的也比較多。以前也常有搭過前端項目,但是給的時間都比較緊,因此很多問題...
閱讀 5030·2021-09-07 09:58
閱讀 780·2019-08-30 15:55
閱讀 2909·2019-08-30 15:55
閱讀 915·2019-08-30 15:53
閱讀 1549·2019-08-29 12:57
閱讀 1796·2019-08-26 13:46
閱讀 558·2019-08-26 11:00
閱讀 3657·2019-08-23 15:42