├── .gitignore ├── README.md ├── app ├── ResumeEditor.js ├── StyleEditor.js ├── app.js └── style │ └── reset.css ├── build └── bundle.js ├── index.html ├── package.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## react-animation-resume 2 | 3 | 原版动态效果参见 http://strml.net/ 4 | 5 | 最近看到 [一个炫酷的简历模板 | 方应杭](https://zhuanlan.zhihu.com/p/25202080?refer=study-fe) 使用 Vue.js 实现了动态简历的效果,感觉很有意思,所以我也用 React 做了一份自己的简易动态简历 6 | 7 | 由于最近在准备实习,所以这个项目做的有点仓促,实现的效果还有改进的地方,设计也需要进步,大家有什么建议,希望不吝赐教,有时间我会将这个项目补充完善,谢谢!:) 8 | 9 | ### 使用方法 10 | 11 | 在线的项目展示效果可以点击链接: [React Animation Resume](https://shiningdan.github.io/react-animation-resume/) 12 | 13 | 如果想在本地下载、编译、运行,可以参考以下命令: 14 | 15 | ``` 16 | git clone https://github.com/ShiningDan/react-animation-resume.git 17 | cd react-animation-resume/ 18 | npm install 19 | npm run build 20 | npm run start 21 | ``` 22 | 23 | 就可以在 http://localhost:8080/index.html 上看到项目的展示效果啦 -------------------------------------------------------------------------------- /app/ResumeEditor.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import marked from "marked"; 4 | 5 | export default class ResumeEditor extends React.Component{ 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | style: "", 10 | content: "", 11 | isMarkdown: false, 12 | }; 13 | } 14 | 15 | replaceStyle(style) { 16 | this.setState({ 17 | style: style, 18 | }); 19 | } 20 | 21 | replaceContent(content) { 22 | this.setState({ 23 | content: content, 24 | }); 25 | } 26 | 27 | addToContent(char) { 28 | this.setState({ 29 | content: this.state.content + char, 30 | }); 31 | } 32 | 33 | getCurrentContentLength() { 34 | return this.state.content.length; 35 | } 36 | 37 | setIsMarkdown(isMarkdown) { 38 | this.setState({ 39 | isMarkdown: isMarkdown, 40 | }); 41 | } 42 | 43 | componentDidUpdate() { 44 | ReactDOM.findDOMNode(this).scrollTop = 10000; 45 | } 46 | 47 | render() { 48 | return (
49 | 			
50 | 		
); 51 | } 52 | } -------------------------------------------------------------------------------- /app/StyleEditor.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import {PrismCode} from "react-prism"; 4 | 5 | export default class StyleEditor extends React.Component{ 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | style: "", 10 | content: "", 11 | }; 12 | } 13 | 14 | addToStyle(char) { 15 | this.setState({ 16 | style: this.state.style + char, 17 | }); 18 | } 19 | 20 | addToContent(char) { 21 | this.setState({ 22 | content: this.state.content + char, 23 | }); 24 | } 25 | 26 | replaceStyle(style) { 27 | this.setState({ 28 | style: style, 29 | }); 30 | } 31 | 32 | replaceContent(content) { 33 | this.setState({ 34 | content: content, 35 | }); 36 | } 37 | 38 | 39 | componentDidUpdate() { 40 | ReactDOM.findDOMNode(this).scrollTop = 10000; 41 | } 42 | 43 | render() { 44 | return (
45 | 			{this.state.content}
46 |
); 47 | } 48 | } -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import StyleEditor from "./StyleEditor.js"; 4 | import ResumeEditor from "./ResumeEditor.js"; 5 | import "./style/reset.css"; 6 | import Prism from "prismjs"; 7 | 8 | class ReactClass extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | style: "", 13 | }; 14 | this.interval = 40; 15 | this.resumeEditorContent = ` 16 | # 张雨晨 17 | 18 | 19 | ## 项目及实习经历 20 | 21 | ### 思科实习生:软件定义云网 (Software-defined Cloud Network) 22 | 23 | * 基于 NSO 控制器开发 IDC 与运营商网络协同自动化框架。 24 | * 开发基于 Segment Routing 的广域网专线 QoS 调度系统。 25 | 26 | ### 实验室项目:面向远程医疗的SDN网络可靠性及安全研究 (Java) 27 | 28 | * 基于 SDN 为数据中心远程医疗平台提供防火墙、DDoS 防御、QoS 保障、链路快速恢复、路由环路与黑洞检测能力。 29 | 30 | ### [React Gallery](https://shiningdan.github.io/react-gallery/) (点击链接试试吧) 31 | 32 | * React 和 Webpack 制作的画廊应用效果 33 | 34 | ### [Animation Resume](https://shiningdan.github.io/react-animation-resume/) (点击链接试试吧) 35 | 36 | * React 和 Webpack 制作的简历自动演示效果。 37 | 38 | 39 | ## 教育经历 40 | 41 | 1. **北京邮电大学 - 通信工程** 研究生 42 | 43 | * 校一等奖学金 44 | 45 | 2. **北京邮电大学 - 通信工程** 本科生 46 | 47 | * 连续三年国家励志奖学金(专业前 10 %) 48 | 49 | ## 其他 50 | 51 | cet-6 (525) 52 | 53 | 54 | ## 博客 55 | 56 | **GitHub: **https://github.com/ShiningDan 57 | **Animation Resume: https://shiningdan.github.io/react-animation-resume/** 58 | 59 | > 如果你喜欢这个效果,Fork [我的项目](https://github.com/ShiningDan/react-animation-resume),打造你自己的简历!`; 60 | 61 | this.styleEditorContent = [`/* 62 | * Inspired by http://strml.net/ 63 | * 64 | * Hello, 我是张雨晨 65 | * 66 | * 我用 React 做了一份简易的动态简历 67 | * 希望大家能够喜欢 :) 68 | */ 69 | 70 | /* 所以我们就开始吧!首先给所有元素加上过渡效果 */ 71 | * { 72 | -webkit-transition: all 1s; 73 | transition: all 1s; 74 | } 75 | /* 白色背景太单调了,我们来点背景 */ 76 | html { 77 | color: rgb(222,222,222); background: #425261; 78 | } 79 | /* 文字直接显示在页面上,没有任何装饰,真的人反人类呢!所以我们来给文字加点装饰吧~~ */ 80 | .styleEditor { 81 | position: fixed; left: 0; top: 0; 82 | background-color: #303030; 83 | padding: .5em; 84 | border: 1px solid; 85 | margin: .5em; 86 | overflow: auto; 87 | width: 45vw; height: 90vh; 88 | } 89 | /* 作为一个程序员,我们不可以太沉闷哦~~,给自己的代码加一点色彩吧 */ 90 | .token.comment{ color: #857F6B; font-style: italic; } 91 | .token.selector{ color: #E86E75; } 92 | .token.property{ color: #F78C6C; } 93 | .token.punctuation{ color: #88DCFE; } 94 | .token.function{ color: #82AAFF; } 95 | 96 | /* 加一点 3D 效果,更加地酷炫 */ 97 | html{ 98 | -webkit-perspective: 1000px; 99 | perspective: 1000px; 100 | } 101 | .styleEditor { 102 | position: fixed; left: 0; top: 0; 103 | -webkit-transition: none; 104 | transition: none; 105 | -webkit-transform: rotateY(10deg) translateZ(-100px) ; 106 | transform: rotateY(10deg) translateZ(-100px) ; 107 | } 108 | /* 不知道以上对代码框的修改你是否喜欢呢? */ 109 | 110 | /* 接下来我给自己准备一个编辑器,用来存放我的简历内容 */ 111 | .resumeEditor{ 112 | position: fixed; right: 0; top: 0; 113 | padding: .5em; margin: .5em; 114 | width: 48vw; height: 90vh; 115 | border: 1px solid; 116 | background: white; color: #222; 117 | overflow: auto; 118 | } 119 | 120 | /* 好了,我开始写简历了 */ 121 | `, 122 | ` 123 | /* 这个简历好像差点什么 124 | * 对了,这是 Markdown 格式的,我需要变成对 HR 更友好的格式 125 | * 简单,用开源工具翻译成 HTML 就行了 126 | * 3 127 | * 2 128 | * 1 129 | * 啦啦! 130 | */ 131 | `, 132 | ` 133 | /* 再对 HTML 加点样式 */ 134 | .resumeEditor{ 135 | padding: 2em; 136 | } 137 | .resumeEditor h1{ 138 | display: block; 139 | width: 80px; 140 | margin: 0 auto; 141 | } 142 | .resumeEditor h2{ 143 | display: inline-block; 144 | border-bottom: 1px solid; 145 | margin: 1em 0 .5em; 146 | } 147 | .resumeEditor h3{ 148 | display: inline-block; 149 | margin: 0.5em 0; 150 | } 151 | .resumeEditor a{ 152 | color: #000; 153 | } 154 | .resumeEditor ul{ 155 | list-style: none; 156 | } 157 | .resumeEditor ul>li::before { 158 | content: "•"; 159 | margin-left: 1em; 160 | margin-right: 0.5em; 161 | } 162 | .resumeEditor blockquote { 163 | margin: 1em; 164 | padding: .5em; 165 | background: #ddd; 166 | } 167 | /* 168 | * I hope you enjoyed this. 169 | */ 170 | `]; 171 | } 172 | 173 | addToStyle(char) { 174 | this.setState({ 175 | style: this.state.style + char, 176 | }); 177 | } 178 | 179 | replaceStyle(style) { 180 | this.setState({ 181 | style: style, 182 | }); 183 | } 184 | 185 | replaceStyleEditorContent() { 186 | 187 | } 188 | 189 | showStyleEditorContent(n) { 190 | let lastContentLength = 0; 191 | if (n !== 0) {lastContentLength = this.state.style.length;} 192 | let style = this.styleEditorContent[n]; 193 | let len = style.length; 194 | return new Promise((resolve, reject) => { 195 | let showStyle = function () { 196 | let currentLen = this.state.style.length - lastContentLength; 197 | if (currentLen < len) { 198 | let char = style.substring(currentLen, currentLen+1); 199 | this.refs.StyleEditor.addToContent(char); 200 | this.addToStyle(char); 201 | setTimeout(showStyle, this.interval); 202 | } else { 203 | resolve(); 204 | } 205 | }.bind(this); 206 | showStyle(); 207 | }); 208 | } 209 | 210 | showResumeContent() { 211 | let content = this.resumeEditorContent; 212 | let len = content.length; 213 | return new Promise((resolve, reject) => { 214 | let showContent = function() { 215 | let currentLen = this.refs.ResumeEditor.getCurrentContentLength(); 216 | if (currentLen < len) { 217 | let char = content.substring(currentLen, currentLen+1); 218 | this.refs.ResumeEditor.addToContent(char); 219 | setTimeout(showContent, this.interval); 220 | } else { 221 | resolve(); 222 | } 223 | }.bind(this); 224 | showContent(); 225 | }); 226 | } 227 | 228 | setResumeMarkdown() { 229 | return new Promise((resolve, reject) => { 230 | setTimeout(this.refs.ResumeEditor.setIsMarkdown(true), this.interval); 231 | resolve(); 232 | }); 233 | } 234 | 235 | async startShow() { 236 | await this.showStyleEditorContent(0).then(function() {console.log('done! show Content 0')}); 237 | await this.showResumeContent(); 238 | await this.showStyleEditorContent(1).then(function() {console.log('done! show Content 1')}); 239 | await this.setResumeMarkdown(); 240 | await this.showStyleEditorContent(2).then(function() {console.log('done! show Content 2')}); 241 | } 242 | 243 | componentDidMount() { 244 | this.startShow(); 245 | console.log(111); 246 | // this.refs.StyleEditor.replaceContent(this.content[0]); 247 | // this.replaceStyle(this.content[0]); 248 | // this.refs.ResumeEditor.replaceContent(""); 249 | } 250 | 251 | render() { 252 | return ( 253 |
254 | 255 | 256 | 257 |
); 258 | } 259 | } 260 | ReactDOM.render(, document.getElementById("content")); -------------------------------------------------------------------------------- /app/style/reset.css: -------------------------------------------------------------------------------- 1 | *{margin: 0; padding: 0;} 2 | *{box-sizing: border-box;} 3 | *::before{box-sizing: border-box;} 4 | *::after{box-sizing: border-box;} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Animation Resume 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-animation-resume", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --progress --colors --watch", 8 | "build": "webpack" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/ShiningDan/react-animation-resume.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/ShiningDan/react-animation-resume/issues" 18 | }, 19 | "homepage": "https://github.com/ShiningDan/react-animation-resume#readme", 20 | "devDependencies": { 21 | "babel-core": "^6.23.1", 22 | "babel-loader": "^6.3.2", 23 | "babel-polyfill": "^6.23.0", 24 | "babel-preset-es2015": "^6.22.0", 25 | "babel-preset-react": "^6.23.0", 26 | "babel-preset-stage-3": "^6.22.0", 27 | "css-loader": "^0.26.1", 28 | "marked": "^0.3.6", 29 | "prismjs": "^1.6.0", 30 | "react": "^15.4.2", 31 | "react-dom": "^15.4.2", 32 | "react-prism": "^4.0.0", 33 | "style-loader": "^0.13.1", 34 | "webpack": "^2.2.1", 35 | "webpack-dev-server": "^2.4.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = { 4 | entry: ["babel-polyfill", path.resolve(__dirname, "app/app.js")], 5 | output: { 6 | path: path.resolve(__dirname, "build"), 7 | filename: "bundle.js", 8 | }, 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.js?$/, 13 | exclude: /node_modules/, 14 | loader: "babel-loader", 15 | query: { 16 | presets: ["es2015", "react", "stage-3"] 17 | } 18 | }, 19 | { 20 | test: /\.css$/, 21 | loader: 'style-loader!css-loader' 22 | } 23 | ], 24 | } 25 | } --------------------------------------------------------------------------------