-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlearn_react_by_code_a_mou.html
1 lines (1 loc) · 41.7 KB
/
learn_react_by_code_a_mou.html
1
<!doctype html><html lang="zh-CN" class="night"><head><meta charset="utf-8"><meta content="width=device-width,initial-scale=1,maximum-scale=4,user-scalable=0" name="viewport"><title>Ede's Blog</title><meta name="description" content="Try to be a qualified programmer"><meta property="og:type" content="website"><meta property="og:description" content="Try to be a qualified programmer"><meta property="og:title" content="Ede's Blog"><meta property="og:site_name" content="Ede's Blog"><meta property="og:url" content="https://ede.ink"><meta property="og:image" content="https://edeity.oss-cn-shenzhen.aliyuncs.com/public/edeity_o.png"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"><link rel="mainfest" href="/mainfest.json"><link rel="stylesheet" href="/public/css/common.css"><link rel="stylesheet" href="//at.alicdn.com/t/font_707055_4b9og9sc5lx.css"><script>!function(){var e=-1!==window.location.search.indexOf("theme=night")||"night"===window.localStorage.getItem("edeity-theme_theme"),t=-1!==window.location.search.indexOf("theme=light")||"light"===window.localStorage.getItem("edeity-theme_theme");(new Date).getHours();var n=document.querySelector("html");e?n.classList.add("night"):t?n.classList.remove("night"):n.classList.add("night")}(),document.addEventListener("DOMContentLoaded",function(){null!==document.querySelector("ol.toc")&&(document.querySelector("#nav-bar").style.cssText="display: block")})</script><script async src="https://www.googletagmanager.com/gtag/js?id=G-M3J9QSEE2Z"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-M3J9QSEE2Z")</script><meta name="generator" content="Hexo 5.0.0"></head><body><div class="loading"></div><div id="switch" data-switch="{"toc":true,"use_pwa":false}"></div><header class="fullscreen"><div class="toolbar"><i class="iconfont icon-menu"></i></div><h1><a href="/">Ede's Blog</a></h1><div class="head-link"><a class="btn waves" href="/"><span><i class="iconfont icon-home">Home </i></span></a><a class="btn waves" href="/about/index.html"><span><i class="iconfont icon-me">About </i></span></a><a class="btn waves" target="_blank" rel="noopener" href="https://github.com/edeink"><span><i class="iconfont icon-github">Github</i></span></a></div></header><div class="some-link"><a class="btn" id="light-or-not"><i class="iconfont icon-light"></i> </a><a style="display:none" class="btn" id="up-to-top"><i class="iconfont icon-up"></i></a></div><div id="nav-bar" style="display:none"><div class="toc"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9D%E6%AD%A5"><span class="toc-number">1.</span> <span class="toc-text">初步</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#react"><span class="toc-number">1.1.</span> <span class="toc-text">react?</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#mou%E7%95%8C%E9%9D%A2"><span class="toc-number">1.2.</span> <span class="toc-text">mou界面</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#css%E7%BE%8E%E5%8C%96%E4%B8%80%E4%B8%8B"><span class="toc-number">1.3.</span> <span class="toc-text">css美化一下</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E5%8C%96"><span class="toc-number">1.4.</span> <span class="toc-text">组件化</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD"><span class="toc-number">2.</span> <span class="toc-text">其他功能</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#marked"><span class="toc-number">2.1.</span> <span class="toc-text">marked</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#markdown-css"><span class="toc-number">2.2.</span> <span class="toc-text">markdown.css</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%90%8C%E6%AD%A5%E6%BB%9A%E5%8A%A8"><span class="toc-number">2.3.</span> <span class="toc-text">同步滚动</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%80%E7%BB%88%E7%9A%84%E7%BB%93%E6%9E%9C"><span class="toc-number">3.</span> <span class="toc-text">最终的结果</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96"><span class="toc-number">3.1.</span> <span class="toc-text">其他</span></a></li></ol></li></ol></div></div><main id="content-main" class="section"><div class="list-item"><h1 class="post-title"><a id="React初探:写一个“mou”" class="article-link" href="">React初探:写一个“mou”</a></h1><div class="post-meta"><time class="meta published">Dec 9, 2015</time></div><div class="article"><div class="post-excerpt markdown-body"><p><img src="https://edeity.oss-cn-shenzhen.aliyuncs.com/2015/mou.jpg" alt="mouer-preview"></p><div class="img-desc">简陋的Web Mou</div><h2 id="初步"><a href="#初步" class="headerlink" title="初步"></a>初步</h2><h3 id="react"><a href="#react" class="headerlink" title="react?"></a>react?</h3><p>要用react, 得先了解react</p><p>facebook如此形容react</p><blockquote><p>We built <strong>React</strong> to solve one problem: <em>building large applications with data that changes over time</em>.</p></blockquote><p>关键短语 :</p><ul><li>building large applications(大型的应用)</li><li>data that changes over time(数据改变频繁)</li></ul><p>表示看不懂,只好在心里默念</p><ul><li>mou, mou, mou</li></ul><p>无视一切,继续前进</p><h3 id="mou界面"><a href="#mou界面" class="headerlink" title="mou界面"></a>mou界面</h3><p>从mou官网盗图一张:</p><p> <img src="https://edeity.oss-cn-shenzhen.aliyuncs.com/2015/mou.png?x-oss-process=style/preview" alt="mou"></p><p>所以[布局]应该是</p><ul><li>StatePanle(上):状态栏,负责显示状态</li><li>InputPanel(左):编辑框,负责用户输入</li><li>RenderPanel(右):显示框,负责渲染markdown文档</li></ul><p>伪代码如下</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">Mou</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">StatePanel</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">InputPanel</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">RenderPanel</span> /></span></span><br><span class="line"><span class="tag"></<span class="name">Mou</span>></span></span><br></pre></td></tr></table></figure><p>用了大半年的<code>div</code>,html里面可没有<code><InputPanel></code>,<code><RenderPanel></code>啊?</p><p>这就是react的作用之一,无中生有,自定义一个伪html标签,以便以后想用就用,就像用html标签一样简单;具体的做法是:</p><figure class="highlight jsx"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mou</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"mou-app"</span>></span><br><span class="line"> <StatePanel/></span><br><span class="line"> <InputPanel/></span><br><span class="line"> <RenderPanel/></span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StatePanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"state-panel"</span>></div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InputPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <textarea id=<span class="string">"input-panel"</span>></textarea></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RenderPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"render-panel"</span>></div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">React.render(<span class="xml"><span class="tag"><<span class="name">Mou</span>/></span></span>, <span class="built_in">document</span>.getElementById(<span class="string">'app'</span>));</span><br></pre></td></tr></table></figure><p>我又开始懵逼了:不是说前端js一统天下吗?<code>class</code>,<code>extends</code>又是什么东东?</p><p>其实,上面的“语言”可分为两部分:</p><ol><li>新鲜出炉的<strong>EcmaScript2015</strong>,俗称<a target="_blank" rel="noopener" href="http://es6.ruanyifeng.com/">ES6</a>,最新的javascript标准, 如:<ul><li><code>class StatePanel extends React.Component</code>;</li></ul></li><li>react专用的模板(<a target="_blank" rel="noopener" href="http://reactjs.cn/react/docs/jsx-in-depth.html">jsx</a>),(web标准可不支持自定义标签,jsx的作用是编写jsx,通过解析,识别伪标签):<ul><li><code>render(){return (<div id="render-panel"></div>)}</code>:</li></ul></li></ol><h3 id="css美化一下"><a href="#css美化一下" class="headerlink" title="css美化一下"></a>css美化一下</h3><p>css如下:</p><figure class="highlight css"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*布局Start*/</span></span><br><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">984px</span>;</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">30px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#mou-app</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">984px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">665px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#state-panel</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">984px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">23px</span>;</span><br><span class="line"> <span class="attribute">border-top</span>: <span class="number">1px</span> solid <span class="number">#DADADA</span>;</span><br><span class="line"> <span class="attribute">border-bottom</span>: <span class="number">1px</span> solid <span class="number">#C0C0C0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#input-panel</span>, <span class="selector-id">#render-panel</span> {</span><br><span class="line"> <span class="attribute">float</span>: left;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">430px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">580px</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">30px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#input-panel</span> {</span><br><span class="line"> <span class="attribute">border</span>: none;</span><br><span class="line"> <span class="attribute">border-right</span>: <span class="number">4px</span> solid <span class="number">#f2f2f2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*布局End*/</span></span><br><span class="line"><span class="comment">/*样式START*/</span></span><br><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: <span class="number">#F5F5F5</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#mou-app</span> {</span><br><span class="line"> <span class="attribute">border-radius</span>: <span class="number">5px</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">10px</span> <span class="number">20px</span> <span class="number">10px</span> <span class="number">#919191</span>;</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#input-panel</span> { </span><br><span class="line"> <span class="attribute">outline</span>: none;</span><br><span class="line"> <span class="attribute">resize</span>: none;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">1.1em</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#render-panel</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: white;</span><br><span class="line"> </span><br><span class="line"> <span class="attribute">overflow</span>: scroll;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#state-panel</span> {</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">linear-gradient</span>(#F5F5F5, #D4D4D4);</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-webkit-linear-gradient</span>(#F5F5F5, #D4D4D4);</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#021000</span>;</span><br><span class="line"> <span class="attribute">text-align</span>: center;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*样式END*/</span></span><br></pre></td></tr></table></figure><p>好了,一个没有灵魂的mou界面终于出厂了。</p><iframe height="535" scrolling="no" src="//codepen.io/edeity/embed/dGOyNj/?height=535&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen style="width:100%">See the Pen <a href="http://codepen.io/edeity/pen/dGOyNj/" target="_blank" rel="external">dGOyNj</a> by 李健乐 (<a href="http://codepen.io/edeity" target="_blank" rel="external">@edeity</a>) on <a href="http://codepen.io" target="_blank" rel="external">CodePen</a>.<br></iframe>## 实时显示<blockquote><p>单单是静态的页面可不行! 得让它动起来! – 当年被忽悠学习javascript的言语</p></blockquote><p>mou最基本的功能有什么?实时显示啊!</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mou</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> <span class="comment">// 定义状态,content为需要显示的markdown</span></span><br><span class="line"> <span class="built_in">this</span>.state = {</span><br><span class="line"> content: <span class="string">''</span>,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 当content改变时,更新状态(state)</span></span><br><span class="line"> handleContentChange = <span class="function">(<span class="params">content</span>) =></span> {</span><br><span class="line"> <span class="built_in">this</span>.setState({<span class="attr">content</span>: content});</span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"mou-app"</span>></span><br><span class="line"> <StatePanel/></span><br><span class="line"> <InputPanel content={<span class="built_in">this</span>.state.content} </span><br><span class="line"> handleContentChange={<span class="built_in">this</span>.handleContentChange}/></span><br><span class="line"> <RenderPanel content={<span class="built_in">this</span>.state.content}/></span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StatePanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"state-panel"</span>></div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InputPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> onChange() {</span><br><span class="line"> <span class="built_in">this</span>.props.handleContentChange(<span class="built_in">this</span>.refs.input.value);</span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <textarea id=<span class="string">"input-panel"</span> ref=<span class="string">'input'</span> </span><br><span class="line"> onChange={<span class="built_in">this</span>.onChange.bind(<span class="built_in">this</span>)}></textarea></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RenderPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="comment">// 显示框的内容和content绑定</span></span><br><span class="line"> <div id=<span class="string">"render-panel"</span>>{<span class="built_in">this</span>.props.content}</div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">React.render(<span class="xml"><span class="tag"><<span class="name">Mou</span>/></span></span>, <span class="built_in">document</span>.getElementById(<span class="string">'app'</span>));</span><br></pre></td></tr></table></figure><p>以上代码的意思是,<code>Mou</code>拥有一份content,当<code>InputPanel</code>的content改变(<code>onChange</code>)时,会相应的更改<code>Mou</code>的content(<code>this.props.handleContentChange</code>),进而修改<code>Mou</code>的state状态,从而触发react框架的默认行为:当state改变时,将触发所有与state绑定的props内容,即<code>RenderPanel</code>中的<code>this.props.content</code>;</p><p>此时,在<code>InputPanel</code>输入文字,便能在<code>RenderPanel</code>中同步显示;</p><iframe height="535" scrolling="no" src="//codepen.io/edeity/embed/vLyYRP/?height=535&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen style="width:100%">See the Pen <a href="http://codepen.io/edeity/pen/vLyYRP/" target="_blank" rel="external">vLyYRP</a> by 李健乐 (<a href="http://codepen.io/edeity" target="_blank" rel="external">@edeity</a>) on <a href="http://codepen.io" target="_blank" rel="external">CodePen</a>.<br></iframe>### Jquery?<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 以上内容转换成jquery的写法是:</span></span><br><span class="line">$(<span class="string">'#input-panel'</span>).change(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> value = $(<span class="built_in">this</span>).value();</span><br><span class="line"> $(<span class="string">'#render-panel'</span>).text(value);</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>WTF? 只需3句话?那我还用什么React,Jquery搞起!</p><p>别急,别急,这么想:当你的页面拥有div1,div2,div3,div4,div5等众多元素时,如</p><ul><li>当div1.props1改变时,修改div2.props1</li><li>当div2.props2改变时,修改div3.props2</li><li>当div4.props3改变时,修改div3.props3和div5.props3</li><li>当div1.props4改变时,修改div2~div5的props4</li></ul><p>于是你的jquery代码变成了</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">$(<span class="string">'.div1'</span>).change(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{$(<span class="string">'.div2'</span>)...})</span><br><span class="line">$(<span class="string">'.div2'</span>).change(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{$(<span class="string">'.div3'</span>)...})</span><br><span class="line">$(<span class="string">'.div4'</span>).change(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{$(<span class="string">'.div3'</span>)...$(<span class="string">'.div5'</span>)...})</span><br><span class="line">$(<span class="string">'.div5'</span>).change(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{$(<span class="string">'.div2'</span>)...$(<span class="string">'.div3'</span>)...$(<span class="string">'.div4'</span>)...($(<span class="string">'.div5'</span>))})</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>假如还有div6,div7,div8…呢?选择多了,整个人就蒙圈了。可能在change事件中,多选了div6,少选了div8等。</p><p>而react的做法是,子div的属性与父div绑定,当子属性(props)变更时,通知父状态(state),然后由react来通知所有与该<code>state</code>绑定的<code>props</code>,并判断是否需要重新渲染。</p><p>打个比方是:古时,当匈奴入侵时,当地的县令不需要通知哪个邻县来救火,哪个军营来增兵,而是一发奏折交给朝廷,由朝廷按照之前制定的御敌规章(state与props的绑定关系),来通知对应的单位火速增援;这样一来,既防止被入侵的县令随心所欲调动资源,乱了朝纲(<code>$('错误的div')</code>),也保证处于同一防线的所有单位都能收到通知(<code>react会通知所有与state绑定的props</code>)。</p><p>当然,这样做的前提是:奏折得像QQ一样快,还不能过分影响效率;否则,县都被攻陷了,奏折还没有到达朝廷。所幸的是,react的diff算法满足了这一点。</p><p>恰如react所描述:react就是用来解决__状态多__,__变更快__的大型app。</p><blockquote><p>We built <strong>React</strong> to solve one problem: <em>building large applications with data that changes over time</em>.</p></blockquote><h3 id="组件化"><a href="#组件化" class="headerlink" title="组件化"></a>组件化</h3><p>然而react还有一个明显优点,当我们想在别的地方重用<code><Mou></code>这个markdown编辑器时,需要怎么做?仅需在其他class的<code>render</code>方法里,<code>function render(){return <Mou/>}</code>,信手沾来!这就是react组件化的魅力,无需套用js的其他设计模式,代码已经被完美地封装到了一个伪html标签里。拿来即用,挥之即去!</p><p>至此, 我以我简陋的理解, 解析了 :<br>为什么要用50行react代码, 做5行html+3行jquery代码就可以完成的事, 大概可分为</p><ul><li>组件化, 便于重用(也有助于BUG定位)</li><li>状态管理, 面对众多状态变更时游刃有余</li></ul><p>当然, react提供给我们的不止这些, 比如官网讲述的 <code>virtual dom</code>, <code>data flow</code>,这些,我都是不清楚的(手动滑稽)</p><h2 id="其他功能"><a href="#其他功能" class="headerlink" title="其他功能"></a>其他功能</h2><p>然而,我只希望应用更拉风一点 。<br>说好的markdown工具, markdown呢? markdown呢?我特么的markdown呢?</p><h3 id="marked"><a href="#marked" class="headerlink" title="marked"></a>marked</h3><p>好吧, 看似拉风的工具, 其实都是建立在巨人的肩膀上的;<br>所以我很厚脸皮地用到了markdown编译器: <a target="_blank" rel="noopener" href="https://github.com/chjj/marked">marked</a>, 它能够将诸如</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 博主你不要脸</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>转化为</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><h1>博主你真的不要脸</h1></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>将</li></ul><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RenderPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"render-panel"</span>>{<span class="built_in">this</span>.props.content}</div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>更改为:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RenderPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> markup(str) {</span><br><span class="line"> <span class="keyword">return</span> {<span class="attr">__html</span>: marked(str)}<span class="comment">// 调用marked.js的marked方法</span></span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> <span class="comment">// 通过dangerouslySetInnerHTML,将渲染后的markdown文本赋值给RenderPanel</span></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"render-panel"</span> </span><br><span class="line"> dangerouslySetInnerHTML={<span class="built_in">this</span>.markup(<span class="built_in">this</span>.props.content)}></div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注:出于安全考虑,React不允许随便渲染html文档,必须显式调用<code>dangerouslySetInnerHTML</code></p><h3 id="markdown-css"><a href="#markdown-css" class="headerlink" title="markdown.css"></a>markdown.css</h3><p>虽不是github 代(tong)码(xing)托(jiao)管(you)平台的忠实粉丝, 没事逛(♂)逛(♂)github的习惯还是有的, 所以比较钟情于github markdown的css样式, 废话不多说, 偷! -> <a target="_blank" rel="noopener" href="https://github.com/sindresorhus/github-markdown-css">剽窃地址</a></p><ul><li>添加className</li></ul><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// class RenderPanel</span></span><br><span class="line"><div id=<span class="string">"render-panel"</span> </span><br><span class="line">dangerouslySetInnerHTML={<span class="built_in">this</span>.markup(<span class="built_in">this</span>.props.content)}></div></span><br></pre></td></tr></table></figure><p>更改为:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// class RenderPanel, 添加class样式</span></span><br><span class="line"><div id=<span class="string">"render-panel"</span> className=<span class="string">"markdown-body"</span> </span><br><span class="line">dangerouslySetInnerHTML={<span class="built_in">this</span>.markup(<span class="built_in">this</span>.props.content)}></div></span><br></pre></td></tr></table></figure><p>注意,因为<code>class</code>是js的关键字,所以在React jsx模板中,我们只能用<code>className</code>来替代<code>class</code></p><h3 id="同步滚动"><a href="#同步滚动" class="headerlink" title="同步滚动"></a>同步滚动</h3><p>至此, 我满怀喜悦地向我们班大神seal同学分享我的成果, 他也满怀喜悦地试了一下,发现不能同步滚动, 然后就没有然后了。T_T</p><p>其实实现同步滚动并不复杂,最简单的思路:</p><p>虽然<code>InputPanel</code>和<code>RenderPanel</code>两人高度不同,但百分比都是一样的啊(100%),所以滚动的百分比一样即可:</p><p>最后的js代码:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mou</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> <span class="comment">// 新增核心资料: scrollRatio,高度系数</span></span><br><span class="line"> <span class="built_in">this</span>.state = {</span><br><span class="line"> content: <span class="string">''</span>,</span><br><span class="line"> scrollRatio: <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> handleContentChange = <span class="function">(<span class="params">content</span>) =></span> {</span><br><span class="line"> <span class="built_in">this</span>.setState({<span class="attr">content</span>: content});</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//</span></span><br><span class="line"> handleScroll = <span class="function">(<span class="params">scrollRatio</span>) =></span> {</span><br><span class="line"> <span class="built_in">this</span>.setState({<span class="attr">scrollRatio</span>: scrollRatio});</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"mou-app"</span>></span><br><span class="line"> <StatePanel/></span><br><span class="line"> <InputPanel content={<span class="built_in">this</span>.state.content} </span><br><span class="line"> handleContentChange={<span class="built_in">this</span>.handleContentChange} </span><br><span class="line"> handleScroll={<span class="built_in">this</span>.handleScroll}/></span><br><span class="line"> <RenderPanel content={<span class="built_in">this</span>.state.content} </span><br><span class="line"> scrollRatio={<span class="built_in">this</span>.state.scrollRatio}/></span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StatePanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"state-panel"</span>></div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InputPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> onChange() {</span><br><span class="line"> <span class="built_in">this</span>.props.handleContentChange(<span class="built_in">this</span>.refs.input.value);</span><br><span class="line"> }</span><br><span class="line"> onScroll(event) {</span><br><span class="line"> <span class="comment">/* 通过参数event.nativeEvent.target获得真实的html对象, 即<textarea>;</span></span><br><span class="line"><span class="comment"> * 获取InputPanel此时的高度</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">var</span> target = event.nativeEvent.target;</span><br><span class="line"> <span class="comment">// 计算高度系数</span></span><br><span class="line"> <span class="keyword">var</span> scrollRatio </span><br><span class="line"> = target.scrollTop / (target.scrollHeight - target.clientHeight);</span><br><span class="line"> <span class="built_in">this</span>.props.handleScroll(scrollRatio);</span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <textarea id=<span class="string">"input-panel"</span> ref=<span class="string">'input'</span> </span><br><span class="line"> onChange={<span class="built_in">this</span>.onChange.bind(<span class="built_in">this</span>)} </span><br><span class="line"> onScroll={<span class="built_in">this</span>.onScroll.bind(<span class="built_in">this</span>)}></textarea></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">} </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RenderPanel</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> componentDidUpdate() {</span><br><span class="line"> <span class="keyword">var</span> render = <span class="built_in">this</span>.refs.render;</span><br><span class="line"> <span class="comment">// 对应RenderPanel的高度系数</span></span><br><span class="line"> render.scrollTop = <span class="built_in">this</span>.props.scrollRatio * </span><br><span class="line"> (render.scrollHeight - render.clientHeight);</span><br><span class="line"> }</span><br><span class="line"> markup(str) {</span><br><span class="line"> <span class="keyword">return</span> {<span class="attr">__html</span>: marked(str)}</span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div id=<span class="string">"render-panel"</span> ref=<span class="string">"render"</span> className=<span class="string">"markdown-body"</span></span><br><span class="line"> dangerouslySetInnerHTML={<span class="built_in">this</span>.markup(<span class="built_in">this</span>.props.content)}></span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">React.render(<span class="xml"><span class="tag"><<span class="name">Mou</span>/></span></span>, <span class="built_in">document</span>.getElementById(<span class="string">'app'</span>));</span><br></pre></td></tr></table></figure><h2 id="最终的结果"><a href="#最终的结果" class="headerlink" title="最终的结果"></a>最终的结果</h2><iframe height="535" scrolling="no" src="//codepen.io/edeity/embed/bEBGyw/?height=535&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen style="width:100%">See the Pen <a href="http://codepen.io/edeity/pen/bEBGyw/" target="_blank" rel="external">bEBGyw</a> by 李健乐 (<a href="http://codepen.io/edeity" target="_blank" rel="external">@edeity</a>) on <a href="http://codepen.io" target="_blank" rel="external">CodePen</a>.<br></iframe>## 尾声<p>很高兴你能在我的胡言乱语中坚持到了最后,末了,附上珍藏在我小抽屉的一句话,以此共勉:</p><blockquote><p>For me, I don’t want to get a job; I want to get invited to great jobs. I don’t want to go to work; I want to go to work with talented people. And I don’t want to be satisfied with knowing enough to do the work that needed to be done yesterday; I want to know how to do the work that will need to get done tomorrow.</p><p>对于我来说,我需要的不是工作,我想要的是被邀请去做一份牛逼的工作。我想要的不只是去干活而已,而是想和一群牛逼的人一起做牛逼的事。我不想仅仅满足于用已有的知识来完成现在的工作,而是希望掌握更多的知识来解决未来将会面对的问题。</p></blockquote><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><ul><li>吃我一记大Vuejs:看看别人家聪明孩子是怎么用vuejs编写的<a target="_blank" rel="noopener" href="http://cn.vuejs.org/examples/">极简的 Markdown 编辑器</a></li><li>更加友好的markdown编辑器<a target="_blank" rel="noopener" href="http://www.typora.io/">Typora</a>,在mac,window,linux下均有对应的安装包哦~强烈推荐</li></ul></div></div></div><div class="more section"><div class="pre"><a class="article-link" href="/js_closure.html"><i class="iconfont icon-right"></i> <span>JS中的闭包</span></a></div><div class="next"><a class="article-link" href="/js_prototype.html">理解Function和Object的原型关系 <i class="iconfont icon-right"></i></a></div></div></main></body><footer class="section fullscreen"><div class="footer-desc">Edeink © 2015-2022 · Powered by Hexo</div></footer><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script><script src="/public/js/init.js"></script></html>