摘要:官方文檔中文文檔基本使用注意一定要在根目錄的中聲明,要不然點擊任何鏈接都無法跳轉。官方文檔中文文檔簡單的來說,每一次的修改狀態都需要觸發,然而其實項目中我現在還沒用到修改數據。。。
學習 React 的過程中實現了一個個人主頁,沒有復雜的實現和操作,適合入門 ~
原文地址:https://github.com/axuebin/react-blog/issues/17
這個項目其實功能很簡單,就是常見的主頁、博客、demo、關于我等功能。
頁面樣式都是自己寫的,黑白風格,可能有點丑。不過還是最低級的 CSS ,準備到時候重構 ~
如果有更好的方法,或者是我的想法有偏差的,歡迎大家交流指正
歡迎參觀:http://axuebin.com/react-blog
Github:https://github.com/axuebin/react-blog
預覽圖 首頁 博客頁 文章內容頁 Demo頁 關鍵技術ES6:項目中用到 ES6 的語法,在寫的過程中盡量使用,可能有的地方沒想到
React
React-Router:前端路由
React-Redux:狀態管理
webpack:打包
marked:Markdown渲染
highlight.js:代碼高亮
fetch:異步請求數據
eslint:代碼檢查
antd:部分組件懶得自己寫。。
準備工作由于不是使用 React 腳手架生成的項目,所以每個東西都是自己手動配置的。。。
模塊打包器打包用的是 webpack 2.6.1,準備入坑 webpack 3 。
官方文檔:https://webpack.js.org/
中文文檔:https://doc.webpack-china.org/
對于 webpack 的配置還不是太熟,就簡單的配置了一下可供項目啟動:
var webpack = require("webpack"); var path = require("path"); module.exports = { context: __dirname + "/src", entry: "./js/index.js", module: { loaders: [ { test: /.js?$/, exclude: /(node_modules)/, loader: "babel-loader", query: { presets: ["react", "es2015"] } }, { test: /.css$/, loader: "style-loader!css-loader" }, { test: /.js$/, exclude: /(node_modules)/, loader: "eslint-loader" }, { test: /.json$/, loader: "json-loader" } ] }, output: { path: __dirname + "/src/", filename: "bundle.js" } }
webpack 有幾個重要的屬性:entry、module、output、plugins,在這里我還沒使用到插件,所以沒有配置 plugins 。
module 中的 loaders:
babel-loader:將代碼轉換成es5代碼
css-loader:處理css中路徑引用等問題
style-loader:動態把樣式寫入css
eslin-loader:使用eslint
包管理包管理現在使用的還是 NPM 。
官方文檔:https://docs.npmjs.com/
npm init
npm install
npm uninstall
關于npm,可能還需要了解 dependencies 和 devDependencies 的區別,我是這樣簡單理解的:
dependencies:項目跑起來后需要使用到的模塊
devDependencies:開發的時候需要用的模塊,但是項目跑起來后就不需要了
代碼檢查項目使用現在比較流行的 ESLint 作為代碼檢查工具,并使用 Airbnb 的檢查規則。
ESLint:https://github.com/eslint/eslint
eslint-config-airbnb:https://www.npmjs.com/package/eslint-config-airbnb
在 package.json 中可以看到,關于 ESLint 的包就是放在 devDependencies 底下的,因為它只是在開發的時候會使用到。
使用在 webpack 配置中加載 eslint-loader:
module: { loaders: [ { test: /.js$/, exclude: /(node_modules)/, loader: "eslint-loader" } ] }
創建 .elintrc文件:
{ "extends": "airbnb", "env":{ "browser": true }, "rules":{} }
然后在運行 webpack 的時候,就會執行代碼檢查啦,看著一堆的 warning 、error 是不是很爽~
這里有常見的ESLint規則:http://eslint.cn/docs/rules/
數據源由于是為了練習 React,暫時就只考慮搭建一個靜態頁面,而且現在越來越多的大牛喜歡用 Github Issues 來寫博客,也可以更好的地提供評論功能,所以我也想試試用 Github Issues 來作為博客的數據源。
API在這:https://developer.github.com/v3/issues/
我也沒看完全部的API,就看了看怎么獲取 Issues 列表。。
https://api.github.com/repos/axuebin/react-blog/issues?creator=axuebin&labels=blog
通過控制參數 creator 和 labels,可以篩選出作為展示的 Issues。它會返回一個帶有 issue 格式對象的數組。每一個 issue 有很多屬性,我們可能不需要那么多,先了解了解底下這幾種:
// 為了方便,我把注釋寫在json中了。。 [{ "url": , // issue 的 url "id": , // issue id , 是一個隨機生成的不重復的數字串 "number": , // issue number , 根據創建 issue 的順序從1開始累加 "title": , // issue 的標題 "labels": [], // issue 的所有 label,它是一個數組 "created_at": , // 創建 issue 的時間 "updated_at": , // 最后修改 issue 的時間 "body": , // issue 的內容 }]異步請求數據
項目中使用的異步請求數據的方法時 fetch。
關于 fetch :https://segmentfault.com/a/1190000003810652
使用起來很簡單:
fetch(url).then(response => response.json()) .then(json => console.log(json)) .catch(e => console.log(e));markdown 渲染
在 Github 上查找關于如何在 React 實現 markdown 的渲染,查到了這兩種庫:
react-markdown:https://github.com/rexxars/react-markdown
marked:https://github.com/chjj/marked
使用起來都很簡單。
如果是 react-markdown,只需要這樣做:
import ReactMarkdown from "react-markdown"; const input = "# This is a header And this is a paragraph"; ReactDOM.render(, document.getElementById("container") );
如果是marked,這樣做:
import marked from "marked"; const input = "# This is a header And this is a paragraph"; const output = marked(input);
這里有點不太一樣,我們獲取到了一個字符串 output,注意,是一個字符串,所以我們得將它插入到 dom中,在 React 中,我們可以這樣做:
由于我們的項目是基于 React 的,所以想著用 react-markdown會更好,而且由于安全問題 React 也不提倡直接往 dom 里插入字符串,然而在使用過程中發現,react-markdown 對表格的支持不友好,所以只好棄用,改用 marked。
代碼高亮代碼高亮用的是highlight.js:https://github.com/isagalaev/highlight.js
它和marked可以無縫銜接~
只需要這樣既可:
import hljs from "highlight.js"; marked.setOptions({ highlight: code => hljs.highlightAuto(code).value, });
highlight.js是支持多種代碼配色風格的,可以在css文件中進行切換:
@import "~highlight.js/styles/atom-one-dark.css";
在這可以看到每種語言的高亮效果和配色風格:https://highlightjs.org/
React state 和 props 是什么可以看之前的一篇文章:https://github.com/axuebin/react-blog/issues/8
關于React組件的生命周期可以看之前的一篇文章:https://github.com/axuebin/react-blog/issues/9
前端路由項目中前端路由用的是 React-Router V4。
官方文檔:https://reacttraining.com/react-router/web/guides/quick-start
中文文檔:http://reacttraining.cn/
基本使用Blog
注意:一定要在根目錄的 Route 中聲明 exact,要不然點擊任何鏈接都無法跳轉。
2級目錄跳轉比如我現在要在博客頁面上點擊跳轉,此時的 url 是 localhost:8080/blog,需要變成 localhost:8080/blog/article,可以這樣做:
這樣就可以跳轉到 localhost:8080/blog/article 了,而且還傳遞了一個 number 參數,在 article 中可以通過 this.props.params.number獲取。
HashRouter當我把項目托管到 Github Page 后,出現了這樣一個問題。
刷新頁面出現 Cannot GET / 提示,路由未生效。
通過了解,知道了原因是這樣,并且可以解決:
由于刷新之后,會根據URL對服務器發送請求,而不是處理路由,導致出現 Cannot GET / 錯誤。
通過修改
當前一個頁面滾動到一定區域后,點擊跳轉后,頁面雖然跳轉了,但是會停留在滾動的區域,不會自動回到頁面頂部。
可以通過這樣來解決:
componentDidMount() { this.node.scrollIntoView(); } render() { return (狀態管理this.node = node} >); }
項目中多次需要用到從 Github Issues 請求來的數據,因為之前就知道 Redux 這個東西的存在,雖然有點大材小用,為了學習還是將它用于項目的狀態管理,只需要請求一次數據即可。
官方文檔:http://redux.js.org/
中文文檔:http://cn.redux.js.org/
簡單的來說,每一次的修改狀態都需要觸發 action ,然而其實項目中我現在還沒用到修改數據2333。。。
關于狀態管理這一塊,由于還不是太了解,就不誤人子弟了~
主要組件React是基于組件構建的,所以在搭建頁面的開始,我們要先考慮一下我們需要一些什么樣的組件,這些組件之間有什么關系,哪些組件是可以復用的等等等。
首頁可以看到,我主要將首頁分成了四個部分:
header:網站標題,副標題,導航欄
banner:about me ~,準備用自己的照片換個背景,但是還沒有合適的照片
card area:暫時是三個卡片
blog card:最近的幾篇博文
demo card:幾個小demo類別
me card:算是我放飛自我的地方吧
footer:版權信息、備案信息、瀏覽量
博客頁博客頁就是很中規中矩的一個頁面吧,這部分是整個項目中代碼量最多的部分,包括以下幾部分:
文章列表組件
翻頁組件
歸檔按鈕組件
類別組件
標簽組件
文章列表文章列表其實就是一個 list,里面有一個個的 item:
文章1文章2對于每一個 item,其實是這樣的:
一個文章item組件它可能需要包括:
文章標題
文章發布的時間、類別、標簽等
文章摘要
...
如果用 DOM 來描述,它應該是這樣的:
文章標題時間類別標簽摘要所以,我們可以有很多個組件:
文章列表組件
文章item組件
類別標簽組件
它們可能是這樣一個關系:
分頁對于分頁功能,傳統的實現方法是在后端完成分頁然后分批返回到前端的,比如可能會返回一段這樣的數據:
{ total:500, page:1, data:[] }也就是后端會返回分好頁的數據,含有表示總數據量的total、當前頁數的page,以及屬于該頁的數據data。
然而,我這個頁面只是個靜態頁面,數據是放在Github Issues上的通過API獲取的。(Github Issues的分頁貌似不能自定義數量...),所以沒法直接返回分好的數據,所以只能在前端強行分頁~
分頁功能這一塊我偷懶了...用的是 antd 的翻頁組件
。 官方文檔:https://ant.design/components/pagination-cn/
文檔很清晰,使用起來也特別簡單。
前端渲染的邏輯(有點蠢):將數據存放到一個數組中,根據當前頁數和每頁顯示條數來計算該顯示的索引值,取出相應的數據即可。
翻頁組件中:
constructor() { super(); this.onChangePage = this.onChangePage.bind(this); } onChangePage(pageNumber) { this.props.handlePageChange(pageNumber); } render() { return (); }當頁數發生改變后,會觸發從父組件傳進
的方法 handlePageChange,從而將頁數傳遞到父組件中,然后傳遞到 中。 父組件中:
handlePageChange(pageNumber) { this.setState({ currentPage: pageNumber }); } render() { return (); }列表中:
render() { const articlelist = []; const issues = this.props.issues; const currentPage = this.props.pageNumber; const defaultPageSize = this.props.defaultPageSize; const start = currentPage === 1 ? 0 : (currentPage - 1) * defaultPageSize; const end = start + defaultPageSize < issues.length ? start + defaultPageSize : issues.length; for (let i = start; i < end; i += 1) { const item = issues[i]; articlelist.push(label); } } 在 Github Issues 中,可以為一個 issue 添加很多個 label,我將這些對于博客內容有用的 label 分為三類,分別用不同顏色來表示。
這里說明一下, label 創建后會隨機生成一個 id,雖然說 id 是不重復的,但是文章的類別、標簽會一直在增加,當新加一個 label 時,程序中可能也要進行對應的修改,當作區分 label 的標準可能就不太合適,所以我采用顏色來區分它們。
表示這是一篇文章的blog:只有有 blog 的 issue 才能顯示在頁面上,過濾 bug 、help 等
表示文章類別的:用來表示文章的類別,比如“前端”、“攝影”等
表示文章標簽的:用來表示文章的標簽,比如“JavaScript”、“React”等
即使有新的 label ,也只要根據顏色區分是屬于哪一類就好了。
類別
在這里的思路主要就是:遍歷所有 issues,然后再遍歷每個 issue的 labels,找出屬于類別的 label,然后計數。
const categoryList = []; const categoryHash = {}; for (let i = 0; i < issues.length; i += 1) { const labels = issues[i].labels; for (let j = 0; j < labels.length; j += 1) { if (labels[j].color === COLOR_LABEL_CATEGORY) { const category = labels[j].name; if (categoryHash[category] === undefined) { categoryHash[category] = true; const categoryTemp = { category, sum: 1 }; categoryList.push(categoryTemp); } else { for (let k = 0; k < categoryList.length; k += 1) { if (categoryList[k].category === category) { categoryList[k].sum += 1; } } } } } }這樣實現得要經歷三次循環,復雜度有點高,感覺有點蠢,有待改進,如果有更好的方法,請多多指教~
標簽
這里的思路和類別的思路基本一樣,只不過不同的顯示方式而已。
本來這里是想通過字體大小來體現每個標簽的權重,后來覺得可能對于我來說,暫時只有那幾個標簽會很頻繁,其它標簽可能會很少,用字體大小來區分就沒有什么意義,還是改成排序的方式。
文章頁文章頁主要分為兩部分:
文章內容區域:顯示文章內容,顯示在頁面的主體區域
章節目錄:文章的章節目錄,顯示在文章的右側區域
文章內容有兩種方式獲取文章具體內容:
從之前已經請求過的數組中去遍歷查找所需的文章內容
通過 issue number 重新發一次請求直接獲取內容
最后我選擇了后者。
文章是用 markdown 語法寫的,所以要先轉成 html 然后插入頁面中,這里用了一個 React 不提倡的屬性:dangerouslySetInnerHTML。
除了渲染markdown,我們還得對文章中的代碼進行高亮顯示,還有就是定制文章中不同標簽的樣式。
章節目錄首先,這里有一個 issue,希望大家可以給一些建議~
文章內容是通過 markdown 渲染后插入 dom 中的,由于 React 不建議通過 document.getElementById 的形式獲取 dom 元素,所以只能想辦法通過字符串匹配的方式獲取文章的各個章節標題。
由于我不太熟悉正則表達式,曾經還在sf上咨詢過,就采用了其中一個答案:
const issues = content; const menu = []; const patt = /(#+)s+?(.+)/g; let result = null; while ((result = patt.exec(issues))) { menu.push({ level: result[1].length, title: result[2] }); }這樣可以獲取到所有的 # 的字符串,也就是 markdown 中的標題, result[1].length 表示有幾個 #,其實就是幾級標題的意思,title 就是標題內容了。
這里還有一個問題,本來通過 的方式可以實現點擊跳轉,但是現在渲染出來的 html 中對于每一個標題沒有獨一無二的標識。。。
歸檔頁按年份歸檔:
按類別歸檔:
按標簽歸檔:
問題基本功能是已經基本實現了,現在還存在著以下幾個問題,也算是一個 TodoList 吧
評論功能。擬利用 Github Issues API 實現評論,得實現 Github 授權登錄
回到頂部。擬利用 antd 的組件,但是 state 中 visibility 一直是 false
首頁渲染?,F在打包完的js文件還是太大了,導致首頁渲染太慢,這個是接下來工作的重點,也了解過關于這方面的優化:
webpack 按需加載。這可能是目前最方便的方式
服務端渲染。這就麻煩了,但是好處也多,不僅解決渲染問題,還有利于SEO,所以也是 todo 之一
代碼混亂,邏輯不對。這是我自己的問題,需要再修煉。
原文地址:https://github.com/axuebin/react-blog/issues/17
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88772.html
相關文章
手把手教你用vue搭建個人站
摘要:在我轉前端以來,一直想要實現一個愿望自己搭建一個可以自動解析文檔的個人站今天終于實現啦,先貼上我的地址確認需求其實一個最簡單的個人站,就是許多的頁面,你只要可以用寫出來就可以,然后掛到上。 在我轉前端以來,一直想要實現一個愿望: 自己搭建一個可以自動解析Markdown文檔的個人站 今天終于實現啦,先貼上我的blog地址 確認需求 其實一個最簡單的個人站,就是許多的HTML頁面,你只要...
2017-07-10 前端日報
摘要:前端日報精選入門指南入口,輸出,加載器和插件中數據類型轉換讓我印象深刻的面試題大話大前端時代一與的組件化庖丁解牛一發布中文第期手把手教你用管理狀態上個快速編程技巧眾成翻譯中執行順序組件解耦之道眾成翻譯組件模型啟示錄有個梨作 2017-07-10 前端日報 精選 Webpack入門指南: 入口,輸出,加載器和插件JavaScript中數據類型轉換讓我印象深刻的javascript面試題大...
手把手教你用 JavaScript 實現一個簡單的國際象棋 AI
摘要:實現這一功能最簡單的方法是計算棋盤上棋子的相對強度大小,用下面的對照表。本鏈接是基于算法優化的國際象棋。我們來稍微調整一下棋盤上棋子狀態的權重,這一圖表是在國際象棋程序維基百科中給出的。 showImg(https://segmentfault.com/img/remote/1460000009143081?w=2000&h=1317); 本文作者: Lauri Hartikka 編...
手把手教你用 JavaScript 實現一個簡單的國際象棋 AI
摘要:實現這一功能最簡單的方法是計算棋盤上棋子的相對強度大小,用下面的對照表。本鏈接是基于算法優化的國際象棋。我們來稍微調整一下棋盤上棋子狀態的權重,這一圖表是在國際象棋程序維基百科中給出的。 showImg(https://segmentfault.com/img/remote/1460000009143081?w=2000&h=1317); 本文作者: Lauri Hartikka 編...
手把手教你用es6+vue2+webpack2+vue-router2搭建個人blog
摘要:更新日志更新完成靜態頁面原型修復使用的正確姿勢更新添加靜態頁面更新添加使用方法請戳我主要作用就是在你開發環節在后端同學還未開發完成的情況下,提供一個。 底下評論說是標題黨,或者是光扔個github地址上來的同學我就不說什么了。你們有看看倉庫的提交記錄么?我還沒有吃撐到開個倉庫去騙star.我的出發點就是每天更新一部分代碼,教大家用我所提到的技術棧搭建一個blog,我的出發點就是這么簡單...
發表評論
0條評論
閱讀 2639·2021-11-22 15:24
閱讀 1370·2021-11-17 09:38
閱讀 2746·2021-10-09 09:57
閱讀 1192·2019-08-30 15:44
閱讀 2438·2019-08-30 14:00
閱讀 3538·2019-08-30 11:26
閱讀 2935·2019-08-29 16:28
閱讀 746·2019-08-29 13:56