├── .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 (
);
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 | }
--------------------------------------------------------------------------------