1 Star 0 Fork 0

Warn / blog

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
atom.xml 391.26 KB
一键复制 编辑 原始数据 按行查看 历史
Warn 提交于 2018-07-22 22:02 . Site updated: 2018-07-22 22:02:56
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Warn&amp;Christina的博客</title>
<icon>https://www.gravatar.com/avatar/597d8656b53fbc8b405cee571e45b3fa</icon>
<subtitle>九流杂耍,蹒跚学步</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://wangen.github.io/"/>
<updated>2018-07-22T14:02:21.344Z</updated>
<id>https://wangen.github.io/</id>
<author>
<name>Warn</name>
<email>imwarn@163.com</email>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>CSS常见问题解决方案:不定高展示</title>
<link href="https://wangen.github.io/2018/07/22/css-solve-1/"/>
<id>https://wangen.github.io/2018/07/22/css-solve-1/</id>
<published>2018-07-22T13:58:40.000Z</published>
<updated>2018-07-22T14:02:21.344Z</updated>
<content type="html"><![CDATA[<h1 id="不定高列表展示错乱"><a href="#不定高列表展示错乱" class="headerlink" title="不定高列表展示错乱"></a>不定高列表展示错乱</h1><p>很多时候,我们需要依次成列展示一些列表内容比如图书、图片等等,我们通常会使用<code>float:left</code>,但是如果有多行多列内容时,由于上一行的<code>&lt;li&gt;</code>或者<code>&lt;div&gt;</code>等元素内容不定高(比如图书标题有一行或两行)导致高度不一致,会使下一行的排列出现错乱。</p><p><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/css-answer-101.jpg" alt="CSS不定高列表展示错乱示意图"></p><h2 id="1-1解决方案:"><a href="#1-1解决方案:" class="headerlink" title="1-1解决方案:"></a>1-1解决方案:</h2><h3 id="摒弃浮动,使用行内块元素"><a href="#摒弃浮动,使用行内块元素" class="headerlink" title="摒弃浮动,使用行内块元素"></a>摒弃浮动,使用行内块元素</h3><p>CSS样式中去掉<code>&lt;li&gt;</code>或者<code>&lt;div&gt;</code>元素定义的<code>float:left</code>,使用<code>display: inline-block</code>定义属性;但是默认元素都是底部对齐,如果想顶部对齐,我们可以设置<code>vertical-align: top;</code>;在某些场景下排列会有莫名边距产生,导致排列错乱,我们还需要对外层父元素设置<code>font-size:0</code>。</p><p>简单示例代码如下:<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--//html结构--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"rowWrap"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"heng"</span> <span class="attr">onclick</span>=<span class="string">"xq(201798)"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"imgWrap"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"/pic/201798/201798.jpg"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">"read-ellipsis-2"</span>&gt;</span>弃少归来<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"heng"</span> <span class="attr">onclick</span>=<span class="string">"xq(201798)"</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!--2/3/4/5/6元素--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></p><p>CSS主要代码示例:<br><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*CSS代码示例*/</span></span><br><span class="line"><span class="selector-class">.rowWrap</span> &#123;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">7.02rem</span>;</span><br><span class="line"> <span class="attribute">height</span>: auto;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.rowWrap</span> <span class="selector-class">.heng</span> &#123;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">2.1rem</span>;</span><br><span class="line"> <span class="attribute">height</span>: auto;</span><br><span class="line"> <span class="attribute">margin-left</span>: <span class="number">0.36rem</span>;</span><br><span class="line"> <span class="comment">/* float: left; */</span></span><br><span class="line"> <span class="attribute">display</span>: inline-block;</span><br><span class="line"> <span class="attribute">vertical-align</span>: top;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h3 id="坚持浮动方案"><a href="#坚持浮动方案" class="headerlink" title="坚持浮动方案"></a>坚持浮动方案</h3><p>这种方案也比较简单,只需要对每行(换行)的第一个元素增加设置<code>clear:left</code>,清除左侧浮动即可。</p><p>CSS主要代码示例:<br><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*CSS代码示例*/</span></span><br><span class="line"><span class="selector-class">.rowWrap</span> &#123;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">7.02rem</span>;</span><br><span class="line"> <span class="attribute">height</span>: auto;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.rowWrap</span> <span class="selector-class">.heng</span> &#123;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">2.1rem</span>;</span><br><span class="line"> <span class="attribute">height</span>: auto;</span><br><span class="line"> <span class="attribute">margin-left</span>: <span class="number">0.36rem</span>;</span><br><span class="line"> <span class="attribute">float</span>: left; </span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.rowWrap</span> <span class="selector-class">.heng</span><span class="selector-pseudo">:nth-child(3n+1)</span>&#123;</span><br><span class="line"> <span class="attribute">margin-left</span>:<span class="number">0</span>;</span><br><span class="line"> <span class="attribute">clear</span>:left;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
&lt;h1 id=&quot;不定高列表展示错乱&quot;&gt;&lt;a href=&quot;#不定高列表展示错乱&quot; class=&quot;headerlink&quot; title=&quot;不定高列表展示错乱&quot;&gt;&lt;/a&gt;不定高列表展示错乱&lt;/h1&gt;&lt;p&gt;很多时候,我们需要依次成列展示一些列表内容比如图书、图片等等,我们通常会使用&lt;cod
</summary>
<category term="CSS" scheme="https://wangen.github.io/categories/CSS/"/>
<category term="CSS" scheme="https://wangen.github.io/tags/CSS/"/>
</entry>
<entry>
<title>layui use 定义js外部引用函数</title>
<link href="https://wangen.github.io/2018/02/26/layui-use-1/"/>
<id>https://wangen.github.io/2018/02/26/layui-use-1/</id>
<published>2018-02-26T13:39:55.000Z</published>
<updated>2018-02-26T13:42:10.615Z</updated>
<content type="html"><![CDATA[<p>layui.use 加载layui.define 定义的模块,当外部 js 或 onclick调用 use 内部函数时,需要在 use 中定义 window 函数供外部引用 ,如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">layui.use([<span class="string">'layer'</span>,<span class="string">'form'</span>],<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> <span class="keyword">var</span> layer = layui.layer,</span><br><span class="line"> form = layer.form();</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">var</span> Test = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> <span class="comment">//不能被外部引用</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"call Test"</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="built_in">window</span>.Hello = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> <span class="comment">//可以被外部引用</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"call hello"</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> Test(); <span class="comment">//执行成功</span></span><br><span class="line"> Hello(); <span class="comment">//执行成功</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> Hello(); <span class="comment">//可以调用</span></span><br><span class="line"> Test(); <span class="comment">//提供未找到 Test</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>注:需要引用 layui.all.js或者layui.js</p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><blockquote><p>转载来源:<a href="http://blog.csdn.net/xcmonline/article/details/75647144" target="_blank" rel="noopener">layui use 定义js外部引用函数</a></p></blockquote>]]></content>
<summary type="html">
&lt;p&gt;layui.use 加载layui.define 定义的模块,当外部 js 或 onclick调用 use 内部函数时,需要在 use 中定义 window 函数供外部引用 ,如下:&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;tab
</summary>
<category term="layui" scheme="https://wangen.github.io/categories/layui/"/>
<category term="layui" scheme="https://wangen.github.io/tags/layui/"/>
</entry>
<entry>
<title>nodejs遇到的问题</title>
<link href="https://wangen.github.io/2018/02/25/web-node-1/"/>
<id>https://wangen.github.io/2018/02/25/web-node-1/</id>
<published>2018-02-25T15:27:38.000Z</published>
<updated>2018-02-25T15:52:17.740Z</updated>
<content type="html"><![CDATA[<h2 id="node插件"><a href="#node插件" class="headerlink" title="node插件"></a>node插件</h2><h3 id="1、nodemon"><a href="#1、nodemon" class="headerlink" title="1、nodemon"></a>1、nodemon</h3><blockquote><p>nodemon <a href="https://github.com/remy/nodemon" target="_blank" rel="noopener">https://github.com/remy/nodemon</a></p></blockquote><p>nodemon库是专门调试时候使用的,它会自动检测 node.js 代码的改动,然后帮你自动重启应用。在调试时可以完全用 nodemon 命令代替 node 命令。</p><blockquote><p>nodemon安装:<code>$ npm i -g nodemon</code><br>nodemon使用:<code>$ nodemon app.js</code> 替代node启动我们的应用</p></blockquote><h2 id="node一些问题备忘"><a href="#node一些问题备忘" class="headerlink" title="node一些问题备忘"></a>node一些问题备忘</h2><h2 id="常见错误"><a href="#常见错误" class="headerlink" title="常见错误"></a>常见错误</h2><p>转载自huansky的文章<a href="https://www.cnblogs.com/huansky/p/5524743.html" target="_blank" rel="noopener">nodejs遇到的问题</a>,在遇到问题6时找到此解决方法。</p><h3 id="1、express-session-deprecated-undefined-resave-option-provide-resave-option-app-js-49-9"><a href="#1、express-session-deprecated-undefined-resave-option-provide-resave-option-app-js-49-9" class="headerlink" title="1、express-session deprecated undefined resave option; provide resave option app.js:49:9"></a>1、express-session deprecated undefined <font color="#ff0000"><strong>resave option</strong></font>; provide resave option app.js:49:9</h3><p>express-session deprecated undefined <font color="#ff0000"><em>saveUninitialized option</em></font>; provide saveUninitialized option app.js:49:9<br>解答:其实我们可以看到斜体的部分就是导致错误的原因<br>解决办法:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">app.use(session(&#123;</span><br><span class="line"> secret: <span class="string">'keyboard cat'</span>, </span><br><span class="line"> cookie: &#123; <span class="attr">maxAge</span>: <span class="number">60000</span> &#125;, </span><br><span class="line"> resave: <span class="literal">true</span>, </span><br><span class="line"> saveUninitialized: <span class="literal">true</span> </span><br><span class="line">&#125;))</span><br></pre></td></tr></table></figure></p><p>具体参看<a href="https://github.com/expressjs/session#options" target="_blank" rel="noopener">https://github.com/expressjs/session#options</a></p><h3 id="2、failed-to-load-c-bson-extension-using-pure-js-version"><a href="#2、failed-to-load-c-bson-extension-using-pure-js-version" class="headerlink" title="2、failed to load c++ bson extension using pure js version"></a>2、failed to load c++ bson extension using pure js version</h3><p>在package.json修改 “connect-mongo”:“0.8.2” 运行npm install安装模块,打开app.js,添加以下代码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">app.use(session(&#123;</span><br><span class="line"> secret: settings.cookieSecret,</span><br><span class="line"> key: settings.db,<span class="comment">//cookie name</span></span><br><span class="line"> cookie: &#123;<span class="attr">maxAge</span>: <span class="number">1000</span> * <span class="number">60</span> * <span class="number">60</span> * <span class="number">24</span> * <span class="number">30</span>&#125;,<span class="comment">//30 days</span></span><br><span class="line"> store: <span class="keyword">new</span> MongoStore(&#123;</span><br><span class="line"> db: settings.db,</span><br><span class="line"> host: settings.host,</span><br><span class="line"> port: settings.port,</span><br><span class="line"> url: <span class="string">'mongodb://localhost/myblog'</span></span><br><span class="line"> &#125;),</span><br><span class="line"> proxy: <span class="literal">true</span>,</span><br><span class="line"> resave: <span class="literal">true</span>,</span><br><span class="line"> saveUninitialized: <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="3、怎么进入mongodb的shell"><a href="#3、怎么进入mongodb的shell" class="headerlink" title="3、怎么进入mongodb的shell"></a>3、怎么进入mongodb的shell</h3><p>打开一个命令行切换到 <code>mongodb/bin/</code> (保证数据库已打开的前提下),输入:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&gt;mongo</span><br><span class="line">&gt;show dbs</span><br><span class="line">&gt;use xxxx; (此处为你要选择的数据库)</span><br></pre></td></tr></table></figure></p><h3 id="4、在看nodejs权威指南的时候,我发现到了第7章,发现运行telnet-localhost-8431提示说这是外部命令;"><a href="#4、在看nodejs权威指南的时候,我发现到了第7章,发现运行telnet-localhost-8431提示说这是外部命令;" class="headerlink" title="4、在看nodejs权威指南的时候,我发现到了第7章,发现运行telnet localhost 8431提示说这是外部命令;"></a>4、在看nodejs权威指南的时候,我发现到了第7章,发现运行telnet localhost 8431提示说这是外部命令;</h3><p>解决办法:依次打开“开始”→“控制面板”→“打开或关闭Windows功能”,在打开的窗口处,寻找并勾选“Telnet客户端”,然后点击“确定”。顺利安装后,再在运行下输入此命令就OK了。</p><blockquote><p>1.开始–&gt;控制面板–&gt;程序和功能<br>2.左侧–&gt;打开或者关闭windows功能<br>3.找到Telnet客户端,选择安装</p></blockquote><h3 id="5、安装express后,此时会出现can-not-find-express,这是因为路径没有配置的原因。"><a href="#5、安装express后,此时会出现can-not-find-express,这是因为路径没有配置的原因。" class="headerlink" title="5、安装express后,此时会出现can not find express,这是因为路径没有配置的原因。"></a>5、安装express后,此时会出现can not find express,这是因为路径没有配置的原因。</h3><p>解决办法:</p><blockquote><p>计算机–&gt;属性–&gt;高级系统设置<br>高级–&gt;环境变量<br>添加NODE_PATH并设置路径为C:\Users\YOUR_USER_NAME\AppData\Roaming\npm\node_modules<br>将%NODE_PATH%添加到当前用户环境变量path中</p></blockquote><h3 id="6、mocha-init-出现错误-missing-required-argument-path"><a href="#6、mocha-init-出现错误-missing-required-argument-path" class="headerlink" title="6、mocha init 出现错误 missing required argument path"></a>6、mocha init 出现错误 missing required argument path</h3><p>文件夹 [^footnote] :lesson7-&gt;vendor,在vendor文件夹里运行mocha init出错,<br>解决办法:首先回到上一层文件夹lesson7;然后输入:<code>mocha init vendor</code></p><h3 id="7、npm-install-–save-与-npm-install-–save-dev"><a href="#7、npm-install-–save-与-npm-install-–save-dev" class="headerlink" title="7、npm install –save 与 npm install –save-dev"></a>7、npm install –save 与 npm install –save-dev</h3><p>一个放在package.json 的dependencies,一个放在devDependencies里面;<br>产品模式用dependencies,开发模式用devDep。test相关npm该放到dev里面。</p><p>[^footnote]: <a href="https://github.com/alsotang/node-lessons/tree/master/lesson7" target="_blank" rel="noopener">《Node.js 包教不包会》 – by alsotang</a> 。</p>]]></content>
<summary type="html">
&lt;h2 id=&quot;node插件&quot;&gt;&lt;a href=&quot;#node插件&quot; class=&quot;headerlink&quot; title=&quot;node插件&quot;&gt;&lt;/a&gt;node插件&lt;/h2&gt;&lt;h3 id=&quot;1、nodemon&quot;&gt;&lt;a href=&quot;#1、nodemon&quot; class=&quot;headerlink
</summary>
<category term="Node" scheme="https://wangen.github.io/categories/Node/"/>
<category term="node" scheme="https://wangen.github.io/tags/node/"/>
</entry>
<entry>
<title>node入门</title>
<link href="https://wangen.github.io/2018/02/25/book-node-1/"/>
<id>https://wangen.github.io/2018/02/25/book-node-1/</id>
<published>2018-02-25T15:25:26.000Z</published>
<updated>2018-02-25T15:51:07.309Z</updated>
<content type="html"><![CDATA[<h2 id="关于"><a href="#关于" class="headerlink" title="关于"></a>关于</h2><blockquote><p>作者: Manuel Kiessling<br>翻译: goddyzhao &amp; GrayZhang &amp; MondayChen</p><p>Github:<a href="https://github.com/manuelkiessling/nodebeginner.org/tree/master/code/application" target="_blank" rel="noopener">本书Github代码仓库</a><br>转载来源:<a href="https://www.nodebeginner.org/index-zh-cn.html" target="_blank" rel="noopener">《Node入门》</a><br>看云阅读:<a href="https://www.kancloud.cn/thinkphp/node-beginner/40725" target="_blank" rel="noopener">《Node入门》</a></p><p>社区:<a href="https://cnodejs.org/" target="_blank" rel="noopener">CNode:Node.js专业中文社区</a></p></blockquote><p>本书致力于教会你如何用Node.js来开发应用,过程中会传授你所有所需的“高级”JavaScript知识。本书绝不是一本“Hello World”的教程。</p><h3 id="状态"><a href="#状态" class="headerlink" title="状态"></a>状态</h3><p>你正在阅读的已经是本书的最终版。因此,只有当进行错误更正以及针对新版本Node.js的改动进行对应的修正时,才会进行更新。</p><p>本书中的代码案例都在Node.js 0.6.11版本中测试过,可以正确工作。</p><h3 id="读者对象"><a href="#读者对象" class="headerlink" title="读者对象"></a>读者对象</h3><p>本书最适合与我有相似技术背景的读者: 至少对一门诸如Ruby、Python、PHP或者Java这样面向对象的语言有一定的经验;对JavaScript处于初学阶段,并且完全是一个Node.js的新手。</p><p>这里指的适合对其他编程语言有一定经验的开发者,意思是说,本书不会对诸如数据类型、变量、控制结构等等之类非常基础的概念作介绍。要读懂本书,这些基础的概念我都默认你已经会了。</p><p>然而,本书还是会对JavaScript中的函数和对象作详细介绍,因为它们与其他同类编程语言中的函数和对象有很大的不同。</p><h3 id="本书结构"><a href="#本书结构" class="headerlink" title="本书结构"></a>本书结构</h3><p>读完本书之后,你将完成一个完整的web应用,该应用允许用户浏览页面以及上传文件。</p><p>当然了,应用本身并没有什么了不起的,相比为了实现该功能书写的代码本身,我们更关注的是如何创建一个框架来对我们应用的不同模块进行干净地剥离。 是不是很玄乎?稍后你就明白了。</p><p>本书先从介绍在Node.js环境中进行JavaScript开发和在浏览器环境中进行JavaScript开发的差异开始。</p><p>紧接着,会带领大家完成一个最传统的“Hello World”应用,这也是最基础的Node.js应用。</p><p>最后,会和大家讨论如何设计一个“真正”完整的应用,剖析要完成该应用需要实现的不同模块,并一步一步介绍如何来实现这些模块。</p><p>可以确保的是,在这过程中,大家会学到JavaScript中一些高级的概念、如何使用它们以及为什么使用这些概念就可以实现而其他编程语言中同类的概念就无法实现。</p><p>该应用所有的源代码都可以通过<a href="https://github.com/manuelkiessling/nodebeginner.org/tree/master/code/application" target="_blank" rel="noopener">本书Github代码仓库</a>.</p><h2 id="JavaScript与Node-js"><a href="#JavaScript与Node-js" class="headerlink" title="JavaScript与Node.js"></a>JavaScript与Node.js</h2><h3 id="JavaScript与你"><a href="#JavaScript与你" class="headerlink" title="JavaScript与你"></a>JavaScript与你</h3><p>抛开技术,我们先来聊聊你以及你和JavaScript的关系。本章的主要目的是想让你看看,对你而言是否有必要继续阅读后续章节的内容。</p><p>如果你和我一样,那么你很早就开始利用HTML进行“开发”,正因如此,你接触到了这个叫JavaScript有趣的东西,而对于JavaScript,你只会基本的操作——为web页面添加交互。</p><p>而你真正想要的是“干货”,你想要知道如何构建复杂的web站点 —— 于是,你学习了一种诸如PHP、Ruby、Java这样的编程语言,并开始书写“后端”代码。</p><p>与此同时,你还始终关注着JavaScript,随着通过一些对jQuery,Prototype之类技术的介绍,你慢慢了解到了很多JavaScript中的进阶技能,同时也感受到了JavaScript绝非仅仅是 <code>_window.open()_</code> 那么简单。</p><p>不过,这些毕竟都是前端技术,尽管当想要增强页面的时候,使用jQuery总让你觉得很爽,但到最后,你顶多是个<em>JavaScript用户</em>,而非<em>JavaScript开发者</em>。</p><p>然后,出现了Node.js,服务端的JavaScript,这有多酷啊?</p><p>于是,你觉得是时候该重新拾起既熟悉又陌生的JavaScript了。但是别急,写Node.js应用是一件事情;理解为什么它们要以它们书写的这种方式来书写则意味着——你要懂JavaScript。这次是玩真的了。</p><p>问题来了: 由于JavaScript真正意义上以两种,甚至可以说是三种形态存在(从中世纪90年代的作为对DHTML进行增强的小玩具,到像jQuery那样严格意义上的前端技术,一直到现在的服务端技术),因此,很难找到一个“正确”的方式来学习JavaScript,使得让你书写Node.js应用的时候感觉自己是在真正开发它而不仅仅是使用它。</p><p>因为这就是关键: 你本身已经是个有经验的开发者,你不想通过到处寻找各种解决方案(其中可能还有不正确的)来学习新的技术,你要确保自己是通过正确的方式来学习这项技术。</p><p>当然了,外面不乏很优秀的学习JavaScript的文章。但是,有的时候光靠那些文章是远远不够的。你需要的是指导。</p><p>本书的目标就是给你提供指导。</p><h3 id="简短申明"><a href="#简短申明" class="headerlink" title="简短申明"></a>简短申明</h3><p>业界有非常优秀的JavaScript程序员。而我并非其中一员。</p><p>我就是上一节中描述的那个我。我熟悉如何开发后端web应用,但是对“真正”的JavaScript以及Node.js,我都只是新手。我也只是最近学习了一些JavaScript的高级概念,并没有实践经验。</p><p>因此,本书并不是一本“从入门到精通”的书,更像是一本“从初级入门到高级入门”的书。</p><p>如果成功的话,那么本书就是我当初开始学习Node.js最希望拥有的教程。</p><h3 id="服务端JavaScript"><a href="#服务端JavaScript" class="headerlink" title="服务端JavaScript"></a>服务端JavaScript</h3><p>JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文,它定义了使用JavaScript可以做什么,但并没有“说”太多关于JavaScript语言本身可以做什么。事实上,JavaScript是一门“完整”的语言: 它可以使用在不同的上下文中,其能力与其他同类语言相比有过之而无不及。</p><p>Node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码。</p><p>要实现在后台运行JavaScript代码,代码需要先被解释然后正确的执行。Node.js的原理正是如此,它使用了Google的V8虚拟机(Google的Chrome浏览器使用的JavaScript执行环境),来解释和执行JavaScript代码。</p><p>除此之外,伴随着Node.js的还有许多有用的模块,它们可以简化很多重复的劳作,比如向终端输出字符串。</p><p>因此,Node.js事实上既是一个运行时环境,同时又是一个库。</p><p>要使用Node.js,首先需要进行安装。关于如何安装Node.js,这里就不赘述了,可以直接参考<a href="https://github.com/nodejs/node-v0.x-archive/wiki/Installation" target="_blank" rel="noopener">官方的安装指南</a>。<br>安装完成后,继续回来阅读本书下面的内容。</p><h3 id="“Hello-World”"><a href="#“Hello-World”" class="headerlink" title="“Hello World”"></a>“Hello World”</h3><p>好了,“废话”不多说了,马上开始我们第一个Node.js应用:“Hello World”。</p><p>打开你最喜欢的编辑器,创建一个<code>helloworld.js</code> 文件。我们要做就是向STDOUT输出“Hello World”,如下是实现该功能的代码:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">"Hello World"</span>);</span><br></pre></td></tr></table></figure></p><p>保存该文件,并通过Node.js来执行:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node helloworld.js</span><br></pre></td></tr></table></figure></p><p>正常的话,就会在终端输出<code>Hello World</code> 。</p><p>好吧,我承认这个应用是有点无趣,那么下面我们就来点“干货”。</p><h2 id="一个完整的基于Node-js的web应用"><a href="#一个完整的基于Node-js的web应用" class="headerlink" title="一个完整的基于Node.js的web应用"></a>一个完整的基于Node.js的web应用</h2><h3 id="用例"><a href="#用例" class="headerlink" title="用例"></a>用例</h3><p>我们来把目标设定得简单点,不过也要够实际才行:</p><p>用户可以通过浏览器使用我们的应用。<br>当用户请求 <code>http://domain8/start</code> 时,可以看到一个欢迎页面,页面上有一个文件上传的表单。<br>用户可以选择一个图片并提交表单,随后文件将被上传到<code>http://domain/upload</code> ,该页面完成上传后会把图片显示在页面上。<br>差不多了,你现在也可以去Google一下,找点东西乱搞一下来完成功能。但是我们现在先不做这个。</p><p>更进一步地说,在完成这一目标的过程中,我们不仅仅需要基础的代码而不管代码是否优雅。我们还要对此进行抽象,来寻找一种适合构建更为复杂的Node.js应用的方式。</p><h3 id="应用不同模块分析"><a href="#应用不同模块分析" class="headerlink" title="应用不同模块分析"></a>应用不同模块分析</h3><p>我们来分解一下这个应用,为了实现上文的用例,我们需要实现哪些部分呢?</p><ul><li>我们需要提供Web页面,因此需要一个<em>HTTP服务器</em></li><li>对于不同的请求,根据请求的URL,我们的服务器需要给予不同的响应,因此我们需要一个<em>路由</em>,用于把请求对应到请求处理程序(request handler)</li><li>当请求被服务器接收并通过路由传递之后,需要可以对其进行处理,因此我们需要最终的<em>请求处理程序</em></li><li>路由还应该能处理POST数据,并且把数据封装成更友好的格式传递给请求处理入程序,因此需要<em>请求数据处理功能</em></li><li>我们不仅仅要处理URL对应的请求,还要把内容显示出来,这意味着我们需要一些<em>视图逻辑</em> 供请求处理程序使用,以便将内容发送给用户的浏览器</li><li>最后,用户需要上传图片,所以我们需要<em>上传处理功能</em>来处理这方面的细节</li></ul><p>我们先来想想,使用PHP的话我们会怎么构建这个结构。一般来说我们会用一个Apache HTTP服务器并配上mod_php5模块。<br>从这个角度看,整个“接收HTTP请求并提供Web页面”的需求根本不需要PHP来处理。<br>不过对Node.js来说,概念完全不一样了。使用Node.js时,我们不仅仅在实现一个应用,同时还实现了整个HTTP服务器。事实上,我们的Web应用以及对应的Web服务器基本上是一样的。</p><p>听起来好像有一大堆活要做,但随后我们会逐渐意识到,对Node.js来说这并不是什么麻烦的事。</p><p>现在我们就来开始实现之路,先从第一个部分–HTTP服务器着手。</p><h2 id="构建应用的模块"><a href="#构建应用的模块" class="headerlink" title="构建应用的模块"></a>构建应用的模块</h2><h3 id="一个基础的HTTP服务器"><a href="#一个基础的HTTP服务器" class="headerlink" title="一个基础的HTTP服务器"></a>一个基础的HTTP服务器</h3><p>当我准备开始写我的第一个“真正的”Node.js应用的时候,我不但不知道怎么写Node.js代码,也不知道怎么组织这些代码。<br>我应该把所有东西都放进一个文件里吗?网上有很多教程都会教你把所有的逻辑都放进一个用Node.js写的基础HTTP服务器里。但是如果我想加入更多的内容,同时还想保持代码的可读性呢?<br>实际上,只要把不同功能的代码放入不同的模块中,保持代码分离还是相当简单的。</p><p>这种方法允许你拥有一个干净的主文件(main file),你可以用Node.js执行它;同时你可以拥有干净的模块,它们可以被主文件和其他的模块调用。</p><p>那么,现在我们来创建一个用于启动我们的应用的主文件,和一个保存着我们的HTTP服务器代码的模块。</p><p>在我的印象里,把主文件叫做<em>index.js</em>或多或少是个标准格式。把服务器模块放进叫<em>server.js</em>的文件里则很好理解。</p><p>让我们先从服务器模块开始。在你的项目的根目录下创建一个叫<em>server.js</em>的文件,并写入以下代码:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;).listen(<span class="number">8888</span>);</span><br></pre></td></tr></table></figure></p><p>搞定!你刚刚完成了一个可以工作的HTTP服务器。为了证明这一点,我们来运行并且测试这段代码。首先,用Node.js执行你的脚本:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node server.js</span><br></pre></td></tr></table></figure></p><p>接下来,打开浏览器访问 <a href="http://localhost:8888/,你会看到一个写着“Hello" target="_blank" rel="noopener">http://localhost:8888/,你会看到一个写着“Hello</a> World”的网页。<br>这很有趣,不是吗?让我们先来谈谈HTTP服务器的问题,把如何组织项目的事情先放一边吧,你觉得如何?我保证之后我们会解决那个问题的。</p><h3 id="分析HTTP服务器"><a href="#分析HTTP服务器" class="headerlink" title="分析HTTP服务器"></a>分析HTTP服务器</h3><p>那么接下来,让我们分析一下这个HTTP服务器的构成。</p><p>第一行<em>请求(require)</em> Node.js自带的 http 模块,并且把它赋值给 http 变量。<br>接下来我们调用http模块提供的函数: createServer 。这个函数会返回一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数,指定这个HTTP服务器监听的端口号。<br>咱们暂时先不管 http.createServer 的括号里的那个函数定义。<br>我们本来可以用这样的代码来启动服务器并侦听8888端口:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> server = http.createServer();</span><br><span class="line">server.listen(<span class="number">8888</span>);</span><br></pre></td></tr></table></figure></p><p>这段代码只会启动一个侦听8888端口的服务器,它不做任何别的事情,甚至连请求都不会应答。</p><p>最有趣(而且,如果你之前习惯使用一个更加保守的语言,比如PHP,它还很奇怪)的部分是 createSever() 的第一个参数,一个函数定义。<br>实际上,这个函数定义是 createServer() 的第一个也是唯一一个参数。因为在JavaScript中,函数和其他变量一样都是可以被传递的。</p><h3 id="进行函数传递"><a href="#进行函数传递" class="headerlink" title="进行函数传递"></a>进行函数传递</h3><p>举例来说,你可以这样做:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">say</span>(<span class="params">word</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(word);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">execute</span>(<span class="params">someFunction, value</span>) </span>&#123;</span><br><span class="line"> someFunction(value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">execute(say, <span class="string">"Hello"</span>);</span><br></pre></td></tr></table></figure></p><p>请仔细阅读这段代码!在这里,我们把 say 函数作为<em>execute</em>函数的第一个变量进行了传递。这里传递的不是 say 的返回值,而是 say 本身!<br>这样一来, say 就变成了<em>execute</em> 中的本地变量 someFunction ,execute可以通过调用 someFunction() (带括号的形式)来使用 say 函数。<br>当然,因为 say 有一个变量, execute 在调用 someFunction 时可以传递这样一个变量。<br>我们可以,就像刚才那样,用它的名字把一个函数作为变量传递。但是我们不一定要绕这个“先定义,再传递”的圈子,我们可以直接在另一个函数的括号中定义和传递这个函数:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">execute</span>(<span class="params">someFunction, value</span>) </span>&#123;</span><br><span class="line"> someFunction(value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">execute(<span class="function"><span class="keyword">function</span>(<span class="params">word</span>)</span>&#123; <span class="built_in">console</span>.log(word) &#125;, <span class="string">"Hello"</span>);</span><br></pre></td></tr></table></figure></p><p>我们在 execute 接受第一个参数的地方直接定义了我们准备传递给 execute 的函数。<br>用这种方式,我们甚至不用给这个函数起名字,这也是为什么它被叫做<code>匿名函数</code> 。<br>这是我们和我所认为的“进阶”JavaScript的第一次亲密接触,不过我们还是得循序渐进。现在,我们先接受这一点:在JavaScript中,一个函数可以作为另一个函数接收一个参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。</p><h3 id="函数传递是如何让HTTP服务器工作的"><a href="#函数传递是如何让HTTP服务器工作的" class="headerlink" title="函数传递是如何让HTTP服务器工作的"></a>函数传递是如何让HTTP服务器工作的</h3><p>带着这些知识,我们再来看看我们简约而不简单的HTTP服务器:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;).listen(<span class="number">8888</span>);</span><br></pre></td></tr></table></figure></p><p>现在它看上去应该清晰了很多:我们向 createServer 函数传递了一个匿名函数。<br>用这样的代码也可以达到同样的目的:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br></pre></td></tr></table></figure></p><p>也许现在我们该问这个问题了:我们为什么要用这种方式呢?</p><h3 id="基于事件驱动的回调"><a href="#基于事件驱动的回调" class="headerlink" title="基于事件驱动的回调"></a>基于事件驱动的回调</h3><p>这个问题可不好回答(至少对我来说),不过这是Node.js原生的工作方式。它是事件驱动的,这也是它为什么这么快的原因。</p><p>你也许会想花点时间读一下Felix Geisendörfer的大作<a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb" target="_blank" rel="noopener">Understanding node.js</a>,它介绍了一些背景知识。<br>这一切都归结于<code>“Node.js是事件驱动的”</code> 这一事实。好吧,其实我也不是特别确切的了解这句话的意思。不过我会试着解释,为什么它对我们用Node.js写网络应用(Web based application)是有意义的。</p><p>当我们使用 http.createServer 方法的时候,我们当然不只是想要一个侦听某个端口的服务器,我们还想要它在服务器收到一个HTTP请求的时候做点什么。<br>问题是,这是异步的:请求任何时候都可能到达,但是我们的服务器却跑在一个单进程中。</p><p>写PHP应用的时候,我们一点也不为此担心:任何时候当有请求进入的时候,网页服务器(通常是Apache)就为这一请求新建一个进程,并且开始从头到尾执行相应的PHP脚本。</p><p>那么在我们的Node.js程序中,当一个新的请求到达8888端口的时候,我们怎么控制流程呢?</p><p>嗯,这就是Node.js/JavaScript的事件驱动设计能够真正帮上忙的地方了——虽然我们还得学一些新概念才能掌握它。让我们来看看这些概念是怎么应用在我们的服务器代码里的。</p><p>我们创建了服务器,并且向创建它的方法传递了一个函数。无论何时我们的服务器收到一个请求,这个函数就会被调用。</p><p>我们不知道这件事情什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。至于它是被预先定义的函数还是匿名函数,就无关紧要了。</p><p>这个就是传说中的<code>回调</code> 。我们给某个方法传递了一个函数,这个方法在有相应事件发生时调用这个函数来进行<em>回调</em>。<br>至少对我来说,需要一些功夫才能弄懂它。你如果还是不太确定的话就再去读读Felix的博客文章。</p><p>让我们再来琢磨琢磨这个新概念。我们怎么证明,在创建完服务器之后,即使没有HTTP请求进来、我们的回调函数也没有被调用的情况下,我们的代码还继续有效呢?我们试试这个:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request received."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br></pre></td></tr></table></figure></p><p>注意:在<code>onRequest</code> (我们的回调函数)触发的地方,我用<code>console.log</code> 输出了一段文本。在HTTP服务器开始工作<em>之后</em>,也输出一段文本。<br>当我们与往常一样,运行它<em>node server.js</em>时,它会马上在命令行上输出“Server has started.”。当我们向服务器发出请求(在浏览器访问<a href="http://localhost:8888/),“Request" target="_blank" rel="noopener">http://localhost:8888/),“Request</a> received.”这条消息就会在命令行中出现。<br>这就是事件驱动的异步服务器端JavaScript和它的回调啦!</p><p>(请注意,当我们在服务器访问网页时,我们的服务器可能会输出两次“Request received.”。那是因为大部分服务器都会在你访问 <a href="http://localhost:8888" target="_blank" rel="noopener">http://localhost:8888</a> /时尝试读取 <a href="http://localhost:8888/favicon.ico" target="_blank" rel="noopener">http://localhost:8888/favicon.ico</a> )</p><h3 id="服务器是如何处理请求的"><a href="#服务器是如何处理请求的" class="headerlink" title="服务器是如何处理请求的"></a>服务器是如何处理请求的</h3><p>好的,接下来我们简单分析一下我们服务器代码中剩下的部分,也就是我们的回调函数 onRequest() 的主体部分。<br>当回调启动,我们的 onRequest() 函数被触发的时候,有两个参数被传入:request 和 response 。<br>它们是对象,你可以使用它们的方法来处理HTTP请求的细节,并且响应请求(比如向发出请求的浏览器发回一些东西)。</p><p>所以我们的代码就是:当收到请求时,使用 <em>response.writeHead()</em> 函数发送一个HTTP状态200和HTTP头的内容类型(content-type),使用 <em>response.write()</em> 函数在HTTP相应主体中发送文本“Hello World”。<br>最后,我们调用 <em>response.end()</em> 完成响应。<br>目前来说,我们对请求的细节并不在意,所以我们没有使用 <em>request</em> 对象。</p><h3 id="服务端的模块放在哪里"><a href="#服务端的模块放在哪里" class="headerlink" title="服务端的模块放在哪里"></a>服务端的模块放在哪里</h3><p>OK,就像我保证过的那样,我们现在可以回到我们如何组织应用这个问题上了。我们现在在 <em>server.js</em> 文件中有一个非常基础的HTTP服务器代码,而且我提到通常我们会有一个叫 <em>index.js</em> 的文件去调用应用的其他模块(比如 <em>server.js</em> 中的HTTP服务器模块)来引导和启动应用。<br>我们现在就来谈谈怎么把 <em>server.js</em> 变成一个真正的Node.js模块,使它可以被我们(还没动工)的 <em>index.js</em> 主文件使用。<br>也许你已经注意到,我们已经在代码中使用了模块了。像这样:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">http.createServer(...);</span><br></pre></td></tr></table></figure></p><p>Node.js中自带了一个叫做“http”的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量。</p><p>这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象。<br>给这种本地变量起一个和模块名称一样的名字是一种惯例,但是你也可以按照自己的喜好来:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> foo = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">foo.createServer(...);</span><br></pre></td></tr></table></figure></p><p>很好,怎么使用Node.js内部模块已经很清楚了。我们怎么创建自己的模块,又怎么使用它呢?</p><p>等我们把 <em>server.js</em> 变成一个真正的模块,你就能搞明白了。<br>事实上,我们不用做太多的修改。把某段代码变成模块意味着我们需要把我们希望提供其功能的部分 <em>导出</em> 到请求这个模块的脚本。<br>目前,我们的HTTP服务器需要导出的功能非常简单,因为请求服务器模块的脚本仅仅是需要启动服务器而已。</p><p>我们把我们的服务器脚本放到一个叫做 <em>start</em> 的函数里,然后我们会导出这个函数。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123; </span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request received."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end(); </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>这样,我们现在就可以创建我们的主文件 <em>index.js</em> 并在其中启动我们的HTTP了,虽然服务器的代码还在 <em>server.js</em> 中。<br>创建 <em>index.js</em> 文件并写入以下内容:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> server = <span class="built_in">require</span>(<span class="string">"./server"</span>);</span><br><span class="line"></span><br><span class="line">server.start();</span><br></pre></td></tr></table></figure></p><p>正如你所看到的,我们可以像使用任何其他的内置模块一样使用server模块:请求这个文件并把它指向一个变量,其中已导出的函数就可以被我们使用了。</p><p>好了。我们现在就可以从我们的主要脚本启动我们的的应用了,而它还是老样子:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node index.js</span><br></pre></td></tr></table></figure></p><p>非常好,我们现在可以把我们的应用的不同部分放入不同的文件里,并且通过生成模块的方式把它们连接到一起了。</p><p>我们仍然只拥有整个应用的最初部分:我们可以接收HTTP请求。但是我们得做点什么——对于不同的URL请求,服务器应该有不同的反应。</p><p>对于一个非常简单的应用来说,你可以直接在回调函数 <em>onRequest()</em> 中做这件事情。不过就像我说过的,我们应该加入一些抽象的元素,让我们的例子变得更有趣一点儿。<br>处理不同的HTTP请求在我们的代码中是一个不同的部分,叫做“路由选择”——那么,我们接下来就创造一个叫做<code>路由</code> 的模块吧。</p><h3 id="如何来进行请求的“路由”"><a href="#如何来进行请求的“路由”" class="headerlink" title="如何来进行请求的“路由”"></a>如何来进行请求的“路由”</h3><p>我们要为路由提供请求的URL和其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码(这里“代码”对应整个应用的第三部分:一系列在接收到请求时真正工作的处理程序)。</p><p>因此,我们需要查看HTTP请求,从中提取出请求的URL以及GET/POST参数。这一功能应当属于路由还是服务器(甚至作为一个模块自身的功能)确实值得探讨,但这里暂定其为我们的HTTP服务器的功能。</p><p>我们需要的所有数据都会包含在request对象中,该对象作为<em>onRequest()</em>回调函数的第一个参数传递。但是为了解析这些数据,我们需要额外的Node.JS模块,它们分别是<em>url</em>和<em>querystring</em>模块。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"> url.parse(string).query</span><br><span class="line"> |</span><br><span class="line"> url.parse(string).pathname |</span><br><span class="line"> | |</span><br><span class="line"> | |</span><br><span class="line"> ------ -------------------</span><br><span class="line">http://localhost:8888/start?foo=bar&amp;hello=world</span><br><span class="line"> --- -----</span><br><span class="line"> | |</span><br><span class="line"> | |</span><br><span class="line"> querystring(string)[<span class="string">"foo"</span>] |</span><br><span class="line"> |</span><br><span class="line"> querystring(string)[<span class="string">"hello"</span>]</span><br></pre></td></tr></table></figure></p><p>当然我们也可以用<em>querystring</em>模块来解析POST请求体中的参数,稍后会有演示。</p><p>现在我们来给<em>onRequest()</em>函数加上一些逻辑,用来找出浏览器请求的URL路径:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end(); </span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>好了,我们的应用现在可以通过请求的URL路径来区别不同请求了–这使我们得以使用(还未完成的)路由来将请求以URL路径为基准映射到处理程序上。</p><p>在我们所要构建的应用中,这意味着来自<em>/start</em>和<em>/upload</em> 的请求可以使用不同的代码来处理。稍后我们将看到这些内容是如何整合到一起的。</p><p>现在我们可以来编写路由了,建立一个名为<em>router.js</em>的文件,添加以下内容:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">pathname</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>如你所见,这段代码什么也没干,不过对于现在来说这是应该的。在添加更多的逻辑以前,我们先来看看如何把路由和服务器整合起来。</p><p>我们的服务器应当知道路由的存在并加以有效利用。我们当然可以通过硬编码的方式将这一依赖项绑定到服务器上,但是其它语言的编程经验告诉我们这会是一件非常痛苦的事,因此我们将使用依赖注入的方式较松散地添加路由模块(你可以读读<a href="https://martinfowler.com/articles/injection.html" target="_blank" rel="noopener">Martin Fowlers</a>关于依赖注入的大作来作为背景知识)。<br>首先,我们来扩展一下服务器的<em>start()</em>函数,以便将路由函数作为参数传递过去:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route</span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123;</span><br><span class="line"> <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"></span><br><span class="line"> route(pathname);</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>同时,我们会相应扩展<em>index.js</em>,使得路由函数可以被注入到服务器中:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> server = <span class="built_in">require</span>(<span class="string">"./server"</span>);</span><br><span class="line"><span class="keyword">var</span> router = <span class="built_in">require</span>(<span class="string">"./router"</span>);</span><br><span class="line"></span><br><span class="line">server.start(router.route);</span><br></pre></td></tr></table></figure></p><p>在这里,我们传递的函数依旧什么也没做。</p><p>如果现在启动应用<em>(node index.js,始终记得这个命令行)</em>,随后请求一个URL,你将会看到应用输出相应的信息,这表明我们的HTTP服务器已经在使用路由模块了,并会将请求的路径传递给路由:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bash$ node index.js</span><br><span class="line">Request <span class="keyword">for</span> /foo received.</span><br><span class="line">About to route a request <span class="keyword">for</span> /foo</span><br></pre></td></tr></table></figure></p><p>(以上输出已经去掉了比较烦人的/favicon.ico请求相关的部分)。</p><h3 id="行为驱动执行"><a href="#行为驱动执行" class="headerlink" title="行为驱动执行"></a>行为驱动执行</h3><p>请允许我再次脱离主题,在这里谈一谈函数式编程。</p><p>将函数作为参数传递并不仅仅出于技术上的考量。对软件设计来说,这其实是个哲学问题。想想这样的场景:在index文件中,我们可以将<em>router</em>对象传递进去,服务器随后可以调用这个对象的<em>route</em>函数。</p><p>就像这样,我们传递一个东西,然后服务器利用这个东西来完成一些事。嗨那个叫路由的东西,能帮我把这个路由一下吗?</p><p>但是服务器其实不需要这样的东西。它只需要把事情做完就行,其实为了把事情做完,你根本不需要东西,你需要的是动作。也就是说,你不需要<em>名词</em>,你需要<em>动词</em>。</p><p>理解了这个概念里最核心、最基本的思想转换后,我自然而然地理解了函数编程。</p><p>我是在读了Steve Yegge的大作<a href="http://lcwangchao.github.io/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/2012/07/02/excution_in_the_kingdom_of_nouns/" target="_blank" rel="noopener">名词王国中的死刑</a>之后理解函数编程。你也去读一读这本书吧,真的。这是曾给予我阅读的快乐的关于软件的书籍之一。</p><h3 id="路由给真正的请求处理程序"><a href="#路由给真正的请求处理程序" class="headerlink" title="路由给真正的请求处理程序"></a>路由给真正的请求处理程序</h3><p>回到正题,现在我们的HTTP服务器和请求路由模块已经如我们的期望,可以相互交流了,就像一对亲密无间的兄弟。</p><p>当然这还远远不够,路由,顾名思义,是指我们要针对不同的URL有不同的处理方式。例如处理<em>/start</em>的“业务逻辑”就应该和处理<em>/upload</em>的不同。</p><p>在现在的实现下,路由过程会在路由模块中“结束”,并且路由模块并不是真正针对请求“采取行动”的模块,否则当我们的应用程序变得更为复杂时,将无法很好地扩展。</p><p>我们暂时把作为路由目标的函数称为请求处理程序。现在我们不要急着来开发路由模块,因为如果请求处理程序没有就绪的话,再怎么完善路由模块也没有多大意义。</p><p>应用程序需要新的部件,因此加入新的模块 – 已经无需为此感到新奇了。我们来创建一个叫做<em>requestHandlers</em>的模块,并对于每一个请求处理程序,添加一个占位用函数,随后将这些函数作为模块的方法导出:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">function start() &#123;</span><br><span class="line"> console.log(&quot;Request handler &apos;start&apos; was called.&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">function upload() &#123;</span><br><span class="line"> console.log(&quot;Request handler &apos;upload&apos; was called.&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>这样我们就可以把请求处理程序和路由模块连接起来,让路由“有路可寻”。</p><p>在这里我们得做个决定:是将<em>requestHandlers</em>模块硬编码到路由里来使用,还是再添加一点依赖注入?虽然和其他模式一样,依赖注入不应该仅仅为使用而使用,但在现在这个情况下,使用依赖注入可以让路由和请求处理程序之间的耦合更加松散,也因此能让路由的重用性更高。</p><p>这意味着我们得将请求处理程序从服务器传递到路由中,但感觉上这么做更离谱了,我们得一路把这堆请求处理程序从我们的主文件传递到服务器中,再将之从服务器传递到路由。</p><p>那么我们要怎么传递这些请求处理程序呢?别看现在我们只有2个处理程序,在一个真实的应用中,请求处理程序的数量会不断增加,我们当然不想每次有一个新的URL或请求处理程序时,都要为了在路由里完成请求到处理程序的映射而反复折腾。除此之外,在路由里有一大堆<em>if request == x then call handler y</em>也使得系统丑陋不堪。</p><p>仔细想想,有一大堆东西,每个都要映射到一个字符串(就是请求的URL)上?似乎关联数组(associative array)能完美胜任。</p><p>不过结果有点令人失望,JavaScript没提供关联数组 – 也可以说它提供了?事实上,在JavaScript中,真正能提供此类功能的是它的对象。</p><p>在这方面,<a href="http://msdn.microsoft.com/en-us/magazine/cc163419.aspx有一个不错的介绍,我在此摘录一段:" target="_blank" rel="noopener">http://msdn.microsoft.com/en-us/magazine/cc163419.aspx有一个不错的介绍,我在此摘录一段:</a></p><blockquote><p>在C++或C#中,当我们谈到对象,指的是类或者结构体的实例。对象根据他们实例化的模板(就是所谓的类),会拥有不同的属性和方法。但在JavaScript里对象不是这个概念。在JavaScript中,对象就是一个键/值对的集合 – 你可以把JavaScript的对象想象成一个键为字符串类型的字典。</p></blockquote><p>但如果JavaScript的对象仅仅是<code>键/值对</code> 的集合,它又怎么会拥有方法呢?好吧,这里的值可以是字符串、数字或者……函数!</p><p>好了,最后再回到代码上来。现在我们已经确定将一系列请求处理程序通过一个对象来传递,并且需要使用松耦合的方式将这个对象注入到<em>route()</em>函数中。</p><p>我们先将这个对象引入到主文件<em>index.js</em>中:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> server = <span class="built_in">require</span>(<span class="string">"./server"</span>);</span><br><span class="line"><span class="keyword">var</span> router = <span class="built_in">require</span>(<span class="string">"./router"</span>);</span><br><span class="line"><span class="keyword">var</span> requestHandlers = <span class="built_in">require</span>(<span class="string">"./requestHandlers"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> handle = &#123;&#125;</span><br><span class="line">handle[<span class="string">"/"</span>] = requestHandlers.start;</span><br><span class="line">handle[<span class="string">"/start"</span>] = requestHandlers.start;</span><br><span class="line">handle[<span class="string">"/upload"</span>] = requestHandlers.upload;</span><br><span class="line"></span><br><span class="line">server.start(router.route, handle);</span><br></pre></td></tr></table></figure></p><p>虽然<em>handle</em>并不仅仅是一个“东西”(一些请求处理程序的集合),我还是建议以一个动词作为其命名,这样做可以让我们在路由中使用更流畅的表达式,稍后会有说明。</p><p>正如所见,将不同的URL映射到相同的请求处理程序上是很容易的:只要在对象中添加一个键为<code>&quot;/&quot;</code> 的属性,对应<em>requestHandlers.start</em>即可,这样我们就可以干净简洁地配置<code>/start</code> 和<code>/</code> 的请求都交由<em>start</em>这一处理程序处理。<br>在完成了对象的定义后,我们把它作为额外的参数传递给服务器,为此将<em>server.js</em>修改如下:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route, handle</span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"></span><br><span class="line"> route(handle, pathname);</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello World"</span>);</span><br><span class="line"> response.end(); &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>这样我们就在<em>start()</em>函数里添加了<em>handle</em>参数,并且把handle对象作为第一个参数传递给了<em>route()</em>回调函数。</p><p>然后我们相应地在<em>route.js</em>文件中修改<em>route()</em>函数:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">handle, pathname</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname); </span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> handle[pathname] === <span class="string">'function'</span>) &#123;</span><br><span class="line"> handle[pathname](); &#125; </span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"No request handler found for "</span> + pathname); </span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>通过以上代码,我们首先检查给定的路径对应的请求处理程序是否存在,如果存在的话直接调用相应的函数。我们可以用从关联数组中获取元素一样的方式从传递的对象中获取请求处理函数,因此就有了简洁流畅的形如<code>handle[pathname]();</code> 的表达式,这个感觉就像在前方中提到的那样:“<em>嗨,请帮我处理了这个路径</em>”。<br>有了这些,我们就把服务器、路由和请求处理程序在一起了。现在我们启动应用程序并在浏览器中访问<em><a href="http://localhost:8888/start" target="_blank" rel="noopener">http://localhost:8888/start</a></em>,以下日志可以说明系统调用了正确的请求处理程序:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Server has started.</span><br><span class="line">Request <span class="keyword">for</span> /start received.</span><br><span class="line">About to route a request <span class="keyword">for</span> /start</span><br><span class="line">Request handler <span class="string">'start'</span> was called.</span><br></pre></td></tr></table></figure></p><p>并且在浏览器中打开<em><a href="http://localhost:8888/" target="_blank" rel="noopener">http://localhost:8888/</a></em>可以看到这个请求同样被<em>start</em>请求处理程序处理了:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Request <span class="keyword">for</span> / received.</span><br><span class="line">About to route a request <span class="keyword">for</span> /</span><br><span class="line">Request handler <span class="string">'start'</span> was called.</span><br></pre></td></tr></table></figure></p><h3 id="让请求处理程序作出响应"><a href="#让请求处理程序作出响应" class="headerlink" title="让请求处理程序作出响应"></a>让请求处理程序作出响应</h3><p>很好。不过现在要是请求处理程序能够向浏览器返回一些有意义的信息而并非全是“Hello World”,那就更好了。</p><p>这里要记住的是,浏览器发出请求后获得并显示的“Hello World”信息仍是来自于我们<em>server.js</em>文件中的<em>onRequest</em>函数。</p><p>其实“处理请求”说白了就是“对请求作出响应”,因此,我们需要让请求处理程序能够像<em>onRequest</em>函数那样可以和浏览器进行“对话”。</p><h4 id="不好的实现方式"><a href="#不好的实现方式" class="headerlink" title="不好的实现方式"></a>不好的实现方式</h4><p>对于我们这样拥有PHP或者Ruby技术背景的开发者来说,最直截了当的实现方式事实上并不是非常靠谱: 看似有效,实则未必如此。</p><p>这里我指的“直截了当的实现方式”意思是:让请求处理程序通过<em>onRequest</em>函数直接返回(return())他们要展示给用户的信息。<br>我们先就这样去实现,然后再来看为什么这不是一种很好的实现方式。</p><p>让我们从让请求处理程序返回需要在浏览器中显示的信息开始。我们需要将<em>requestHandler.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Hello Start"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Hello Upload"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>好的。同样的,请求路由需要将请求处理程序返回给它的信息返回给服务器。因此,我们需要将<em>router.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">handle, pathname</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname); </span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> handle[pathname] === <span class="string">'function'</span>) &#123; </span><br><span class="line"> <span class="keyword">return</span> handle[pathname](); &#125; </span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"No request handler found for "</span> + pathname); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"404 Not found"</span>; </span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>正如上述代码所示,当请求无法路由的时候,我们也返回了一些相关的错误信息。</p><p>最后,我们需要对我们的<em>server.js</em>进行重构以使得它能够将请求处理程序通过请求路由返回的内容响应给浏览器,如下所示:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route, handle</span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;); </span><br><span class="line"> <span class="keyword">var</span> content = route(handle, pathname)</span><br><span class="line"> response.write(content);</span><br><span class="line"> response.end(); </span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>如果我们运行重构后的应用,一切都会工作的很好:请求<a href="http://localhost:8888/start,浏览器会输出“Hello" target="_blank" rel="noopener">http://localhost:8888/start,浏览器会输出“Hello</a> Start”,请求<a href="http://localhost:8888/upload会输出“Hello" target="_blank" rel="noopener">http://localhost:8888/upload会输出“Hello</a> Upload”,而请求<a href="http://localhost:8888/foo" target="_blank" rel="noopener">http://localhost:8888/foo</a> 会输出“404 Not found”。<br>好,那么问题在哪里呢?简单的说就是: 当未来有请求处理程序需要进行非阻塞的操作的时候,我们的应用就“挂”了。</p><p>没理解?没关系,下面就来详细解释下。</p><h4 id="阻塞与非阻塞"><a href="#阻塞与非阻塞" class="headerlink" title="阻塞与非阻塞"></a>阻塞与非阻塞</h4><p>正如此前所提到的,当在请求处理程序中包括非阻塞操作时就会出问题。但是,在说这之前,我们先来看看什么是阻塞操作。</p><p>我不想去解释“阻塞”和“非阻塞”的具体含义,我们直接来看,当在请求处理程序中加入阻塞操作时会发生什么。</p><p>这里,我们来修改下<em>start</em>请求处理程序,我们让它等待10秒以后再返回“Hello Start”。因为,JavaScript中没有类似<em>sleep()</em>这样的操作,所以这里只能够来点小Hack来模拟实现。</p><p>让我们将<em>requestHandlers.js</em>修改成如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>); </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">sleep</span>(<span class="params">milliSeconds</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> startTime = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime(); </span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">new</span> <span class="built_in">Date</span>().getTime() &lt; startTime + milliSeconds); </span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> sleep(<span class="number">10000</span>); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Hello Start"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Hello Upload"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>上述代码中,当函数<em>start()</em>被调用的时候,Node.js会先等待10秒,之后才会返回“Hello Start”。当调用<em>upload()</em>的时候,会和此前一样立即返回。</p><p>(当然了,这里只是模拟休眠10秒,实际场景中,这样的阻塞操作有很多,比方说一些长时间的计算操作等。)</p><p>接下来就让我们来看看,我们的改动带来了哪些变化。</p><p>如往常一样,我们先要重启下服务器。为了看到效果,我们要进行一些相对复杂的操作(跟着我一起做): 首先,打开两个浏览器窗口或者标签页。在第一个浏览器窗口的地址栏中输入<a href="http://localhost:8888/start," target="_blank" rel="noopener">http://localhost:8888/start,</a> 但是先不要打开它!<br>在第二个浏览器窗口的地址栏中输入<a href="http://localhost:8888/upload," target="_blank" rel="noopener">http://localhost:8888/upload,</a> 同样的,先不要打开它!<br>接下来,做如下操作:在第一个窗口中<code>(“/start”)</code> 按下回车,然后快速切换到第二个窗口中<code>(“/upload”)</code> 按下回车。</p><p>注意,发生了什么:<em>/start</em> URL加载花了10秒,这和我们预期的一样。但是,<em>/upload</em> URL居然也花了10秒,而它在对应的请求处理程序中并没有类似于<em>sleep()</em>这样的操作!</p><p>这到底是为什么呢?原因就是<em>start()</em>包含了阻塞操作。形象的说就是“它阻塞了所有其他的处理工作”。</p><p>这显然是个问题,因为Node一向是这样来标榜自己的:“在node中除了代码,所有一切都是并行执行的”。</p><p>这句话的意思是说,Node.js可以在不新增额外线程的情况下,依然可以对任务进行并行处理 —— Node.js是单线程的。它通过事件轮询(event loop)来实现并行操作,对此,我们应该要充分利用这一点 —— 尽可能的避免阻塞操作,取而代之,多使用非阻塞操作。</p><p>然而,要用非阻塞操作,我们需要使用回调,通过将函数作为参数传递给其他需要花时间做处理的函数(比方说,休眠10秒,或者查询数据库,又或者是进行大量的计算)。</p><p>对于Node.js来说,它是这样处理的:<em>“嘿,probablyExpensiveFunction()(译者注:这里指的就是需要花时间处理的函数),你继续处理你的事情,我(Node.js线程)先不等你了,我继续去处理你后面的代码,请你提供一个callbackFunction(),等你处理完之后我会去调用该回调函数的,谢谢!”</em> 。</p><p>(如果想要了解更多关于事件轮询细节,可以阅读Mixu的博文——<a href="http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/" target="_blank" rel="noopener">理解node.js的事件轮询</a>。)<br>接下来,我们会介绍一种错误的使用非阻塞操作的方式。</p><p>和上次一样,我们通过修改我们的应用来暴露问题。</p><p>这次我们还是拿<em>start</em>请求处理程序来“开刀”。将其修改成如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> exec = <span class="built_in">require</span>(<span class="string">"child_process"</span>).exec;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>); </span><br><span class="line"> <span class="keyword">var</span> content = <span class="string">"empty"</span>;</span><br><span class="line"></span><br><span class="line"> exec(<span class="string">"ls -lah"</span>, </span><br><span class="line"> <span class="function"><span class="keyword">function</span> (<span class="params">error, stdout, stderr</span>) </span>&#123; </span><br><span class="line"> content = stdout; &#125;); </span><br><span class="line"> <span class="keyword">return</span> content;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>); </span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Hello Upload"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>上述代码中,我们引入了一个新的Node.js模块<code>child_process</code> ,之所以用它,是为了实现一个既简单又实用的非阻塞操作:exec()。</p><p><em>exec()</em> 做了什么呢?它从Node.js来执行一个shell命令。在上述例子中,我们用它来获取当前目录下所有的文件(“ls -lah”),然后,当/start_URL请求的时候将文件信息输出到浏览器中。<br>上述代码是非常直观的: 创建了一个新的变量<em>content</em>(初始值为“empty”),执行“ls -lah”命令,将结果赋值给content,最后将content返回。</p><p>和往常一样,我们启动服务器,然后访问“<a href="http://localhost:8888/start”" target="_blank" rel="noopener">http://localhost:8888/start”</a> 。<br>之后会载入一个漂亮的web页面,其内容为“empty”。怎么回事?</p><p>这个时候,你可能大致已经猜到了,<em>exec()</em>在非阻塞这块发挥了神奇的功效。它其实是个很好的东西,有了它,我们可以执行非常耗时的shell操作而无需迫使我们的应用停下来等待该操作。</p><p>(如果想要证明这一点,可以将<code>“ls -lah”</code> 换成比如<code>“find /”</code> 这样更耗时的操作来效果)。</p><p>然而,针对浏览器显示的结果来看,我们并不满意我们的非阻塞操作,对吧?</p><p>好,接下来,我们来修正这个问题。在这过程中,让我们先来看看为什么当前的这种方式不起作用。</p><p>问题就在于,为了进行非阻塞工作,<em>exec()</em>使用了回调函数。</p><p>在我们的例子中,该回调函数就是作为第二个参数传递给<em>exec()</em>的匿名函数:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> (<span class="params">error, stdout, stderr</span>) </span>&#123; </span><br><span class="line"> content = stdout;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>现在就到了问题根源所在了:我们的代码是同步执行的,这就意味着在调用<em>exec()</em>之后,Node.js会立即执行 <code>return content;</code> 在这个时候,<em>content</em>仍然是“empty”,因为传递给<em>exec()</em>的回调函数还未执行到——因为<em>exec()</em>的操作是异步的。<br>我们这里“ls -lah”的操作其实是非常快的(除非当前目录下有上百万个文件)。这也是为什么回调函数也会很快的执行到 —— 不过,不管怎么说它还是异步的。</p><p>为了让效果更加明显,我们想象一个更耗时的命令: <code>“find /”</code> ,它在我机器上需要执行1分钟左右的时间,然而,尽管在请求处理程序中,我把“ls -lah”换成“find /”,当打开/start URL的时候,依然能够立即获得HTTP响应 —— 很明显,当<em>exec()</em>在后台执行的时候,Node.js自身会继续执行后面的代码。并且我们这里假设传递给<em>exec()</em>的回调函数,只会在“find /”命令执行完成之后才会被调用。</p><p>那究竟我们要如何才能实现将当前目录下的文件列表显示给用户呢?</p><p>好,了解了这种不好的实现方式之后,我们接下来来介绍如何以正确的方式让请求处理程序对浏览器请求作出响应。</p><h4 id="以非阻塞操作进行请求响应"><a href="#以非阻塞操作进行请求响应" class="headerlink" title="以非阻塞操作进行请求响应"></a>以非阻塞操作进行请求响应</h4><p>我刚刚提到了这样一个短语 —— “正确的方式”。而事实上通常“正确的方式”一般都不简单。</p><p>不过,用Node.js就有这样一种实现方案: 函数传递。下面就让我们来具体看看如何实现。</p><p>到目前为止,我们的应用已经可以通过应用各层之间传递值的方式(请求处理程序 -&gt; 请求路由 -&gt; 服务器)将请求处理程序返回的内容(请求处理程序最终要显示给用户的内容)传递给HTTP服务器。</p><p>现在我们采用如下这种新的实现方式:相对采用将内容传递给服务器的方式,我们这次采用将服务器“传递”给内容的方式。 从实践角度来说,就是将<em>response</em>对象(从服务器的回调函数<em>onRequest()</em>获取)通过请求路由传递给请求处理程序。 随后,处理程序就可以采用该对象上的函数来对请求作出响应。</p><p>原理就是如此,接下来让我们来一步步实现这种方案。</p><p>先从<em>server.js</em>开始:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route, handle</span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"></span><br><span class="line"> route(handle, pathname, response); </span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>相对此前从<em>route()</em>函数获取返回值的做法,这次我们将response对象作为第三个参数传递给<em>route()</em>函数,并且,我们将<em>onRequest()</em>处理程序中所有有关<em>response</em>的函数调都移除,因为我们希望这部分工作让<em>route()</em>函数来完成。</p><p>下面就来看看我们的<em>router.js</em>:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">handle, pathname, response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname); </span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> handle[pathname] === <span class="string">'function'</span>) &#123;</span><br><span class="line"> handle[pathname](response); &#125; </span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"No request handler found for "</span> + pathname);</span><br><span class="line"> response.writeHead(<span class="number">404</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"404 Not found"</span>);</span><br><span class="line"> response.end(); </span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>同样的模式:相对此前从请求处理程序中获取返回值,这次取而代之的是直接传递<em>response</em>对象。</p><p>如果没有对应的请求处理器处理,我们就直接返回“404”错误。</p><p>最后,我们将<em>requestHandler.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> exec = <span class="built_in">require</span>(<span class="string">"child_process"</span>).exec;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> exec(<span class="string">"ls -lah"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">error, stdout, stderr</span>) </span>&#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(stdout);</span><br><span class="line"> response.end(); &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello Upload"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>我们的处理程序函数需要接收response参数,为了对请求作出直接的响应。</p><p><em>start</em>处理程序在<em>exec()</em>的匿名回调函数中做请求响应的操作,而<em>upload</em>处理程序仍然是简单的回复“Hello World”,只是这次是使用<em>response</em>对象而已。</p><p>这时再次我们启动应用(node index.js),一切都会工作的很好。<br>如果想要证明<em>/start</em>处理程序中耗时的操作不会阻塞对<em>/upload</em>请求作出立即响应的话,可以将<em>requestHandlers.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> exec = <span class="built_in">require</span>(<span class="string">"child_process"</span>).exec;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> exec(<span class="string">"find /"</span>, &#123; <span class="attr">timeout</span>: <span class="number">10000</span>, <span class="attr">maxBuffer</span>: <span class="number">20000</span>*<span class="number">1024</span> &#125;, <span class="function"><span class="keyword">function</span> (<span class="params">error, stdout, stderr</span>) </span>&#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(stdout);</span><br><span class="line"> response.end(); &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello Upload"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>这样一来,当请求<a href="http://localhost:8888/start的时候,会花10秒钟的时间才载入,而当请求http://localhost:8888/upload的时候,会立即响应,纵然这个时候`/start`" target="_blank" rel="noopener">http://localhost:8888/start的时候,会花10秒钟的时间才载入,而当请求http://localhost:8888/upload的时候,会立即响应,纵然这个时候`/start`</a> 响应还在处理中。</p><h3 id="更有用的场景"><a href="#更有用的场景" class="headerlink" title="更有用的场景"></a>更有用的场景</h3><p>到目前为止,我们做的已经很好了,但是,我们的应用没有实际用途。</p><p>服务器,请求路由以及请求处理程序都已经完成了,下面让我们按照此前的用例给网站添加交互:用户选择一个文件,上传该文件,然后在浏览器中看到上传的文件。 为了保持简单,我们假设用户只会上传图片,然后我们应用将该图片显示到浏览器中。</p><p>好,下面就一步步来实现,鉴于此前已经对JavaScript原理性技术性的内容做过大量介绍了,这次我们加快点速度。</p><p>要实现该功能,分为如下两步: 首先,让我们来看看如何处理POST请求(非文件上传),之后,我们使用Node.js的一个用于文件上传的外部模块。之所以采用这种实现方式有两个理由。</p><p>第一,尽管在Node.js中处理基础的POST请求相对比较简单,但在这过程中还是能学到很多。<br>第二,用Node.js来处理文件上传(multipart POST请求)是比较复杂的,它<em>不</em>在本书的范畴,但,如何使用外部模块却是在本书涉猎内容之内。</p><h4 id="处理POST请求"><a href="#处理POST请求" class="headerlink" title="处理POST请求"></a>处理POST请求</h4><p>考虑这样一个简单的例子:我们显示一个文本区(textarea)供用户输入内容,然后通过POST请求提交给服务器。最后,服务器接受到请求,通过处理程序将输入的内容展示到浏览器中。</p><p><em>/start</em>请求处理程序用于生成带文本区的表单,因此,我们将<em>requestHandlers.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" content="text/html; '</span>+</span><br><span class="line"> <span class="string">'charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;textarea name="text" rows="20" cols="60"&gt;&lt;/textarea&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Submit text" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"Hello Upload"</span>);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>好了,现在我们的应用已经很完善了,都可以获得威比奖(Webby Awards)了,哈哈。(<em>译者注:威比奖是由国际数字艺术与科学学院主办的评选全球最佳网站的奖项,具体参见详细说明</em>)通过在浏览器中访问<a href="http://localhost:8888/start就可以看到简单的表单了,要记得重启服务器哦!" target="_blank" rel="noopener">http://localhost:8888/start就可以看到简单的表单了,要记得重启服务器哦!</a></p><p>你可能会说:这种直接将视觉元素放在请求处理程序中的方式太丑陋了。说的没错,但是,我并不想在本书中介绍诸如MVC之类的模式,因为这对于你了解JavaScript或者Node.js环境来说没多大关系。</p><p>余下的篇幅,我们来探讨一个更有趣的问题:当用户提交表单时,触发<em>/upload</em>请求处理程序处理POST请求的问题。</p><p>现在,我们已经是新手中的专家了,很自然会想到采用异步回调来实现非阻塞地处理POST请求的数据。</p><p>这里采用非阻塞方式处理是明智的,因为POST请求一般都比较“重” —— 用户可能会输入大量的内容。用阻塞的方式处理大数据量的请求必然会导致用户操作的阻塞。</p><p>为了使整个过程非阻塞,Node.js会将POST数据拆分成很多小的数据块,然后通过触发特定的事件,将这些小数据块传递给回调函数。这里的特定的事件有<em>data</em>事件(表示新的小数据块到达了)以及<em>end</em>事件(表示所有的数据都已经接收完毕)。</p><p>我们需要告诉Node.js当这些事件触发的时候,回调哪些函数。怎么告诉呢? 我们通过在<em>request</em>对象上注册<strong>监听器</strong>(listener) 来实现。这里的request对象是每次接收到HTTP请求时候,都会把该对象传递给<em>onRequest</em>回调函数。</p><p>如下所示:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">request.addListener(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">chunk</span>) </span>&#123; </span><br><span class="line"> <span class="comment">// called when a new chunk of data was received</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">request.addListener(<span class="string">"end"</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; </span><br><span class="line"> <span class="comment">// called when all chunks of data have been received</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>问题来了,这部分逻辑写在哪里呢? 我们现在只是在服务器中获取到了<em>request</em>对象 —— 我们并没有像之前<em>response</em>对象那样,把 request 对象传递给请求路由和请求处理程序。</p><p>在我看来,获取所有来自请求的数据,然后将这些数据给应用层处理,应该是HTTP服务器要做的事情。因此,我建议,我们直接在服务器中处理POST数据,然后将最终的数据传递给请求路由和请求处理器,让他们来进行进一步的处理。</p><p>因此,实现思路就是: 将<em>data</em>和<em>end</em>事件的回调函数直接放在服务器中,在<em>data</em>事件回调中收集所有的POST数据,当接收到所有数据,触发<em>end</em>事件后,其回调函数调用请求路由,并将数据传递给它,然后,请求路由再将该数据传递给请求处理程序。</p><p>还等什么,马上来实现。先从<em>server.js</em>开始:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route, handle</span>) </span>&#123; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; </span><br><span class="line"> <span class="keyword">var</span> postData = <span class="string">""</span>; <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"></span><br><span class="line"> request.setEncoding(<span class="string">"utf8"</span>);</span><br><span class="line"></span><br><span class="line"> request.addListener(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">postDataChunk</span>) </span>&#123; postData += postDataChunk;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Received POST data chunk '"</span>+ postDataChunk + <span class="string">"'."</span>); &#125;);</span><br><span class="line"></span><br><span class="line"> request.addListener(<span class="string">"end"</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> route(handle, pathname, response, postData); &#125;); &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>上述代码做了三件事情: 首先,我们设置了接收数据的编码格式为UTF-8,然后注册了“data”事件的监听器,用于收集每次接收到的新数据块,并将其赋值给<em>postData</em> 变量,最后,我们将请求路由的调用移到<em>end</em>事件处理程序中,以确保它只会当所有数据接收完毕后才触发,并且只触发一次。我们同时还把POST数据传递给请求路由,因为这些数据,请求处理程序会用到。</p><p>上述代码在每个数据块到达的时候输出了日志,这对于最终生产环境来说,是很不好的(数据量可能会很大,还记得吧?),但是,在开发阶段是很有用的,有助于让我们看到发生了什么。</p><p>我建议可以尝试下,尝试着去输入一小段文本,以及大段内容,当大段内容的时候,就会发现<em>data</em>事件会触发多次。</p><p>再来点酷的。我们接下来在/upload页面,展示用户输入的内容。要实现该功能,我们需要将<em>postData</em>传递给请求处理程序,修改<em>router.js</em>为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">handle, pathname, response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname); </span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> handle[pathname] === <span class="string">'function'</span>) &#123;</span><br><span class="line"> handle[pathname](response, postData); &#125; </span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"No request handler found for "</span> + pathname);</span><br><span class="line"> response.writeHead(<span class="number">404</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"404 Not found"</span>);</span><br><span class="line"> response.end(); </span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>然后,在<em>requestHandlers.js</em>中,我们将数据包含在对<em>upload</em>请求的响应中:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" content="text/html; '</span>+</span><br><span class="line"> <span class="string">'charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;textarea name="text" rows="20" cols="60"&gt;&lt;/textarea&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Submit text" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"You've sent: "</span> + postData);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>好了,我们现在可以接收POST数据并在请求处理程序中处理该数据了。</p><p>我们最后要做的是: 当前我们是把请求的整个消息体传递给了请求路由和请求处理程序。我们应该只把POST数据中,我们感兴趣的部分传递给请求路由和请求处理程序。在我们这个例子中,我们感兴趣的其实只是<em>text</em>字段。</p><p>我们可以使用此前介绍过的<em>querystring</em>模块来实现:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> querystring = <span class="built_in">require</span>(<span class="string">"querystring"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" content="text/html; '</span>+</span><br><span class="line"> <span class="string">'charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;textarea name="text" rows="20" cols="60"&gt;&lt;/textarea&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Submit text" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"You've sent the text: "</span>+</span><br><span class="line"> querystring.parse(postData).text);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br></pre></td></tr></table></figure></p><p>好了,以上就是关于处理POST数据的全部内容。</p><h4 id="处理文件上传"><a href="#处理文件上传" class="headerlink" title="处理文件上传"></a>处理文件上传</h4><p>最后,我们来实现我们最终的用例:允许用户上传图片,并将该图片在浏览器中显示出来。</p><p>回到90年代,这个用例完全可以满足用于IPO的商业模型了,如今,我们通过它能学到这样两件事情: 如何安装外部Node.js模块,以及如何将它们应用到我们的应用中。</p><p>这里我们要用到的外部模块是Felix Geisendörfer开发的<code>node-formidable</code> 模块。它对解析上传的文件数据做了很好的抽象。 其实说白了,处理文件上传<em>“就是”</em>处理POST数据 —— 但是,麻烦的是在具体的处理细节,所以,这里采用现成的方案更合适点。</p><p>使用该模块,首先需要安装该模块。Node.js有它自己的包管理器,叫<strong>NPM</strong>。它可以让安装Node.js的外部模块变得非常方便。通过如下一条命令就可以完成该模块的安装:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install formidable</span><br></pre></td></tr></table></figure></p><p>如果终端输出如下内容:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm info build Success: formidable@1.0.9</span><br><span class="line">npm ok</span><br></pre></td></tr></table></figure></p><p>就说明模块已经安装成功了。</p><p>现在我们就可以用<em>formidable</em>模块了——使用外部模块与内部模块类似,用require语句将其引入即可:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> formidable = <span class="built_in">require</span>(<span class="string">"formidable"</span>);</span><br></pre></td></tr></table></figure></p><p>这里该模块做的就是将通过HTTP POST请求提交的表单,在Node.js中可以被解析。我们要做的就是创建一个新的<em>IncomingForm</em>,它是对提交表单的抽象表示,之后,就可以用它解析request对象,获取表单中需要的数据字段。</p><p>node-formidable官方的例子展示了这两部分是如何融合在一起工作的:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> formidable = <span class="built_in">require</span>(<span class="string">'formidable'</span>),</span><br><span class="line"> http = <span class="built_in">require</span>(<span class="string">'http'</span>),</span><br><span class="line"> util = <span class="built_in">require</span>(<span class="string">'util'</span>);</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span>(<span class="params">req, res</span>) </span>&#123;</span><br><span class="line"> <span class="keyword">if</span> (req.url == <span class="string">'/upload'</span> &amp;&amp; req.method.toLowerCase() == <span class="string">'post'</span>) &#123;</span><br><span class="line"> <span class="comment">// parse a file upload</span></span><br><span class="line"> <span class="keyword">var</span> form = <span class="keyword">new</span> formidable.IncomingForm();</span><br><span class="line"> form.parse(req, <span class="function"><span class="keyword">function</span>(<span class="params">err, fields, files</span>) </span>&#123;</span><br><span class="line"> res.writeHead(<span class="number">200</span>, &#123;<span class="string">'content-type'</span>: <span class="string">'text/plain'</span>&#125;);</span><br><span class="line"> res.write(<span class="string">'received upload:\n\n'</span>);</span><br><span class="line"> res.end(util.inspect(&#123;<span class="attr">fields</span>: fields, <span class="attr">files</span>: files&#125;));</span><br><span class="line"> &#125;);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// show a file upload form</span></span><br><span class="line"> res.writeHead(<span class="number">200</span>, &#123;<span class="string">'content-type'</span>: <span class="string">'text/html'</span>&#125;);</span><br><span class="line"> res.end(</span><br><span class="line"> <span class="string">'&lt;form action="/upload" enctype="multipart/form-data" '</span>+</span><br><span class="line"> <span class="string">'method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="text" name="title"&gt;&lt;br&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="file" name="upload" multiple="multiple"&gt;&lt;br&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Upload"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span></span><br><span class="line"> );</span><br><span class="line">&#125;).listen(<span class="number">8888</span>);</span><br></pre></td></tr></table></figure></p><p>如果我们将上述代码,保存到一个文件中,并通过<em>node</em>来执行,就可以进行简单的表单提交了,包括文件上传。然后,可以看到通过调用<em>form.parse</em>传递给回调函数的<em>files</em>对象的内容,如下所示:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">received upload:</span><br><span class="line"></span><br><span class="line">&#123; <span class="attr">fields</span>: &#123; <span class="attr">title</span>: <span class="string">'Hello World'</span> &#125;,</span><br><span class="line"> files:</span><br><span class="line"> &#123; <span class="attr">upload</span>:</span><br><span class="line"> &#123; <span class="attr">size</span>: <span class="number">1558</span>,</span><br><span class="line"> path: <span class="string">'/tmp/1c747974a27a6292743669e91f29350b'</span>,</span><br><span class="line"> name: <span class="string">'us-flag.png'</span>,</span><br><span class="line"> type: <span class="string">'image/png'</span>,</span><br><span class="line"> lastModifiedDate: Tue, <span class="number">21</span> Jun <span class="number">2011</span> <span class="number">07</span>:<span class="number">02</span>:<span class="number">41</span> GMT,</span><br><span class="line"> _writeStream: [<span class="built_in">Object</span>],</span><br><span class="line"> length: [Getter],</span><br><span class="line"> filename: [Getter],</span><br><span class="line"> mime: [Getter] &#125; &#125; &#125;</span><br></pre></td></tr></table></figure></p><p>为了实现我们的功能,我们需要将上述代码应用到我们的应用中,另外,我们还要考虑如何将上传文件的内容(保存在<code>/tmp</code> 目录中)显示到浏览器中。</p><p>我们先来解决后面那个问题: 对于保存在本地硬盘中的文件,如何才能在浏览器中看到呢?</p><p>显然,我们需要将该文件读取到我们的服务器中,使用一个叫<code>fs</code> 的模块。</p><p>我们来添加<code>/show_URL</code> 的请求处理程序,该处理程序直接硬编码将文件<code>/tmp/test.png</code> 内容展示到浏览器中。当然了,首先需要将该图片保存到这个位置才行。</p><p>将<em>requestHandlers.js</em>修改为如下形式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> querystring = <span class="built_in">require</span>(<span class="string">"querystring"</span>),</span><br><span class="line"> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" '</span>+</span><br><span class="line"> <span class="string">'content="text/html; charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;textarea name="text" rows="20" cols="60"&gt;&lt;/textarea&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Submit text" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"You've sent the text: "</span>+</span><br><span class="line"> querystring.parse(postData).text);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'show' was called."</span>);</span><br><span class="line"> fs.readFile(<span class="string">"/tmp/test.png"</span>, <span class="string">"binary"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">error, file</span>) </span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(error) &#123;</span><br><span class="line"> response.writeHead(<span class="number">500</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(error + <span class="string">"\n"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"image/png"</span>&#125;);</span><br><span class="line"> response.write(file, <span class="string">"binary"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br><span class="line">exports.show = show;</span><br></pre></td></tr></table></figure></p><p>我们还需要将这新的请求处理程序,添加到<em>index.js</em>中的路由映射表中:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> server = <span class="built_in">require</span>(<span class="string">"./server"</span>);</span><br><span class="line"><span class="keyword">var</span> router = <span class="built_in">require</span>(<span class="string">"./router"</span>);</span><br><span class="line"><span class="keyword">var</span> requestHandlers = <span class="built_in">require</span>(<span class="string">"./requestHandlers"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> handle = &#123;&#125;</span><br><span class="line">handle[<span class="string">"/"</span>] = requestHandlers.start;</span><br><span class="line">handle[<span class="string">"/start"</span>] = requestHandlers.start;</span><br><span class="line">handle[<span class="string">"/upload"</span>] = requestHandlers.upload;</span><br><span class="line">handle[<span class="string">"/show"</span>] = requestHandlers.show;</span><br><span class="line"></span><br><span class="line">server.start(router.route, handle);</span><br></pre></td></tr></table></figure></p><p>重启服务器之后,通过访问<a href="http://localhost:8888/show,就可以看到保存在`/tmp/test.png`" target="_blank" rel="noopener">http://localhost:8888/show,就可以看到保存在`/tmp/test.png`</a> 的图片了。</p><p>好,最后我们要的就是:</p><ul><li>在<code>/start</code> 表单中添加一个文件上传元素</li><li>将node-formidable整合到我们的<em>upload</em>请求处理程序中,用于将上传的图片保存到<code>/tmp/test.png</code> </li><li>将上传的图片内嵌到<code>/upload_URL</code> 输出的HTML中</li></ul><p>第一项很简单。只需要在HTML表单中,添加一<code>multipart/form-data</code> 的编码类型,移除此前的文本区,添加一个文件上传组件,并将提交按钮的文案改为“Upload file”即可。 如下<em>requestHandler.js</em>所示:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> querystring = <span class="built_in">require</span>(<span class="string">"querystring"</span>),</span><br><span class="line"> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" '</span>+</span><br><span class="line"> <span class="string">'content="text/html; charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" enctype="multipart/form-data" '</span>+</span><br><span class="line"> <span class="string">'method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="file" name="upload"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Upload file" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"You've sent the text: "</span>+</span><br><span class="line"> querystring.parse(postData).text);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params">response, postData</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'show' was called."</span>);</span><br><span class="line"> fs.readFile(<span class="string">"/tmp/test.png"</span>, <span class="string">"binary"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">error, file</span>) </span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(error) &#123;</span><br><span class="line"> response.writeHead(<span class="number">500</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(error + <span class="string">"\n"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"image/png"</span>&#125;);</span><br><span class="line"> response.write(file, <span class="string">"binary"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br><span class="line">exports.show = show;</span><br></pre></td></tr></table></figure></p><p>很好。下一步相对比较复杂。这里有这样一个问题: 我们需要在<em>upload</em>处理程序中对上传的文件进行处理,这样的话,我们就需要将<em>request</em>对象传递给node-formidable的<em>form.parse</em>函数。</p><p>但是,我们有的只是<em>response</em>对象和<em>postData</em>数组。看样子,我们只能不得不将<em>request</em>对象从服务器开始一路通过请求路由,再传递给请求处理程序。 或许还有更好的方案,但是,不管怎么说,目前这样做可以满足我们的需求。</p><p>到这里,我们可以将<em>postData</em>从服务器以及请求处理程序中移除了 —— 一方面,对于我们处理文件上传来说已经不需要了,另外一方面,它甚至可能会引发这样一个问题: 我们已经“消耗”了<em>request</em>对象中的数据,这意味着,对于<em>form.parse</em>来说,当它想要获取数据的时候就什么也获取不到了。(因为Node.js不会对数据做缓存)</p><p>我们从<em>server.js</em>开始 —— 移除对postData的处理以及<em>request.setEncoding</em> (这部分node-formidable自身会处理),转而采用将<em>request</em>对象传递给请求路由的方式:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">"url"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">route, handle</span>) </span>&#123; <span class="function"><span class="keyword">function</span> <span class="title">onRequest</span>(<span class="params">request, response</span>) </span>&#123; <span class="keyword">var</span> pathname = url.parse(request.url).pathname;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request for "</span> + pathname + <span class="string">" received."</span>);</span><br><span class="line"> route(handle, pathname, response, request); &#125;</span><br><span class="line"></span><br><span class="line"> http.createServer(onRequest).listen(<span class="number">8888</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Server has started."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br></pre></td></tr></table></figure></p><p>接下来是 router.js —— 我们不再需要传递<em>postData</em>了,这次要传递<em>request</em>对象:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">route</span>(<span class="params">handle, pathname, response, request</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"About to route a request for "</span> + pathname); <span class="keyword">if</span> (<span class="keyword">typeof</span> handle[pathname] === <span class="string">'function'</span>) &#123;</span><br><span class="line"> handle[pathname](response, request); &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"No request handler found for "</span> + pathname);</span><br><span class="line"> response.writeHead(<span class="number">404</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"404 Not found"</span>);</span><br><span class="line"> response.end(); &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.route = route;</span><br></pre></td></tr></table></figure></p><p>现在,request_对象就可以在我们的<em>upload</em>请求处理程序中使用了。node-formidable会处理将上传的文件保存到本地<code>/tmp</code> 目录中,而我们需要做的是确保该文件保存成<code>/tmp/test.png</code> 。 没错,我们保持简单,并假设只允许上传PNG图片。<br>这里采用<code>fs.renameSync(path1,path2)</code> 来实现。要注意的是,正如其名,该方法是同步执行的, 也就是说,如果该重命名的操作很耗时的话会阻塞。 这块我们先不考虑。</p><p>接下来,我们把处理文件上传以及重命名的操作放到一起,如下<em>requestHandlers.js</em>所示:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> querystring = <span class="built_in">require</span>(<span class="string">"querystring"</span>),</span><br><span class="line"> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>),</span><br><span class="line"> formidable = <span class="built_in">require</span>(<span class="string">"formidable"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'start' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> body = <span class="string">'&lt;html&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;meta http-equiv="Content-Type" content="text/html; '</span>+</span><br><span class="line"> <span class="string">'charset=UTF-8" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/head&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;form action="/upload" enctype="multipart/form-data" '</span>+</span><br><span class="line"> <span class="string">'method="post"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="file" name="upload" multiple="multiple"&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;input type="submit" value="Upload file" /&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/form&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/body&gt;'</span>+</span><br><span class="line"> <span class="string">'&lt;/html&gt;'</span>;</span><br><span class="line"></span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(body);</span><br><span class="line"> response.end();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">upload</span>(<span class="params">response, request</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'upload' was called."</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> form = <span class="keyword">new</span> formidable.IncomingForm();</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"about to parse"</span>);</span><br><span class="line"> form.parse(request, <span class="function"><span class="keyword">function</span>(<span class="params">error, fields, files</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"parsing done"</span>);</span><br><span class="line"> fs.renameSync(files.upload.path, <span class="string">"/tmp/test.png"</span>);</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/html"</span>&#125;);</span><br><span class="line"> response.write(<span class="string">"received image:&lt;br/&gt;"</span>);</span><br><span class="line"> response.write(<span class="string">"&lt;img src='/show' /&gt;"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params">response</span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Request handler 'show' was called."</span>);</span><br><span class="line"> fs.readFile(<span class="string">"/tmp/test.png"</span>, <span class="string">"binary"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">error, file</span>) </span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(error) &#123;</span><br><span class="line"> response.writeHead(<span class="number">500</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>&#125;);</span><br><span class="line"> response.write(error + <span class="string">"\n"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> response.writeHead(<span class="number">200</span>, &#123;<span class="string">"Content-Type"</span>: <span class="string">"image/png"</span>&#125;);</span><br><span class="line"> response.write(file, <span class="string">"binary"</span>);</span><br><span class="line"> response.end();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exports.start = start;</span><br><span class="line">exports.upload = upload;</span><br><span class="line">exports.show = show;</span><br></pre></td></tr></table></figure></p><p>好了,重启服务器,我们应用所有的功能就可以用了。选择一张本地图片,将其上传到服务器,然后浏览器就会显示该图片。</p><h2 id="总结与展望"><a href="#总结与展望" class="headerlink" title="总结与展望"></a>总结与展望</h2><p>恭喜,我们的任务已经完成了!我们开发完了一个Node.js的web应用,应用虽小,但却“五脏俱全”。 期间,我们介绍了很多技术点:服务端JavaScript、函数式编程、阻塞与非阻塞、回调、事件、内部和外部模块等等。</p><p>当然了,还有许多本书没有介绍到的: 如何操作数据库、如何进行单元测试、如何开发Node.js的外部模块以及一些简单的诸如如何获取GET请求之类的方法。</p><p>但本书毕竟只是一本给初学者的教程 —— 不可能覆盖到所有的内容。</p><p>幸运的是,Node.js社区非常活跃(作个不恰当的比喻就是犹如一群有多动症小孩子在一起,能不活跃吗?), 这意味着,有许多关于Node.js的资源,有什么问题都可以向社区寻求解答。 其中<a href="https://github.com/nodejs/node-v0.x-archive/wiki" target="_blank" rel="noopener">Node.js社区的wiki</a>以及 <a href="https://www.nodecloud.org/" target="_blank" rel="noopener">NodeCloud</a>就是最好的资源。</p>]]></content>
<summary type="html">
&lt;h2 id=&quot;关于&quot;&gt;&lt;a href=&quot;#关于&quot; class=&quot;headerlink&quot; title=&quot;关于&quot;&gt;&lt;/a&gt;关于&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;作者: Manuel Kiessling&lt;br&gt;翻译: goddyzhao &amp;amp; GrayZhang &amp;am
</summary>
<category term="Book" scheme="https://wangen.github.io/categories/Book/"/>
<category term="node" scheme="https://wangen.github.io/tags/node/"/>
<category term="book" scheme="https://wangen.github.io/tags/book/"/>
</entry>
<entry>
<title>名词王国里的死刑(翻译)</title>
<link href="https://wangen.github.io/2018/02/25/book-java-1/"/>
<id>https://wangen.github.io/2018/02/25/book-java-1/</id>
<published>2018-02-25T15:23:14.000Z</published>
<updated>2018-02-25T15:51:37.881Z</updated>
<content type="html"><![CDATA[<blockquote><p>原文地址:<a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html" target="_blank" rel="noopener">Execution in the Kingdom of Nouns</a><br>翻译原文:<a href="http://lcwangchao.github.io/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/2012/07/02/excution_in_the_kingdom_of_nouns/" target="_blank" rel="noopener">名词王国里的死刑(翻译)</a></p></blockquote><h2 id="译者注"><a href="#译者注" class="headerlink" title="译者注"></a>译者注</h2><p>翻译自Steve Yegge的大作《Execution in the Kingdom of Nouns》原文在<a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html" target="_blank" rel="noopener">这里</a></p><p>另外第一次翻译,很多地方不准确或根本翻译不出来,见谅~</p><h2 id="翻译正文"><a href="#翻译正文" class="headerlink" title="翻译正文"></a>翻译正文</h2><p>Hello,world!今天我给大家讲一个关于Java魔鬼国王和他在全国范围内驱逐动词的故事。</p><p>注意:这个故事并没有什么圆满结局。如果你心灵脆弱或者吹毛求疵的话,这个故事不适合你。如果你易于动怒或喜欢在别人的博客上妄加评论, 那么请立即停止阅读。</p><p>在我们开始这个故事之前,先让我们熟悉一下背景:</p><h3 id="溢出的垃圾"><a href="#溢出的垃圾" class="headerlink" title="溢出的垃圾"></a>溢出的垃圾</h3><p>所有使用Java的人都喜欢“用例”,所以让我们以一个用例开始吧:倒垃圾。就像这样:“Johnny,快去倒垃圾,他都快溢出来了!”</p><p>如何表达倒垃圾这一活动呢?如果你是一个正常说英语的人,你可以粗略地用以下几句话来描述它</p><ul><li>在水池下取出垃圾袋</li><li>带着垃圾袋去车库</li><li>把它扔到垃圾桶里</li><li>走回来</li><li>洗手</li><li>坐回沙发上</li><li>继续玩你的电视游戏(或者干其他的事)</li></ul><p>即使你不用英语思考,你也会想象出一系列类似的动作。不考虑你选择的语言,或者采取的具体步骤,取决于你采取的行动,倒垃圾是一系列终止于垃圾在外面,你回到屋子里的动作。</p><p>我们的思想充斥着各种或勇敢的,或暴躁的,或激昂的动作。我们生活,我们呼吸,我们走路,我们谈话,我们笑,我们哭,我们希望,我们害怕,我们吃,我们喝,我们走,我们听,我们倒垃圾。我们能自由地“做”和“行动”。假如我们只是石头,生活没准还算好,但是我们不会自由。因为我们可以“做”事,所以才会自由。</p><p>我们的生活也同时充斥着各种“名词”。我们吃“名词”(食物),我们从商店买“名词”(商品),我们坐在“名词”(凳子)上。“名词”(石头)可能会忽然砸到你头上,在你的“名词”(头)上弄一个“名词”(大包)。名词即事物,想想没有了事物我们会怎样?但他们仅仅只是事物,比如:意味着结束或者结束本身,或者一些贵重物品,或者我们周围经常看到的事物的名字。这是一座建筑,那是一个石头。任何一个小孩子都能指出名词,仅此而已。发生在名词身上的 “变化”才是最有趣的事情。</p><p>变化需要动作。动作是生活的调料。动作甚至给了调料以调料!毕竟除非你“吃”它,你是不会感到香这种味道的。名词也许无处不在,但是生活一直在变并一直有趣的功劳还是在于动词。</p><p>当然,除了名词和动词,我们还有形容词,介词,代词,冠词,连词,语气词,和许许多多其他让我们构造有趣语言的词汇。它们都在语言中扮演着自己的角色,而且每一个都很重要。 如果它们哪一个不存在了的话,那是挺遗憾的事情。</p><p>那么,如果有一天我们不再用动词了,你是不是感到很奇怪呢?</p><p>在下面我要给大家讲的故事里,这件事情真的发生了……</p><h3 id="名词王国"><a href="#名词王国" class="headerlink" title="名词王国"></a>名词王国</h3><p>在Java王国中,国王Java以铁腕统治着他的国家,而他子民的思考方式也并不和你我一样。在这里,你可以看到,名词是十分重要的并直接服从国王的命令。名词是最重要的居民,它们身穿艳丽的服装显得高贵而优雅,而这些衣服是由形容词提供的。而形容词哪,也很满意它们的生活,当然,他们不可能像名词那么高贵,不过相比于动词来讲却幸运得很多。</p><p>因为,动词在Java王国里的日子,相当,相当的糟糕。</p><p>奉国王Java的法令,动词是隶属于名词的,但他们不仅仅是宠物而已。或者说连宠物都不是,在整个国家,动词负担起所有的劳力工作。实际上,他们是王国的奴隶,至少是 农奴或者契约奴之类的。Java王国的居民对自己的生活还是比较满意的,他们从来没有想到会发生什么变化。</p><p>动词负责王国里的所有工作,但是仍然获取不到任何尊重,甚至都不允许单独出来。如果一个动词被发现在公共场合出现,它会立即被名词逮捕。</p><p>当然“逮捕”也是一个动词,他也从不被允许单独行动;你必须创造一个“动词逮捕者”来协助逮捕。但是“创造”和“协助”哪?这样的话,“创造者”和“协助者”也各自在这个工作上伴随“创造”和“协助”起到了重要的作用。</p><p>国王Java,在他的上帝Sun(<em>现在是Oracle了吧…[译者注]</em>)的指引下,时不时地威胁要将所有动词驱逐出王国。如果那一天到来了,他们当然需要至少一个动词来做 各种工作,而从国王残忍的幽默感上猜测,这个动词很可能就是“执行”。</p><p>动词“执行”(execute),和它的亲戚“运行”,“开始”,“走你”,“做”,“就这样做”或者相似的什么词可以通过找到合适的“执行者”来替代任何其他的动词。想等(wait)一下? <code>Waiter.execute()</code> ;刷(brush)牙(teeth)?<code>ToothBrusher(myTeeth).go()</code> ;扔(take out)垃圾(garbage)? <code>TrashDisposalPlanExecutor.doIt()</code> 。没有任何 一个动词是安全的,一切动词都会被执行的名词而取代。</p><p>在这种精神更加泛滥的角落,名词已经把动词驱逐干净。不仔细看的话,你会觉得仍然有动词存在,比如耕种或倒茶壶,但是一旦仔细观察,真相便浮出了水面:名词可以随意 命名紧跟在它们后面的动词“执行”,而不改变自身的角色。所以,当你看到“耕地者”在“耕地”,“倒茶壶者”在“倒”或者说“注册管理者”在“注册”,你真正看到的是魔鬼国王Java的 “执行者”大军,只不过他们披着所有者的外衣而已。</p><h3 id="在其他王国里的动词"><a href="#在其他王国里的动词" class="headerlink" title="在其他王国里的动词"></a>在其他王国里的动词</h3><p>在其他编程语言的王国中,倒垃圾是一件很直白的事情,和我们用英语表述的十分相似。在Java王国中,数据实体是名词而函数是动词,而在其他王国中却不然:王国的居民 是混在一起的,而且在能顺利完成工作的前提下,只要他们愿意,既可以是名词也可以是动词。</p><p>比如在附近的C的领域,JavaScript的地盘,Perl的地盘和Ruby的地盘,他们可能会把倒垃圾这件事分解成一系列的动作(或者叫做动词或者函数)。如果他们将这些 动作以适当的顺序应用于适当的事物(拿垃圾,把它带出去,扔到垃圾桶里等等),倒垃圾的任务就圆满成功了。在这个过程中根本不需要执行者或其他的伴随者这出现。</p><p>在这些王国里,真的没有必要创造这么多的包裹器来包裹动词。他们没有“垃圾倾倒策略”之类的名词,或者“垃圾倾倒地点定位者”来只是定义你倒垃圾的路径,也没有“倒完垃圾后的回调”来保证你倒垃圾后回到自己的沙发上。他们只是写一些动词来操作名词,并创建一个主要的名词 <code>例如提出垃圾(take_out_garbage())</code> ,并把一些需要做的子动作放在里面。</p><p>在这些王国中,当需求提升的时候,也通常有一种机制来生成比较重要的名词。如果这些精明的创造者创造出了一个全新的名词,比如房子,马车,或者耕起地来比人还快的机器, 他们会被给予一个统一的概念:<strong>类</strong>。而人们会给<strong>类</strong>一个名称,一个描述,一些状态和一些操作建议。</p><p>这些王国与Java的不同之处在于,动词是允许单独出现的,你没必要创造新的名词去束缚他们。</p><p>Java王国的人以一种轻视的态度看待他们的邻居,而这也是程序诸王国的现状。</p><h3 id="如果你挖个足够深的洞…"><a href="#如果你挖个足够深的洞…" class="headerlink" title="如果你挖个足够深的洞…"></a>如果你挖个足够深的洞…</h3><p>在世界的另一边,有一片贫瘠的居住地。在那里,动词居民的地位十分之高。这就是函数式王国,包括Haskellia,Ocamlica,Schemeria和一些其它的国家。因为附近的国家很少,他们几乎不与Java王国何其附近的国家有接触。也正因为这样,函数式诸国们相互轻视,并有事没事的时候打一仗以排遣寂寞。</p><p>在函数式王国里,名词和动词一般被看做同样等级的居民。但是,名词,对是名词,基本上整天无所事事。他们的出现在做事或者执行任务的时候并没有多大意义,因为活跃的动词们基本把能做的事情都做了。这里也没有什么奇怪的法律说要创造各种“帮助者”来帮助动词做事,因此在这些王国中,名词的数量和实际上存在事物的数量是相同的。</p><p>这样做的结果是,动词在这片土地上为所欲为(请原谅我的用词)。如果你是一个外来人,你很容易产生<strong>名词(函数)是这里最重要的居民</strong>的印象。顺便提一句,这也是为什么这里被叫做函数式诸国还不是事物诸国的原因。</p><p>在最为遥远的地方,远离函数式诸国,存在着一块传说中的土地,“Lamda the Ultimate”(<em>终极lamda?霸气~[译者注]</em>)。传说中在那里,没有名词,只有动词。 那里有事物,但事物由动词组成。如果传说不虚,甚至数字,那里最为流行的货币,也是动词!数字0被表示为<em>lamda()</em>,数字1是<em>lamda(lamda())</em>,2是<em>lamda(lamda(lamda()))</em>,以此类推。</p><p>在这片神奇的土地上,一切事物,别管你是名词,动词,还是其他什么,都是由最基本的动词lamda组成的。</p><p>老实说,Java王国中幸福生活着的居民并没有意识到另外一个世界的存在。你能想象得知此事之后的文化震动么?他们可能会发明一个新的名词(比如“憎恶”)来表达自己新的感受。</p><h3 id="Java王国中的居民真的快乐么?"><a href="#Java王国中的居民真的快乐么?" class="headerlink" title="Java王国中的居民真的快乐么?"></a>Java王国中的居民真的快乐么?</h3><p>你可能觉得Java王国中的生活有点奇怪,如果糟糕的话还效率还会变得十分低下。不过,你能从一个地方的童谣中看出他们的幸福程度,而Java王国的童谣,是一群古怪的诗。 比如,这里的儿童经常朗诵的寓言: (<em>这就不翻了[译者注]</em>)<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line">For the lack of a nail,</span><br><span class="line"> throw new HorseshoeNailNotFoundException(<span class="string">"no nails!"</span>);</span><br><span class="line"></span><br><span class="line">For the lack of a horseshoe,</span><br><span class="line"> EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();</span><br><span class="line"></span><br><span class="line">For the lack of a horse,</span><br><span class="line"> RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(</span><br><span class="line"> new BroadcastMessage(StableFactory.getNullHorseInstance()));</span><br><span class="line"></span><br><span class="line">For the lack of a rider,</span><br><span class="line"> MessageDeliverySubsystem.getLogger().logDeliveryFailure(</span><br><span class="line"> MessageFactory.getAbstractMessageInstance(</span><br><span class="line"> new MessageMedium(MessageType.VERBAL),</span><br><span class="line"> new MessageTransport(MessageTransportType.MOUNTED_RIDER),</span><br><span class="line"> new MessageSessionDestination(BattleManager.getRoutingInfo(</span><br><span class="line"> BattleLocation.NEAREST))),</span><br><span class="line"> MessageFailureReasonCode.UNKNOWN_RIDER_FAILURE);</span><br><span class="line"></span><br><span class="line">For the lack of a message,</span><br><span class="line"> ((BattleNotificationSender)</span><br><span class="line"> BattleResourceMediator.getMediatorInstance().getResource(</span><br><span class="line"> BattleParticipant.PROXY_PARTICIPANT,</span><br><span class="line"> BattleResource.BATTLE_NOTIFICATION_SENDER)).sendNotification(</span><br><span class="line"> ((BattleNotificationBuilder)</span><br><span class="line"> (BattleResourceMediator.getMediatorInstance().getResource(</span><br><span class="line"> BattleOrganizer.getBattleParticipant(Battle.Participant.GOOD_GUYS),</span><br><span class="line"> BattleResource.BATTLE_NOTIFICATION_BUILDER))).buildNotification(</span><br><span class="line"> BattleOrganizer.getBattleState(BattleResult.BATTLE_LOST),</span><br><span class="line"> BattleManager.getChainOfCommand().getCommandChainNotifier()));</span><br><span class="line"></span><br><span class="line">For the lack of a battle,</span><br><span class="line"> try &#123;</span><br><span class="line"> synchronized(BattleInformationRouterLock.getLockInstance()) &#123;</span><br><span class="line"> BattleInformationRouterLock.getLockInstance().<span class="built_in">wait</span>();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; catch (InterruptedException ix) &#123;</span><br><span class="line"> <span class="keyword">if</span> (BattleSessionManager.getBattleStatus(</span><br><span class="line"> BattleResource.getLocalizedBattleResource(Locale.getDefault()),</span><br><span class="line"> BattleContext.createContext(</span><br><span class="line"> Kingdom.getMasterBattleCoordinatorInstance(</span><br><span class="line"> new TweedleBeetlePuddlePaddleBattle()).populate(</span><br><span class="line"> RegionManager.getArmpitProvince(Armpit.LEFTMOST)))) ==</span><br><span class="line"> BattleStatus.LOST) &#123;</span><br><span class="line"> <span class="keyword">if</span> (LOGGER.isLoggable(Level.TOTALLY_SCREWED)) &#123;</span><br><span class="line"> LOGGER.logScrewage(BattleLogger.createBattleLogMessage(</span><br><span class="line"> BattleStatusFormatter.format(BattleStatus.LOST_WAR,</span><br><span class="line"> Locale.getDefault())));</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line">For the lack of a war,</span><br><span class="line"> new ServiceExecutionJoinPoint(</span><br><span class="line"> DistributedQueryAnalyzer.forwardQueryResult(</span><br><span class="line"> NotificationSchemaManager.getAbstractSchemaMapper(</span><br><span class="line"> new PublishSubscribeNotificationSchema()).getSchemaProxy().</span><br><span class="line"> executePublishSubscribeQueryPlan(</span><br><span class="line"> NotificationSchema.ALERT,</span><br><span class="line"> new NotificationSchemaPriority(SchemaPriority.MAX_PRIORITY),</span><br><span class="line"> new PublisherMessage(MessageFactory.getAbstractMessage(</span><br><span class="line"> MessageType.WRITTEN,</span><br><span class="line"> new MessageTransport(MessageTransportType.WOUNDED_SURVIVOR),</span><br><span class="line"> new MessageSessionDestination(</span><br><span class="line"> DestinationManager.getNullDestinationForQueryPlan()))),</span><br><span class="line"> DistributedWarMachine.getPartyRoleManager().getRegisteredParties(</span><br><span class="line"> PartyRoleManager.PARTY_KING ||</span><br><span class="line"> PartyRoleManager.PARTY_GENERAL ||</span><br><span class="line"> PartyRoleManager.PARTY_AMBASSADOR)).getQueryResult(),</span><br><span class="line"> PriorityMessageDispatcher.getPriorityDispatchInstance())).</span><br><span class="line"> waitForService();</span><br><span class="line"></span><br><span class="line">All <span class="keyword">for</span> the lack of a horseshoe nail.</span><br></pre></td></tr></table></figure></p><p>直到今天,这仍然是美好的建议。</p><p>尽管在Java王国的叙述方式和本.富兰克林的原作大有不同,但是这里的居民觉得他们的重新编排还是有一种不同的魅力在里面。</p><p>而最大的魅力在于“架构”,是所有人都能看见的。架构被国王Java授予了之高无上的地位,因为,架构全部是由名词构成的。正如我们所知的,在Java王国,名词即事物,事物 的荣耀高于一切的动词。架构由无数事物构成:你可以看或触摸的事物,给你留下壮观印象的事物,用棍子刮擦发出美妙声音的事物。国王Java,十分喜欢刮擦的噪音,每当他新换车夫的时候,踢轮子发出的美妙声音让他觉得很满意。不管上面的故事有什么瑕疵,“事物”总是不缺少的。</p><p>作为人类,我们的第一本能总是寻找由各宗物体构成的庇护。庇护越坚固,我们感觉越安全。在Java王国,有很过坚固的东西让居民们感到安心。他们感慨如此庞大的架构建造之神奇并认为它是“最为坚固的设计”。而且每当结构变化时,他们就越坚信这点。接着,架构的力量也变得强的令人生畏以至于没有人认为可以摧毁他。</p><p>除了坚固的架构之外,在Java王国中的所有东西很有调理地组织着:你会发现任何名词都会呆在适当的地方。这里每个故事都有一个固定的模式:实例构造在故事的表述中占了主要的篇幅,因为每个抽象都会有一个管理者(Manager),而且每个管理者都有一个run()方法。Java居民们觉得他们可以用这种模型表述任何事情。这是一种“名词计算”,只要你愿意,它可以满足任何抽象,任何计算。你需要的仅仅是足够的名词,名词的构造器,获取器方法,和重要的execute()函数来实现你的计划。</p><p>Java王国的居民活的不仅仅是幸福,简直是迸发出强烈的自豪感。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">StateManager.getConsiderationSetter(<span class="string">"Noun Oriented Thinking"</span>, State.HARMFUL).run()</span><br></pre></td></tr></table></figure></p><p>或者,正如外面的世界所说,“面向名词的思考是有害的”。</p><p>面向对象的编程把名词放到首位,但是我们为什么非得把名词捧上神坛以至于让语句变的如此啰嗦哪?为什么一种语句成分的地位非得高于另外一种?这并不是好像面向对象的编程突然使得动词的低位降低,正如我们认为的那样。这是一种奇怪的认识的扭曲。正如我的朋友 Jacob Gabrielso有一次说到,提倡面向对象的编程好比提倡面向裤子的穿衣方式。</p><p>Java的静态类型系统,像其他任何类似的语言一样,有着共同的问题。但是过分强调面向名词的编程思想给人带来很大的困扰。任何类型系统都会要求你重新梳理思路来配合它,但是清除独立的动词看起来十分不合情理。</p><p>C++并没有这个问题。因为C++作为C语言的超集允许你定义单独的函数。此外,C++提供了独立的命名空间的概念。Java的类承载了太多的内容:命名空间,用户自定义类型,句法委托机制,可见性和作用域机制,等等。</p><p>不要误解了我的意思。我并没有说C++“好”,我只是赞美它至少相比于Java来讲灵活的类型系统。C++出现问题会让听众抓狂并且想杀了你(比如,意想不到的段错误和其他难以发现的隐患)。并且在C++你很难找到一个能描述你的想法的咒语。但是它灵活地可表述的思想的范围却远远超出了Java。因为C++提供给你了动词,谁想用一个没有动词的语言说话哪?</p><p>类是Java中唯一提供的建模的工具。所以当一个新的想法出现在你脑海的时候,你不得不重塑它,包装它,甚至弄碎它直到它变成一个名词,即使它开始是一个动作,过程,或者任何其他不是“物”的概念。</p><p>我似乎回到了8,9年前一帮搞Perl的家伙对我说的:“伙计,并不是所有的东西都是对象的。”</p><p>很奇怪,Java似乎是主流面向对象语言中唯一一个完全以名词为中心的语言。在Python或者Ruby中,你不会找到<em>AbstractProxyMediator</em>,<em>NotificationStrategyFactory</em>或者其他类似的东西。 为什么在Java中它们满地都是?我敢打赌原因是出在了动词的身上。然而Python,Ruby,JavaScript,Perl,当然还有所有的函数式编程语言允许你声明并传递函数而不用用类包装它。</p><p>很显然,动态类型语言的使用更容易;你可以仅仅传递一个引用给函数,函数可以用名字获取它,而函数的调用者仅仅用合适的参数调用函数并正确地使用返回的值就可以了。</p><p>但是很多静态类型的语言同样也有第一类的函数。这包括固定类型的语言比如C和C++,还有类型自动推断的语言比如Haskell和ML。这些语言仅仅需要一些语法来建立,传递和调用函数的内容就可以了。</p><p>Java没有理由不简单地添加第一类函数并最终实现一个成熟的、没有扭曲的可以让人自由运用动词来实现他们想法的世界。 实际上,有一个基于JVM叫做<code>The Nice programming language</code> 的语言实现了一个非常类似Java的语法,并包含了一个非常具有表现力的实现了使用动词方式:独立函数。而Java强制你用Callback,Ruunable或其他匿名接口来包装它为一个类以便于调用。</p><p>Sun公司甚至没有打破他们一切函数都必须被类拥有的信条。任何匿名的函数都会具有一个隐式的this指针指向定义它的类,问题解决了。</p><p>我不知道为什么Sun公司坚持Java矗立在名词王国。我怀疑这是低估了他们的民众;他们添加了泛型,一个更加复杂的概念,所以他们不再关心如何保持他们语法的简练。并且添加动词并不是一件坏事,这是因为Java现今所建立的:为一个Java程序员提供工具让他们按自己的想法编程更有意义。</p><p>我真心希望Java能修复这个缺陷,以便我可以把垃圾带出去并回来玩游戏或者一切当时在做的事情。</p>]]></content>
<summary type="html">
&lt;blockquote&gt;
&lt;p&gt;原文地址:&lt;a href=&quot;http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exe
</summary>
<category term="Book" scheme="https://wangen.github.io/categories/Book/"/>
<category term="函数式编程" scheme="https://wangen.github.io/tags/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<category term="Java" scheme="https://wangen.github.io/tags/Java/"/>
</entry>
<entry>
<title>结合Layui实现iframe无刷新给父页面添加新数据</title>
<link href="https://wangen.github.io/2018/01/29/layui-layer-2/"/>
<id>https://wangen.github.io/2018/01/29/layui-layer-2/</id>
<published>2018-01-29T14:56:02.000Z</published>
<updated>2018-01-29T15:02:48.059Z</updated>
<content type="html"><![CDATA[<h2 id="需求概要"><a href="#需求概要" class="headerlink" title="需求概要"></a>需求概要</h2><p>在父页面会员列表点击【添加】操作,弹出iFrame弹层,包含输入input各项信息的表单,编辑完成提交后,将表单中input的value值传递给父页面,并且在父页面会员列表table中无刷新添加一行表格<code>&lt;tr&gt;</code>,模拟后台数据的提交与接收。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><blockquote><p><a href="http://layer.layui.com/" target="_blank" rel="noopener">layer:iframe-子父操作</a></p></blockquote><p>主要依赖参考:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//给父页面传值</span></span><br><span class="line">$(<span class="string">'#transmit'</span>).on(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> parent.$(<span class="string">'#parentIframe'</span>).text(<span class="string">'我被改变了'</span>);</span><br><span class="line"> parent.layer.tips(<span class="string">'Look here'</span>, <span class="string">'#parentIframe'</span>, &#123;<span class="attr">time</span>: <span class="number">5000</span>&#125;);</span><br><span class="line"> parent.layer.close(index);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><h2 id="优化实现方法"><a href="#优化实现方法" class="headerlink" title="优化实现方法"></a>优化实现方法</h2><p>frame页面确定增加时,触发给父页面传值事件。结合jQuery查询到父页面table的ID,将form表单提交的field值插入到父页面table结尾。以下示例代码,删除部分不需要内容:</p><h3 id="主要HTML代码"><a href="#主要HTML代码" class="headerlink" title="主要HTML代码"></a>主要HTML代码</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--父页面添加按钮操作--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"weadmin-block"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">"layui-btn layui-btn-danger"</span> <span class="attr">onclick</span>=<span class="string">"delAll()"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"layui-icon"</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span>批量删除<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">"layui-btn"</span> <span class="attr">onclick</span>=<span class="string">"WeAdminShow('添加用户','./add.html',600,400)"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"layui-icon"</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span>添加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--父页面会员列表--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">table</span> <span class="attr">class</span>=<span class="string">"layui-table"</span> <span class="attr">id</span>=<span class="string">"memberList"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">thead</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-unselect header layui-form-checkbox"</span> <span class="attr">lay-skin</span>=<span class="string">"primary"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"layui-icon"</span>&gt;</span>&amp;#xe605;<span class="tag">&lt;/<span class="name">i</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>ID<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>用户名<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>性别<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>手机<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>邮箱<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>地址<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>加入时间<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">th</span>&gt;</span>状态<span class="tag">&lt;/<span class="name">th</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">thead</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-unselect layui-form-checkbox"</span> <span class="attr">lay-skin</span>=<span class="string">"primary"</span> <span class="attr">data-id</span>=<span class="string">"2"</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">"layui-icon"</span>&gt;</span>&amp;#xe605;<span class="tag">&lt;/<span class="name">i</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>1<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>小明<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>男<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>13000000000<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>admin@mail.com<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>北京市 朝阳区<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span>&gt;</span>2017-01-01 11:11:42<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span> <span class="attr">class</span>=<span class="string">"td-status"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"layui-btn layui-btn-normal layui-btn-xs"</span>&gt;</span>已启用<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--子页面frame 主要表单代码实例--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">"layui-form"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_username"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>登录名<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_username"</span> <span class="attr">name</span>=<span class="string">"username"</span> <span class="attr">lay-verify</span>=<span class="string">"required|nikename"</span> <span class="attr">autocomplete</span>=<span class="string">"off"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-mid layui-word-aux"</span>&gt;</span></span><br><span class="line">请设置至少5个字符,将会成为您唯一的登录名</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_sex"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span>性别<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-block"</span> <span class="attr">id</span>=<span class="string">"L_sex"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"sex"</span> <span class="attr">value</span>=<span class="string">"男"</span> <span class="attr">title</span>=<span class="string">"男"</span> <span class="attr">checked</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"sex"</span> <span class="attr">value</span>=<span class="string">"女"</span> <span class="attr">title</span>=<span class="string">"女"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"sex"</span> <span class="attr">value</span>=<span class="string">"未知"</span> <span class="attr">title</span>=<span class="string">"未知"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_email"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>手机<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_phone"</span> <span class="attr">name</span>=<span class="string">"phone"</span> <span class="attr">lay-verify</span>=<span class="string">"required|phone"</span> <span class="attr">autocomplete</span>=<span class="string">"off"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_email"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>邮箱<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_email"</span> <span class="attr">name</span>=<span class="string">"email"</span> <span class="attr">lay-verify</span>=<span class="string">"email"</span> <span class="attr">autocomplete</span>=<span class="string">"off"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_repass"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">"layui-btn"</span> <span class="attr">lay-filter</span>=<span class="string">"add"</span> <span class="attr">lay-submit</span>=<span class="string">""</span>&gt;</span>增加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="主要JavaScript代码"><a href="#主要JavaScript代码" class="headerlink" title="主要JavaScript代码"></a>主要JavaScript代码</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">layui.use([<span class="string">'form'</span>, <span class="string">'layer'</span>], <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">$ = layui.jquery;</span><br><span class="line"><span class="keyword">var</span> form = layui.form,</span><br><span class="line">layer = layui.layer;</span><br><span class="line"><span class="comment">//监听提交</span></span><br><span class="line">form.on(<span class="string">'submit(add)'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line"><span class="built_in">console</span>.log(data.field);</span><br><span class="line"><span class="keyword">var</span> f = data.field; <span class="comment">//获取表单中提交的value</span></span><br><span class="line"><span class="comment">//发异步,把数据提交给php后台,此处模拟实现</span></span><br><span class="line">layer.alert(<span class="string">"增加成功"</span>, &#123;</span><br><span class="line">icon: <span class="number">6</span></span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="comment">// 获得frame索引</span></span><br><span class="line"><span class="keyword">var</span> index = parent.layer.getFrameIndex(<span class="built_in">window</span>.name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取父页面会员列表的长度,给每条数据赋值不同的data-id属性</span></span><br><span class="line"><span class="keyword">var</span> _len = parent.$(<span class="string">'#memberList tr'</span>).length;</span><br><span class="line">alert(_len);</span><br><span class="line"><span class="comment">//根据需求,按照父页面表格已有字段,在table结尾插入一组数据</span></span><br><span class="line">parent.$(<span class="string">'#memberList'</span>).append(</span><br><span class="line"><span class="string">'&lt;tr data-id="'</span> + _len + <span class="string">'"&gt;'</span> +</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;div class="layui-unselect layui-form-checkbox" lay-skin="primary" data-id="'</span> + _len + <span class="string">'"&gt;&lt;i class="layui-icon"&gt;&amp;#xe605;&lt;/i&gt;&lt;/div&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span> + _len + <span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+f.username+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+f.sex+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+f.phone+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+f.email+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;2018-01-01 11:11:42&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td class="td-status"&gt;&lt;span class="layui-btn layui-btn-normal layui-btn-xs"&gt;已启用&lt;/span&gt;&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/tr&gt;'</span></span><br><span class="line">);</span><br><span class="line"><span class="comment">//关闭当前frame</span></span><br><span class="line">parent.layer.close(index);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;);</span><br><span class="line">&#125;);</span><br><span class="line">&lt;<span class="regexp">/script&gt;</span></span><br></pre></td></tr></table></figure><h2 id="给父页面赋值后再添加的实现方法"><a href="#给父页面赋值后再添加的实现方法" class="headerlink" title="给父页面赋值后再添加的实现方法"></a>给父页面赋值后再添加的实现方法</h2><blockquote><p>根据自己的实际需求选择合适的实现方法最好,个人在此项实现场景中不推荐此方法,因为此项目中父页面对应多个frame子页面,每个frame子页面对应的代码写在自己页面内部,感觉可能代码会更规整一些。</p></blockquote><h3 id="实现思路:"><a href="#实现思路:" class="headerlink" title="实现思路:"></a>实现思路:</h3><p>在父页面创建一个隐藏的form表单用来接收frame子页面的传值,在父页面创建一个addMember()函数来在table尾部插入一组新数据;在iframe子页面编辑完成触发事件时,给父页面隐藏表单传值,然后执行父页面的addMember()函数。</p><h3 id="增加HTML主要代码"><a href="#增加HTML主要代码" class="headerlink" title="增加HTML主要代码"></a>增加HTML主要代码</h3><p>在以上实现方法基础上,新增隐藏form表单<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--列表页增加form表单,接收add页面传过来的值,模拟后台提交与接收--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">"layui-form"</span> <span class="attr">id</span>=<span class="string">"modalForm"</span> <span class="attr">style</span>=<span class="string">"display: none;"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_username"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>登录名</span><br><span class="line"> <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_username"</span> <span class="attr">name</span>=<span class="string">"username"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_sex"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span>性别<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_sex"</span> <span class="attr">name</span>=<span class="string">"sex"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_email"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>手机</span><br><span class="line"> <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_phone"</span> <span class="attr">name</span>=<span class="string">"phone"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_email"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>邮箱</span><br><span class="line"> <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"L_email"</span> <span class="attr">name</span>=<span class="string">"email"</span> <span class="attr">lass</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"L_pass"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"we-red"</span>&gt;</span>*<span class="tag">&lt;/<span class="name">span</span>&gt;</span>密码</span><br><span class="line"> <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-inline"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">id</span>=<span class="string">"L_pass"</span> <span class="attr">name</span>=<span class="string">"pass"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure></p><h3 id="增加JavaScript代码"><a href="#增加JavaScript代码" class="headerlink" title="增加JavaScript代码"></a>增加JavaScript代码</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//父页面创建addMember()函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">addMember</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="keyword">var</span> _len = $(<span class="string">'#memberList tr'</span>).length;</span><br><span class="line">alert(_len);</span><br><span class="line">$(<span class="string">'#memberList'</span>).append(</span><br><span class="line"><span class="string">'&lt;tr data-id="'</span> + _len + <span class="string">'"&gt;'</span> +</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;div class="layui-unselect layui-form-checkbox" lay-skin="primary" data-id="5"&gt;&lt;i class="layui-icon"&gt;&amp;#xe605;&lt;/i&gt;&lt;/div&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;5&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+$(<span class="string">'input[name="username"]'</span>).val()+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+$(<span class="string">'input[name="sex"]'</span>).val()+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+$(<span class="string">'input[name="phone"]'</span>).val()+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;'</span>+$(<span class="string">'input[name="email"]'</span>).val()+<span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;北京市西城区&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td&gt;2018-01-01 11:11:42&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td class="td-status"&gt;&lt;span class="layui-btn layui-btn-normal layui-btn-xs"&gt;已启用&lt;/span&gt;&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;td class="td-manage"&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;a onclick="member_stop(this,\'10001\')" href="javascript:;" title="启用"&gt;&lt;i class="layui-icon"&gt;&amp;#xe601;&lt;/i&gt;&lt;/a&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;a title="编辑" onclick="WeAdminShow(\'编辑\',\'./edit.html\',600,400)" href="javascript:;"&gt;&lt;i class="layui-icon"&gt;&amp;#xe642;&lt;/i&gt;&lt;/a&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;a onclick="WeAdminShow(\'修改密码\',\'./password.html\',600,400)" title="修改密码" href="javascript:;"&gt;&lt;i class="layui-icon"&gt;&amp;#xe631;&lt;/i&gt;&lt;/a&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;a title="删除" onclick="member_del(this,\'要删除的id\')" href="javascript:;"&gt;&lt;i class="layui-icon"&gt;&amp;#xe640;&lt;/i&gt;&lt;/a&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/td&gt;'</span>+</span><br><span class="line"><span class="string">'&lt;/tr&gt;'</span></span><br><span class="line">);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//frame子页面改写点击监听事件</span></span><br><span class="line"><span class="comment">//监听提交</span></span><br><span class="line">form.on(<span class="string">'submit(add)'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line"><span class="built_in">console</span>.log(data.field);</span><br><span class="line"><span class="keyword">var</span> f = data.field;</span><br><span class="line"><span class="comment">//发异步,把数据提交给php</span></span><br><span class="line">layer.alert(<span class="string">"增加成功"</span>, &#123;</span><br><span class="line">icon: <span class="number">6</span></span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="comment">// 获得frame索引</span></span><br><span class="line"><span class="keyword">var</span> index = parent.layer.getFrameIndex(<span class="built_in">window</span>.name);</span><br><span class="line"><span class="comment">//将form提交的值传递给父页面的隐藏表单对应的input值</span></span><br><span class="line">parent.$(<span class="string">'input[name="username"]'</span>).val(f.username);</span><br><span class="line">parent.$(<span class="string">'input[name="sex"]'</span>).val(f.sex);</span><br><span class="line">parent.$(<span class="string">'input[name="email"]'</span>).val(f.email);</span><br><span class="line">parent.$(<span class="string">'input[name="phone"]'</span>).val(f.phone);</span><br><span class="line">parent.$(<span class="string">'input[name="pass"]'</span>).val(f.pass);</span><br><span class="line"><span class="comment">//然后执行父页面的addMember()函数</span></span><br><span class="line">parent.addMember();</span><br><span class="line"><span class="comment">//关闭当前frame</span></span><br><span class="line">parent.layer.close(index);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
&lt;h2 id=&quot;需求概要&quot;&gt;&lt;a href=&quot;#需求概要&quot; class=&quot;headerlink&quot; title=&quot;需求概要&quot;&gt;&lt;/a&gt;需求概要&lt;/h2&gt;&lt;p&gt;在父页面会员列表点击【添加】操作,弹出iFrame弹层,包含输入input各项信息的表单,编辑完成提交后,将表单中input
</summary>
<category term="layui" scheme="https://wangen.github.io/categories/layui/"/>
<category term="layui" scheme="https://wangen.github.io/tags/layui/"/>
<category term="layer" scheme="https://wangen.github.io/tags/layer/"/>
<category term="iframe" scheme="https://wangen.github.io/tags/iframe/"/>
</entry>
<entry>
<title>使用layer的iframe层提交表单后,关闭当前iframe,然后刷新父页面</title>
<link href="https://wangen.github.io/2018/01/28/layui-layer-1/"/>
<id>https://wangen.github.io/2018/01/28/layui-layer-1/</id>
<published>2018-01-28T06:51:05.000Z</published>
<updated>2018-01-28T06:52:34.680Z</updated>
<content type="html"><![CDATA[<p>需求:需要使用iframe来实现添加新账号的功能,在iframe页面中通过表单提交新账号的资料后,关闭iframe页面,并且刷新父页面账号列表。</p><h2 id="layer参考"><a href="#layer参考" class="headerlink" title="layer参考"></a>layer参考</h2><p>layer独立组件官网:<a href="http://layer.layui.com/" target="_blank" rel="noopener">http://layer.layui.com/</a><br>layui文档:<a href="http://www.layui.com/doc/modules/layer.html" target="_blank" rel="noopener">弹层组件文档</a></p><blockquote><p>iframe层-父子操作子页面主要代码<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//给父页面传值</span></span><br><span class="line">$(<span class="string">'#transmit'</span>).on(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"> parent.$(<span class="string">'#parentIframe'</span>).text(<span class="string">'我被改变了'</span>);</span><br><span class="line"> parent.layer.tips(<span class="string">'Look here'</span>, <span class="string">'#parentIframe'</span>, &#123;<span class="attr">time</span>: <span class="number">5000</span>&#125;);</span><br><span class="line"> parent.layer.close(index);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p></blockquote><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>直接在iframe页面通过<code>$(&#39;#transmit&#39;).on(&#39;click&#39;, function(){});</code>来执行关闭及刷新操作,会造成本页面的form表单无法提交到后台,因此换用ajax来提交form表单,判断ajax提交成功/失败后,再进行父页面传值等操作。</p><h2 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h2><p>主要代码如下:</p><h3 id="HTML相关代码"><a href="#HTML相关代码" class="headerlink" title="HTML相关代码"></a>HTML相关代码</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">"form-horizontal"</span> <span class="attr">id</span>=<span class="string">"myform"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"box-body"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group col-sm-6"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"inputAccount1"</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>微信号<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> <span class="attr">id</span>=<span class="string">"inputAccount1"</span> <span class="attr">placeholder</span>=<span class="string">"微信号"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group col-sm-6"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"inputAccount2"</span> <span class="attr">class</span>=<span class="string">"col-sm-4 control-label"</span>&gt;</span>手机号<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> <span class="attr">id</span>=<span class="string">"inputAccount2"</span> <span class="attr">placeholder</span>=<span class="string">"手机号"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group col-sm-12"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"inputAccount3"</span> <span class="attr">class</span>=<span class="string">"col-sm-2 control-label"</span>&gt;</span>二维码<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-sm-10"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"javascript:;"</span> <span class="attr">id</span>=<span class="string">"inputAccount3"</span> <span class="attr">class</span>=<span class="string">"upload"</span>&gt;</span>点击上传图片<span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">"change"</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">multiple</span>=<span class="string">"multiple"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="js相关代码"><a href="#js相关代码" class="headerlink" title="js相关代码"></a>js相关代码</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">"/js/jquery-2.2.3.min.js"</span>&gt;<span class="xml"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line">&lt;script src=<span class="string">"/js/layer/layer.min.js"</span>&gt;<span class="xml"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line">&lt;script type=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line"><span class="keyword">var</span> index = parent.layer.getFrameIndex(<span class="built_in">window</span>.name);</span><br><span class="line"><span class="comment">//获取iframe父页面索引</span></span><br><span class="line"> $(<span class="string">'form'</span>).submit(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> $.ajax(&#123;</span><br><span class="line"> url:<span class="string">"url"</span>,</span><br><span class="line"> type:<span class="string">"post"</span>,</span><br><span class="line"> data:$(<span class="keyword">this</span>).serialize(),</span><br><span class="line"> success:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line"> <span class="comment">//console.log(data);</span></span><br><span class="line"> parent.location.reload(); <span class="comment">//刷新父页面</span></span><br><span class="line"> parent.layer.close(index); <span class="comment">//关闭当前页面,写在最后面</span></span><br><span class="line"> &#125;,</span><br><span class="line"> error:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line"> <span class="comment">//console.log("Error~");</span></span><br><span class="line"> <span class="comment">//console.log(data);</span></span><br><span class="line"> parent.location.reload();</span><br><span class="line"> parent.layer.close(index);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;); </span><br><span class="line">&#125;);</span><br><span class="line">&lt;<span class="regexp">/script&gt;</span></span><br></pre></td></tr></table></figure><h3 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h3><p>关于layer弹层iframe窗的子父操作,<code>parent.layer.close(index)</code>这个关闭操作一定要写在最后面,大概是因为执行关闭执行,其他操作就不会执行了。</p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><blockquote><p>参考文档1:<a href="http://blog.csdn.net/u011848397/article/details/52353226?locationNum=11" target="_blank" rel="noopener">layer弹窗iframe页面,关闭弹窗方法导致form表单无法提交到服务器</a><br>参考文档2:<a href="http://blog.csdn.net/u011020900/article/details/52083166" target="_blank" rel="noopener">使用layer的iframe层提交表单后,需要关闭当前的iframe层,然后刷新父页面的方法</a></p></blockquote>]]></content>
<summary type="html">
&lt;p&gt;需求:需要使用iframe来实现添加新账号的功能,在iframe页面中通过表单提交新账号的资料后,关闭iframe页面,并且刷新父页面账号列表。&lt;/p&gt;
&lt;h2 id=&quot;layer参考&quot;&gt;&lt;a href=&quot;#layer参考&quot; class=&quot;headerlink&quot; title
</summary>
<category term="layui" scheme="https://wangen.github.io/categories/layui/"/>
<category term="layui" scheme="https://wangen.github.io/tags/layui/"/>
<category term="layer" scheme="https://wangen.github.io/tags/layer/"/>
<category term="iframe" scheme="https://wangen.github.io/tags/iframe/"/>
</entry>
<entry>
<title>Web前端学习参考网站备忘</title>
<link href="https://wangen.github.io/2018/01/23/web-dom-1/"/>
<id>https://wangen.github.io/2018/01/23/web-dom-1/</id>
<published>2018-01-23T14:18:45.000Z</published>
<updated>2018-01-23T15:30:02.131Z</updated>
<content type="html"><![CDATA[<h3 id="前端参考文档"><a href="#前端参考文档" class="headerlink" title="前端参考文档"></a>前端参考文档</h3><p><a href="http://caibaojian.com/book/" target="_blank" rel="noopener">精选推荐教程 · 技术文档-在线教程</a></p>]]></content>
<summary type="html">
&lt;h3 id=&quot;前端参考文档&quot;&gt;&lt;a href=&quot;#前端参考文档&quot; class=&quot;headerlink&quot; title=&quot;前端参考文档&quot;&gt;&lt;/a&gt;前端参考文档&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;http://caibaojian.com/book/&quot; target=&quot;_blank&quot;
</summary>
<category term="study" scheme="https://wangen.github.io/categories/study/"/>
<category term="Web" scheme="https://wangen.github.io/tags/Web/"/>
<category term="前端" scheme="https://wangen.github.io/tags/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>jQuery不同版本库同时引入冲突解决办法</title>
<link href="https://wangen.github.io/2018/01/21/jQuery-clash-1/"/>
<id>https://wangen.github.io/2018/01/21/jQuery-clash-1/</id>
<published>2018-01-21T09:08:15.000Z</published>
<updated>2018-01-21T09:26:26.279Z</updated>
<content type="html"><![CDATA[<blockquote><p>jQuery多个版本或和其他js库冲突主要是常用的$符号的冲突。</p></blockquote><h2 id="一、常规解决办法"><a href="#一、常规解决办法" class="headerlink" title="一、常规解决办法"></a>一、常规解决办法</h2><p>在同一页面中引入了多个版本的jQuery,导致js失效,可以去掉其中一个版本的jQuery,但是最好保证jQuery的引入在其他js之前。优先尝试保留新版本jQuery,注释掉旧版本的;如若不行,尝试保留旧版本的jQuery。<br>但是有一些特殊情况:我们引入的js插件,有的依赖于新版本jQuery的特性,有的依赖于旧版本jQuery的特性,比如说,你的业务代码采用了最新版的jQuery库,而你选用的第三方插件依赖的更早版本的jQuery库(大多数原因是js插件未持续更新);又比如说,你正维护着一个系统,它已有的业务代码由于各种原因,引用了较老版本的jQuery库,你新开发的模块采用的是其他版本的jQuery库。这种情况又该如何处理?</p><p><center><br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/jqueryClash101.jpg" alt="jQuery-clash-1"><br></center><br>最直白的办法,寻找其他可替换的js插件,只保留一个jQuery即可。但是有时候我们必须保留现有的js插件,也就是说两个版本的jQuery都必须保留,怎么办?请继续往下看:</p><h2 id="二、认识jQuery-noConflict"><a href="#二、认识jQuery-noConflict" class="headerlink" title="二、认识jQuery.noConflict()"></a>二、认识jQuery.noConflict()</h2><p>jQuery是目前使用最广泛的前端框架之一,有大量的第三方库和插件基于它开发。为了避免全局命名空间污染,jQuery提供了jQuery.noConflict()方法解决变量冲突。这个方法,毫无疑问,非常有效。遗憾的是,jQuery的官方文档对该方法的描述不够清晰,许多开发者并不清楚当他们调用jQuery.noConflict()时,究竟发生了什么,从而导致在使用时出现了许多问题。尽管如此,jQuery.noConflict()背后实现原理依然值得Web开发者学习掌握,成为解决类似全局命名空间污染问题的利器。</p><h3 id="1、jQuery-noConflict-的作用?"><a href="#1、jQuery-noConflict-的作用?" class="headerlink" title="1、jQuery.noConflict()的作用?"></a>1、jQuery.noConflict()的作用?</h3><p>jQuery.noConflict()的存在只有一个目的:它允许你在同一个页面加载多个jQuery实例,尤其是不同版本的jQuery。在多版本jQuery共存时,不得不面对jQuery对象/方法冲突的问题。幸运的是,jQuery.noConflict()帮你解决了这个烦恼。</p><h3 id="2、jQuery被加载时发生了什么?"><a href="#2、jQuery被加载时发生了什么?" class="headerlink" title="2、jQuery被加载时发生了什么?"></a>2、jQuery被加载时发生了什么?</h3><p>当jQuery被页面引用/加载时,它被封装在一个自执行函数(匿名函数)里,它提供的所有一切变量、函数、对象都在匿名函数内部的可执行环境内,外部环境无法调用,以防止全局命名空间污染。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">"//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"</span>&gt;&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><p>jQuery在匿名函数内部定义了两个全局对象:<code>jQuery</code>和<code>$</code>,把自己暴露给外部环境。开发者习惯使用的各种公共方法都是通过这两个对象进行访问的,如jQuery.ajax()/jQuery.css()等。在最初,它们指向匿名函数内部的同一个对象jQuery(私有变量),通过它访问匿名函数内部的私有变量和函数。这使得匿名函数在自执行后其内部的私有变量和函数仍然进驻在内存里,不会被javascript的垃圾回收机制清除。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">window.jQuery = window.$ = jQuery;</span><br></pre></td></tr></table></figure></p><p>当jQuery被页面加载后,当前页面有可能已经存在了<code>jQuery</code>和<code>$</code>这两个全局变量(比如,加载了其它的第三方库,其内部也定义了它俩),这就会导致已经存在的对象被覆盖(全局命名空间污染)。为了解决这个问题,jQuery在内部先将已经存在的全局变量缓存起来,保存在私有变量_jQuery和_\$中,供后续调用。所以,如果页面在加载jQuery库时,还不存在<code>jQuery</code>和<code>$</code>对象,那么_jQuery和_\$都是undefined;否则,它们都会保存对已有<code>jQuery</code>和<code>$</code>的引用(也许来自之前引用的第三方库或是不同版本的jQuery库)。之后,jQuery会像上文说描述的那样,覆盖这两个全局变量并将自己暴露给外部环境。至此,页面上的全局变量<code>jQuery</code>和<code>$</code>已经指向刚刚引入的jQuery库。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">// Map over jQuery <span class="keyword">in</span> <span class="keyword">case</span> of overwrite</span><br><span class="line">_jQuery = window.jQuery,</span><br><span class="line"></span><br><span class="line">// Map over the $ <span class="keyword">in</span> <span class="keyword">case</span> of overwrite</span><br><span class="line">_$ = window.$,</span><br><span class="line"></span><br><span class="line">// Otherwise expose jQuery to the global object as usual</span><br><span class="line">window.jQuery = window.$ = jQuery;</span><br></pre></td></tr></table></figure></p><h3 id="3、jQuery-noConflict-的神奇效果?"><a href="#3、jQuery-noConflict-的神奇效果?" class="headerlink" title="3、jQuery.noConflict()的神奇效果?"></a>3、jQuery.noConflict()的神奇效果?</h3><p>假设你维护的系统已经引用了1.7.0版本的jQuery库,而你在新添加的功能里引用了1.10.2版本的jQuery库。那么,还有办法重新使用jQuery 1.7.0 或是同时使用两个版本的jQuery库吗?答案是肯定,那就是jQuery.noConflict()。实际上,利用jQuery.noConflict(),你可以立刻把全局变量<code>jQuery</code>和<code>$</code>重新指向之前引用的对象。很神奇吧?这就是为什么jQuery在对外暴露自己前内部缓存了之前引用的对象。<br>jQuery.noConflict()接受一个可选的布尔值参数,通常默认值是false。这个参数会带来什么影响呢?其实,很简单。如果调用jQuery.noConflict()或是jQuery.noConflict(false),只有全局变量<code>$</code>会被重置恢复成之前的引用值;如果调用jQuery.noConflict(true),那么全局变量<code>jQuery</code>和<code>$</code>都会被重置恢复成之前的引用值。<strong>这一点非常重要,建议牢记</strong>。当你调用jQuery.noConflict(false/true)之后,它会返回当前jQuery的实例,利用这个特性我们可以实现jQuery的重命名。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// <span class="string">"Renaming"</span> jQuery</span><br><span class="line">var jayquery = jQuery.noConflict( <span class="literal">true</span> );</span><br><span class="line">// Now we can call things like jayquery.ajax(), jayquery.css(), and so on</span><br></pre></td></tr></table></figure></p><p>我们再来看一个代码片段,测试一下是否真正理解了神奇的noConflict()<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- jQuery and $ are undefined --&gt;</span><br><span class="line">&lt;script src=<span class="string">"//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;!-- jQuery and $ now point to jQuery 1.10.2 --&gt;</span><br><span class="line">&lt;script src=<span class="string">"//ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"</span>&gt;</span><br><span class="line">&lt;!-- jQuery and $ now point to jQuery 1.7.0 --&gt;</span><br><span class="line">&lt;script&gt;jQuery.noConflict();&lt;/script&gt;</span><br><span class="line">&lt;!-- jQuery still points to jQuery 1.7.0; $ now points to jQuery 1.10.2 --&gt;</span><br><span class="line">&lt;script src=<span class="string">"//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"</span>&gt;</span><br><span class="line">&lt;!-- jQuery and $ now point to jQuery 1.6.4 --&gt;</span><br><span class="line">&lt;script&gt;var jquery164 = jQuery.noConflict( <span class="literal">true</span> );&lt;/script&gt;</span><br><span class="line">&lt;!-- jQuery now points to jQuery 1.7.0; $ now points to jQuery 1.10.2; jquery164 points to jQuery 1.6.4 --&gt;</span><br></pre></td></tr></table></figure></p><h3 id="4、避免第三方库的冲突"><a href="#4、避免第三方库的冲突" class="headerlink" title="4、避免第三方库的冲突"></a>4、避免第三方库的冲突</h3><p>以上的代码片段展示了如何解决多版本jQuery的冲突。接下来,我们尝试解决jQuery库和第三方库的冲突,下面出现的代码片段在jQuery的官方文档中都有,有兴趣的程序猿可以仔细阅读官方文档体会其中的区别。</p><h4 id="直接使用No-Conflict模式"><a href="#直接使用No-Conflict模式" class="headerlink" title="直接使用No-Conflict模式"></a>直接使用No-Conflict模式</h4><p>使用No-Conflict模式,其实就是对jQuery进行重命名,再调用。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 采用no-conflict模式,jquery.js在prototype.js之后被引入. --&gt;</span><br><span class="line">&lt;script src=<span class="string">"prototype.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"jquery.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var <span class="variable">$j</span> = jQuery.noConflict();</span><br><span class="line"> // <span class="variable">$j</span> 引用了jQuery对象本身.</span><br><span class="line"> <span class="variable">$j</span>(document).ready(<span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> <span class="variable">$j</span>( <span class="string">"div"</span> ).hide();</span><br><span class="line"> &#125;);</span><br><span class="line"> // $ 被重新指向prototype.js里定义的对象</span><br><span class="line"> // document.getElementById(). mainDiv below is a DOM element, not a jQuery object.</span><br><span class="line"> window.onload = <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> var mainDiv = $( <span class="string">"main"</span> );</span><br><span class="line"> &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><h4 id="使用自执行函数封装"><a href="#使用自执行函数封装" class="headerlink" title="使用自执行函数封装"></a>使用自执行函数封装</h4><p>使用这种方式,你可以在匿名函数内部继续使用标准的<code>$</code>对象,这也是众多jQuery插件采用的方法。需要注意的是,使用这种方法,函数内部无法再使用prototype.js定义的<code>$</code>对象了。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- jquery.js在prototype.js之后被引入. --&gt;</span><br><span class="line">&lt;script src=<span class="string">"prototype.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"jquery.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> jQuery.noConflict();</span><br><span class="line"> (<span class="keyword">function</span>( $ ) &#123;</span><br><span class="line"> // Your jQuery code here, using the $</span><br><span class="line"> &#125;)( jQuery );</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><h4 id="使用标准jQuery-document-ready-函数"><a href="#使用标准jQuery-document-ready-函数" class="headerlink" title="使用标准jQuery(document).ready()函数"></a>使用标准jQuery(document).ready()函数</h4><p>如果jQuery库在其它库之前引入,那么jQuery内部定义的<code>jQuery</code>和<code>$</code>会被第三方库覆盖,这时候再使用noConflict()已经没有什么意义了。解决的方法很简单,直接使用jQuery的标准调用方式。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- jquery.js在prototype.js之前被引入. --&gt;</span><br><span class="line">&lt;script src=<span class="string">"jquery.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"prototype.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> // Use full jQuery <span class="keyword">function</span> name to reference jQuery.</span><br><span class="line"> jQuery( document ).ready(<span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> jQuery( <span class="string">"div"</span> ).hide();</span><br><span class="line"> &#125;);</span><br><span class="line"> // 或者</span><br><span class="line"> jQuery(<span class="keyword">function</span>($)&#123;</span><br><span class="line"> // Your jQuery code here, using the $</span><br><span class="line"> &#125;);</span><br><span class="line"> // Use the $ variable as defined <span class="keyword">in</span> prototype.js</span><br><span class="line"> window.onload = <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> var mainDiv = $( <span class="string">"main"</span> );</span><br><span class="line"> &#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><h2 id="三、冲突的解决"><a href="#三、冲突的解决" class="headerlink" title="三、冲突的解决"></a>三、冲突的解决</h2><p>jQuery.noConflict()是解决jQuery冲突的主力军,通过不同情形下的调用来解决不同版本库共存的冲突。</p><h3 id="1、同一页面jQuery多个版本冲突解决方法"><a href="#1、同一页面jQuery多个版本冲突解决方法" class="headerlink" title="1、同一页面jQuery多个版本冲突解决方法"></a>1、同一页面jQuery多个版本冲突解决方法</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 引入1.6.4版的jq --&gt;</span><br><span class="line">&lt;script src=<span class="string">"http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt; var jq164 = jQuery.noConflict(<span class="literal">true</span>); &lt;/script&gt;</span><br><span class="line">&lt;!-- 引入1.4.2版的jq --&gt;</span><br><span class="line">&lt;script src=<span class="string">"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt; var jq142 = jQuery.noConflict(<span class="literal">true</span>); &lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">(<span class="keyword">function</span>($)&#123;</span><br><span class="line"> //此时的$是jQuery-1.6.4</span><br><span class="line"> $(<span class="string">'#'</span>);</span><br><span class="line">&#125;)(jq164);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"> </span><br><span class="line">&lt;script&gt;</span><br><span class="line">jq142(<span class="keyword">function</span>($)&#123;</span><br><span class="line"> //此时的$是jQuery-1.4.2</span><br><span class="line"> $(<span class="string">'#'</span>);</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"> </span><br><span class="line">&lt;/body&gt;</span><br></pre></td></tr></table></figure><h3 id="2、jQuery库在其他库之后导入"><a href="#2、jQuery库在其他库之后导入" class="headerlink" title="2、jQuery库在其他库之后导入"></a>2、jQuery库在其他库之后导入</h3><blockquote><p>jQuery noConflict() 方法会释放会 $ 标识符的控制,这样其他脚本就可以使用它了。</p></blockquote><h4 id="2-1-可以通过jQuery全名替代简写的方式来使用-jQuery"><a href="#2-1-可以通过jQuery全名替代简写的方式来使用-jQuery" class="headerlink" title="2-1 可以通过jQuery全名替代简写的方式来使用 jQuery"></a>2-1 可以通过jQuery全名替代简写的方式来使用 jQuery</h4><p>在其他库和jQuery库都加载完毕后,可以在任何时候调用jQuery.noConflict()函数来将变量$的控制权移交给其他JavaSript库。然后就可以在程序里将jQuery()函数作为jQuery对象的制造工厂。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">"prototype.js"</span> <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"jquery.js"</span> <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;p id=<span class="string">"pp"</span>&gt;<span class="built_in">test</span>---prototype&lt;/p&gt;</span><br><span class="line">&lt;p&gt;<span class="built_in">test</span>---jQuery&lt;/p&gt;</span><br><span class="line"></span><br><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">jQuery.noConflict(); </span><br><span class="line">//将变量$的控制权让渡给prototype.js,全名可以不调用。</span><br><span class="line">jQuery(<span class="function"><span class="title">function</span></span>()&#123; //使用jQuery</span><br><span class="line"> jQuery(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> alert( jQuery(this).text() );</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line">//此处不可以再写成$,此时的$代表prototype.js中定义的$符号。</span><br><span class="line"></span><br><span class="line">$(<span class="string">"pp"</span>).style.display = <span class="string">'none'</span>; //使用prototype</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h4 id="2-2-自定义一个快捷方式"><a href="#2-2-自定义一个快捷方式" class="headerlink" title="2-2 自定义一个快捷方式"></a>2-2 自定义一个快捷方式</h4><blockquote><p>noConflict() 可返回对 jQuery 的引用,可以把它存入自定义名称,例如jq,$J变量,以供稍后使用。</p></blockquote><p>这样可以确保jQuery不会与其他库冲突,同时又使用自定义一个快捷方式。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">var <span class="variable">$j</span> = jQuery.noConflict(); //自定义一个比较短快捷方式</span><br><span class="line"><span class="variable">$j</span>(<span class="function"><span class="title">function</span></span>()&#123; //使用jQuery</span><br><span class="line"> <span class="variable">$j</span>(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> alert( <span class="variable">$j</span>(this).text() );</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">$(<span class="string">"pp"</span>).style.display = <span class="string">'none'</span>; //使用prototype</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h4 id="2-3-在不冲突的情况下仍然用"><a href="#2-3-在不冲突的情况下仍然用" class="headerlink" title="2-3 在不冲突的情况下仍然用$"></a>2-3 在不冲突的情况下仍然用$</h4><p>如果想在jQuery 代码块使用 \$ 简写,不愿意改变这个快捷方式,可以把 \$ 符号作为变量传递给 ready 方法。这样就可以在函数内使用 \$ 符号了 , 而在函数外,依旧不得不使用 “jQuery”。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">jQuery.noConflict(); //将变量$的控制权让渡给prototype.js</span><br><span class="line">jQuery(document).ready(<span class="keyword">function</span>($)&#123;</span><br><span class="line"> $(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123; //继续使用 $ 方法</span><br><span class="line"> alert( $(this).text() );</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line">//或者如下</span><br><span class="line">jQuery(<span class="keyword">function</span>($)&#123; //使用jQuery</span><br><span class="line"> $(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123; //继续使用 $ 方法</span><br><span class="line"> alert( $(this).text() );</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>或者使用IEF语句块,这应该是最理想的方式,因为可以通过改变最少的代码来实现全面的兼容性。</p><p>在我们自己写jquery插件时,应该都使用这种写法,因为我们不知道具体工作过程中是如何顺序引入各种js库的,而这种语句块的写法却能屏蔽冲突。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">jQuery.noConflict(); //将变量$的控制权让渡给prototype.js</span><br><span class="line">(<span class="keyword">function</span>($)&#123; //定义匿名函数并设置形参为$</span><br><span class="line"> $(<span class="function"><span class="title">function</span></span>()&#123; //匿名函数内部的$均为jQuery</span><br><span class="line"> $(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123; //继续使用 $ 方法</span><br><span class="line"> alert($(this).text());</span><br><span class="line"> &#125;);</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;)(jQuery); //执行匿名函数且传递实参jQuery</span><br><span class="line"></span><br><span class="line">$(<span class="string">"pp"</span>).style.display = <span class="string">'none'</span>; //使用prototype</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="3、jQuery库在其他库之前导入"><a href="#3、jQuery库在其他库之前导入" class="headerlink" title="3、jQuery库在其他库之前导入"></a>3、jQuery库在其他库之前导入</h3><blockquote><p>jQuery库在其他库之前导入,$的归属权默认归后面的JavaScript库所有。那么可以直接使用”jQuery”来做一些jQuery的工作。</p></blockquote><p>同时,可以使用$()方法作为其他库的快捷方式。这里无须调用jQuery.noConflict()函数。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 引入 jQuery --&gt;</span><br><span class="line">&lt;script src=<span class="string">"../../scripts/jquery.js"</span> <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;!-- 引入 prototype --&gt;</span><br><span class="line">&lt;script src=<span class="string">"lib/prototype.js"</span> <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;p id=<span class="string">"pp"</span>&gt;Test-prototype(将被隐藏)&lt;/p&gt;</span><br><span class="line">&lt;p &gt;Test-jQuery(将被绑定单击事件)&lt;/p&gt;</span><br><span class="line"></span><br><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">jQuery(<span class="function"><span class="title">function</span></span>()&#123; //直接使用 jQuery ,没有必要调用<span class="string">"jQuery.noConflict()"</span>函数。</span><br><span class="line"> jQuery(<span class="string">"p"</span>).click(<span class="function"><span class="title">function</span></span>()&#123; </span><br><span class="line"> alert( jQuery(this).text() );</span><br><span class="line"> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">$(<span class="string">"pp"</span>).style.display = <span class="string">'none'</span>; //使用prototype</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;/body&gt;</span><br></pre></td></tr></table></figure><h2 id="四、原理"><a href="#四、原理" class="headerlink" title="四、原理"></a>四、原理</h2><h3 id="1、源码"><a href="#1、源码" class="headerlink" title="1、源码"></a>1、源码</h3><p>源码:看一下源码里怎么做到的</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">var</span><br><span class="line">// Map over jQuery <span class="keyword">in</span> <span class="keyword">case</span> of overwrite</span><br><span class="line">_jQuery = window.jQuery,</span><br><span class="line"></span><br><span class="line">// Map over the $ <span class="keyword">in</span> <span class="keyword">case</span> of overwrite</span><br><span class="line">_$ = window.$,</span><br><span class="line"></span><br><span class="line">jQuery.extend(&#123;</span><br><span class="line"> noConflict: <span class="keyword">function</span>( deep ) &#123;</span><br><span class="line"> <span class="keyword">if</span> ( window.$ === jQuery ) &#123;</span><br><span class="line"> window.$ = _$;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ( deep &amp;&amp; window.jQuery === jQuery ) &#123;</span><br><span class="line"> window.jQuery = _jQuery;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> jQuery;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>在jQuery加载的时候,通过事先声明的<em>jQuery变量获取到当前window.jQuery,通过\</em>$ 获取到当前<code>window.$</code>。</p><p>通过jQuery.extend()把noConflict挂载到jQuery下面。所以我们在调用的时候都是jQuery.noConflict()这样调。</p><p>在调用noConflict()时做了2个判断,</p><p>第一个if,把$的控制权交出去。</p><p>第二个if,在noConflict()传参的时候把,jQuery的控制权交出去。</p><p>最后noConflict()返回jQuery对象,用哪个参数接收,哪个参数将拥有jQuery的控制权。</p><h3 id="2、-验证"><a href="#2、-验证" class="headerlink" title="2、 验证"></a>2、 验证</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">//冲突 </span><br><span class="line">var $ = 123; //假设其他库中$为123</span><br><span class="line">$(</span><br><span class="line"> <span class="function"><span class="title">function</span></span> () &#123;</span><br><span class="line"> console.log($); </span><br><span class="line"> <span class="comment"># //报错Uncaught TypeError: $ is not a function</span></span><br><span class="line"> &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>解决冲突<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#//解决冲突</span></span><br><span class="line">var jq = $.noConflict();</span><br><span class="line">var $ = 123;</span><br><span class="line">jq(<span class="function"><span class="title">function</span></span> () &#123;</span><br><span class="line"> alert($); //123</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><h4 id="释放-控制权例子"><a href="#释放-控制权例子" class="headerlink" title="释放\$控制权例子"></a>释放\$控制权例子</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"> var $ = 123; // window.$是123,存储在私有的_$上。</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"https://code.jquery.com/jquery-2.2.4.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;div&gt;aaa&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var jq = $.noConflict();</span><br><span class="line"> <span class="comment">#//当window.$===jQuery的时候,把_$赋给了window.$。</span></span><br><span class="line"> jq(<span class="function"><span class="title">function</span></span> () &#123;</span><br><span class="line"> alert($); //123</span><br><span class="line"> &#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">``` </span><br><span class="line"><span class="comment">#### 释放jQuery控制权例子</span></span><br><span class="line"></span><br><span class="line">参数deep的作用:deep用来放弃jQuery对外的接口。</span><br><span class="line">如下,noConflict()不写参数,弹出jQuery为构造函数。</span><br><span class="line"></span><br><span class="line">``` bash</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var $ = 123;</span><br><span class="line"> var jQuery=456;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"https://code.jquery.com/jquery-2.0.3.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;div&gt;aaa&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var jq = $.noConflict();</span><br><span class="line"> jq(<span class="function"><span class="title">function</span></span> () &#123;</span><br><span class="line"> alert(jQuery); //构造函数</span><br><span class="line"> &#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>如果写个参数true,会弹出456。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"> var $ = 123;</span><br><span class="line"> var jQuery=456;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;script src=<span class="string">"https://code.jquery.com/jquery-2.0.3.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;div&gt;aaa&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var jq = $.noConflict(<span class="literal">true</span>);</span><br><span class="line"><span class="comment">#//写了true或者参数的时候,deep为真window.jQuery===jQuery为真,所以进入if条件。把456赋值给window.jQuery</span></span><br><span class="line"> jq(<span class="function"><span class="title">function</span></span> () &#123;</span><br><span class="line"> alert(jQuery); //456</span><br><span class="line"> &#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,留下参考教程,方便追根溯源。</p><blockquote><p>1、<a href="http://www.cnblogs.com/starof/p/6855186.html" target="_blank" rel="noopener">starof:jQuery库冲突解决办法</a><br>2、<a href="http://www.jb51.net/article/90293.htm" target="_blank" rel="noopener">jQuery多个版本和其他js库冲突的解决方法</a><br>3、<a href="https://www.cnblogs.com/laoyu/p/5189750.html" target="_blank" rel="noopener">老俞:三分钟玩转jQuery.noConflict()</a></p></blockquote>]]></content>
<summary type="html">
&lt;blockquote&gt;
&lt;p&gt;jQuery多个版本或和其他js库冲突主要是常用的$符号的冲突。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;一、常规解决办法&quot;&gt;&lt;a href=&quot;#一、常规解决办法&quot; class=&quot;headerlink&quot; title=&quot;一、常规解决办法&quot;
</summary>
<category term="jQuery" scheme="https://wangen.github.io/categories/jQuery/"/>
<category term="jQuery" scheme="https://wangen.github.io/tags/jQuery/"/>
<category term="冲突" scheme="https://wangen.github.io/tags/%E5%86%B2%E7%AA%81/"/>
</entry>
<entry>
<title>dedecms织梦特定条件下,隐藏特定栏目的方法,通过css实现</title>
<link href="https://wangen.github.io/2018/01/20/dede-list-3/"/>
<id>https://wangen.github.io/2018/01/20/dede-list-3/</id>
<published>2018-01-20T13:54:52.000Z</published>
<updated>2018-01-20T14:13:32.674Z</updated>
<content type="html"><![CDATA[<h2 id="一、通过前台直接隐藏栏目"><a href="#一、通过前台直接隐藏栏目" class="headerlink" title="一、通过前台直接隐藏栏目"></a>一、通过前台直接隐藏栏目</h2><blockquote><p>如果栏目在后台设置显示或者设置隐藏无效,前台怎么隐藏?</p></blockquote><h3 id="CSS样式"><a href="#CSS样式" class="headerlink" title="CSS样式"></a>CSS样式</h3><p>定义用来隐藏栏目的CSS样式<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.hidden&#123;display:nidden&#125;</span><br></pre></td></tr></table></figure></p><h3 id="HTML调用代码"><a href="#HTML调用代码" class="headerlink" title="HTML调用代码"></a>HTML调用代码</h3><p>因为栏目id为6的栏目是【关于我们】等非核心栏目,不想在导航上显示,但在后台又没有设置隐藏,设置隐藏了前台的其它栏目页就没法调用他了。所以,在导航条上要处理一下。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;dede:channel <span class="built_in">type</span>=<span class="string">'top'</span> row=<span class="string">'10'</span> currentstyle=<span class="string">"&lt;li class='active'&gt;&lt;a href='~typelink~' ~rel~&gt;~typename~&lt;/a&gt;&lt;/li&gt;"</span>&#125;</span><br><span class="line"> &lt;li class=<span class="string">"[field:id runphp='yes'] if(@me=='6') @me = 'hidden'; else @me = '';[/field:id]"</span> &gt;</span><br><span class="line"> &lt;a href=<span class="string">'[field:typeurl/]'</span>&gt;[field:typename/]&lt;/a&gt;</span><br><span class="line"> &lt;/li&gt;</span><br><span class="line">&#123;/dede:channel&#125;</span><br></pre></td></tr></table></figure><h2 id="二、前台单独显示隐藏栏目"><a href="#二、前台单独显示隐藏栏目" class="headerlink" title="二、前台单独显示隐藏栏目"></a>二、前台单独显示隐藏栏目</h2><blockquote><p>如果ID为666的栏目在后台设置隐藏,而在前台想让他单独显示在导航条的右侧,怎么实现?代码如下所示:</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># //调用首页</span></span><br><span class="line">&lt;li &#123;dede:field name=id runphp=<span class="string">'yes'</span>&#125;(@me==<span class="string">''</span>)?@me=<span class="string">"class='active'"</span>:@me=<span class="string">''</span>;&#123;/dede:field&#125; &gt;</span><br><span class="line"> &lt;a href=<span class="string">"&#123;dede:global.cfg_basehost/&#125;"</span>&gt;首页&lt;/a&gt;</span><br><span class="line">&lt;/li&gt;</span><br><span class="line"><span class="comment"># //调用所有显示的栏目</span></span><br><span class="line">&#123;dede:channel <span class="built_in">type</span>=<span class="string">'top'</span> row=<span class="string">'10'</span> currentstyle=<span class="string">"&lt;li class='active'&gt;&lt;a href='~typelink~' ~rel~&gt;&lt;span&gt;~typename~&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;"</span>&#125;</span><br><span class="line">&lt;li&gt;</span><br><span class="line"> &lt;a href=<span class="string">'[field:typeurl/]'</span> [field:rel/]&gt;&lt;span&gt;[field:typename/]&lt;/span&gt;&lt;/a&gt;</span><br><span class="line">&lt;/li&gt;</span><br><span class="line">&#123;/dede:channel&#125;</span><br><span class="line"><span class="comment"># //在右侧调用隐藏的栏目(ID:666)</span></span><br><span class="line"> &lt;li class=<span class="string">"float-right &#123;dede:field name=id runphp='yes'&#125;(@me=='666')?@me='active':@me='';&#123;/dede:field&#125;"</span>&gt;</span><br><span class="line"> &#123;dede:<span class="built_in">type</span> typeid=666&#125;</span><br><span class="line"> &lt;a href=<span class="string">"[field:typeurl /]"</span>&gt;[field:typename /]&lt;/a&gt;</span><br><span class="line"> &#123;/dede:<span class="built_in">type</span>&#125;</span><br><span class="line"> &lt;/li&gt;</span><br></pre></td></tr></table></figure><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><blockquote><p>原文地址:<a href="http://www.dede58.com/a/dedejq/4271.html" target="_blank" rel="noopener">http://www.dede58.com/a/dedejq/4271.html</a></p></blockquote>]]></content>
<summary type="html">
&lt;h2 id=&quot;一、通过前台直接隐藏栏目&quot;&gt;&lt;a href=&quot;#一、通过前台直接隐藏栏目&quot; class=&quot;headerlink&quot; title=&quot;一、通过前台直接隐藏栏目&quot;&gt;&lt;/a&gt;一、通过前台直接隐藏栏目&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;如果栏目在后台设置显示或者设置隐藏
</summary>
<category term="DedeCMS" scheme="https://wangen.github.io/categories/DedeCMS/"/>
<category term="DedeCMS" scheme="https://wangen.github.io/tags/DedeCMS/"/>
<category term="栏目" scheme="https://wangen.github.io/tags/%E6%A0%8F%E7%9B%AE/"/>
</entry>
<entry>
<title>Mac OS常用操作命令备忘</title>
<link href="https://wangen.github.io/2018/01/15/Mac-file-1/"/>
<id>https://wangen.github.io/2018/01/15/Mac-file-1/</id>
<published>2018-01-15T15:45:22.000Z</published>
<updated>2018-01-21T09:28:29.078Z</updated>
<content type="html"><![CDATA[<h2 id="查看复制文件路径"><a href="#查看复制文件路径" class="headerlink" title="查看复制文件路径"></a>查看复制文件路径</h2><p>Launchpad-【其他】中打开<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">``` bash</span><br><span class="line">defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES</span><br></pre></td></tr></table></figure></p><p>之后,就能在Finder顶部看见完整的路径地址了<br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/macfile101.jpg" alt="Finder顶部路径"><br>在Finder顶端的地址栏右键,还可以直接访问路径中的任意一层<br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/macfile102.jpg" alt="Finder右键路径"><br>复制路径的方法:<br>1、推荐方案-『复制路径可以用 Option+Command+C』<br>2、右键文件-显示简介(或者使用快捷键cmd + i),复制位置信息,在文本中粘贴即可得到路径信息。<br>3、打开一个可以粘贴文字的应用(比如说终端,记事本),然后把要获取路径的【文件/文件夹】拖进去,看到的就是对应的绝对路径。</p><h2 id="常用快捷键一览"><a href="#常用快捷键一览" class="headerlink" title="常用快捷键一览"></a>常用快捷键一览</h2><p><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/macfile103.jpg" alt="Mac OS X快捷键"></p>]]></content>
<summary type="html">
&lt;h2 id=&quot;查看复制文件路径&quot;&gt;&lt;a href=&quot;#查看复制文件路径&quot; class=&quot;headerlink&quot; title=&quot;查看复制文件路径&quot;&gt;&lt;/a&gt;查看复制文件路径&lt;/h2&gt;&lt;p&gt;Launchpad-【其他】中打开&lt;figure class=&quot;highlight plai
</summary>
<category term="Mac" scheme="https://wangen.github.io/categories/Mac/"/>
<category term="Mac" scheme="https://wangen.github.io/tags/Mac/"/>
<category term="文件操作" scheme="https://wangen.github.io/tags/%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C/"/>
<category term="目录路径" scheme="https://wangen.github.io/tags/%E7%9B%AE%E5%BD%95%E8%B7%AF%E5%BE%84/"/>
</entry>
<entry>
<title>结合layui实现无刷新添加和删除input输入框,自动生成不同name值</title>
<link href="https://wangen.github.io/2017/12/26/form-input-2/"/>
<id>https://wangen.github.io/2017/12/26/form-input-2/</id>
<published>2017-12-26T15:47:09.000Z</published>
<updated>2017-12-26T15:59:46.755Z</updated>
<content type="html"><![CDATA[<h3 id="前情回顾"><a href="#前情回顾" class="headerlink" title="前情回顾"></a>前情回顾</h3><blockquote><p>随意删除添加后保存到服务端的input,再次编辑时(先调用服务端保存的值)添加新的input输入框name值可能会生成重复,提交保存时,name值重复的input元素会覆盖已有元素。</p></blockquote><p>昨天借鉴<a href="/2017/12/25/form-input-1/">jquery无刷新添加和删除input输入框 增加减少input框</a> 的思路实现了jQuery无刷新随意添加和删除input输入框,但是在使用layui结合ajax提交时,发现随意添加/删除后会生成重复name值的input输入框(比如name=”edu_bg[5]” / name=”edu_bg[6]” / name=”edu_bg[5]” 三个输入框)进行编辑提交,提交后只保存了后两个值,因为layui表单中name不支持数组的形式,相同的name也只会提交最后一个,layui社区也有朋友分享出解决方法:<a href="http://fly.layui.com/jie/9166/" target="_blank" rel="noopener">表单input不支持数组方式询问+解决办法</a>,可以借鉴下。</p><h3 id="思路整理"><a href="#思路整理" class="headerlink" title="思路整理"></a>思路整理</h3><blockquote><p>综合了一大堆搜索及意见,也不想改动框架的代码,决定采用以下方式:</p></blockquote><p>1、获取已经存在的子元素input的长度及name值,将获取的name值推入一个数组arr1中;<br>2、定义初始值key=0,定义插入函数insertInput(),key++循环;<br>3、当edu_bg[key]不在数组arr1中时,创建元素并append()推入父元素内完成,否则,重新执行insertInput()函数。</p><h3 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h3><h4 id="HTML代码"><a href="#HTML代码" class="headerlink" title="HTML代码"></a>HTML代码</h4><p>主要是定义几个已有的包含input的子元素(模拟从服务端获取的已有元素),然后定义一个包含点击事件的按钮元素。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&lt;div class=<span class="string">"layui-form-item yf-input-del"</span>&gt;</span><br><span class="line"> &lt;label class=<span class="string">"layui-form-label"</span>&gt;教育背景&lt;/label&gt;</span><br><span class="line"> &lt;div class=<span class="string">"layui-input-block"</span> id=<span class="string">"edu_bg"</span>&gt;</span><br><span class="line"> <span class="comment">#//测试随机创建几个连续和不连续的子元素,真实场景下直接循环出你已有的子元素即可</span></span><br><span class="line"> &lt;div class=<span class="string">"layui-input-inline"</span>&gt;</span><br><span class="line"> //input文本框</span><br><span class="line"> &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"edu_bg[5]"</span> value=<span class="string">""</span> autocomplete=<span class="string">"off"</span> placeholder=<span class="string">"请输入"</span> lay-verify=<span class="string">"required"</span> class=<span class="string">"layui-input"</span>&gt;</span><br><span class="line"> //删除按钮</span><br><span class="line"> &lt;i class=<span class="string">"layui-icon deleteEduBg"</span>&gt;&amp;<span class="comment">#x1006;&lt;/i&gt;</span></span><br><span class="line"> &lt;/div&gt;</span><br><span class="line"> &lt;div class=<span class="string">"layui-input-inline"</span>&gt;</span><br><span class="line"> &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"edu_bg[6]"</span> value=<span class="string">""</span> autocomplete=<span class="string">"off"</span> placeholder=<span class="string">"请输入"</span> lay-verify=<span class="string">"required"</span> class=<span class="string">"layui-input"</span>&gt;</span><br><span class="line"> &lt;i class=<span class="string">"layui-icon deleteEduBg"</span>&gt;&amp;<span class="comment">#x1006;&lt;/i&gt;</span></span><br><span class="line"> &lt;/div&gt;</span><br><span class="line"> &lt;div class=<span class="string">"layui-input-inline"</span>&gt;</span><br><span class="line"> &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"edu_bg[9]"</span> value=<span class="string">""</span> autocomplete=<span class="string">"off"</span> placeholder=<span class="string">"请输入"</span> lay-verify=<span class="string">"required"</span> class=<span class="string">"layui-input"</span>&gt;</span><br><span class="line"> &lt;i class=<span class="string">"layui-icon deleteEduBg"</span>&gt;&amp;<span class="comment">#x1006;&lt;/i&gt;</span></span><br><span class="line"> &lt;/div&gt;</span><br><span class="line"> &lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;div class=<span class="string">"layui-form-item"</span> id=<span class="string">"edu_bg_add"</span>&gt;</span><br><span class="line"> &lt;label class=<span class="string">"layui-form-label"</span>&gt;&lt;/label&gt;</span><br><span class="line"> &lt;div class=<span class="string">"layui-input-inline"</span>&gt;</span><br><span class="line"> &lt;a href=<span class="string">"javascript:;"</span> class=<span class="string">"layui-btn site-demo-active"</span> onclick=<span class="string">"insertInput()"</span>&gt;</span><br><span class="line"> &lt;i class=<span class="string">"layui-icon"</span>&gt;&amp;<span class="comment">#xe654;&lt;/i&gt; 新增1条教育背景</span></span><br><span class="line"> &lt;/a&gt;</span><br><span class="line"> &lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure><h4 id="JavaScript代码"><a href="#JavaScript代码" class="headerlink" title="JavaScript代码"></a>JavaScript代码</h4><p>定义一个插入函数insertInput()和一个点击删除函数</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">//引入layui.js</span><br><span class="line">&lt;script src=<span class="string">"/layui/dist/layui.all.js"</span>&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line"> var $ = layui.jquery; //引用layui内置的jQuery,也可以自己调用</span><br><span class="line"> var key1=$(<span class="string">"#edu_bg"</span>).children(<span class="string">".layui-input-inline"</span>).length;</span><br><span class="line"> var FieldCount1=0;</span><br><span class="line"> <span class="keyword">function</span> <span class="function"><span class="title">insertInput</span></span>() &#123;</span><br><span class="line"> //检索已有的input包含的name值</span><br><span class="line"> var arr1=[];</span><br><span class="line"> FieldCount1++;</span><br><span class="line"> $(<span class="string">"#edu_bg input[type='text']"</span>).each(<span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> arr1.push($(this).attr(<span class="string">'name'</span>));</span><br><span class="line"> &#125;);</span><br><span class="line"> //console.log(arr1);</span><br><span class="line"> //所有name加入数组arr1</span><br><span class="line"> var div1 = $(<span class="string">"&lt;div&gt;&lt;/div&gt;"</span>).addClass(<span class="string">"layui-input-inline"</span>);</span><br><span class="line"> //console.log(edu_bg[FieldCount1]);</span><br><span class="line"> var newCount1=<span class="string">"edu_bg["</span>+FieldCount1+<span class="string">"]"</span>;</span><br><span class="line"> //判断新生成的name值是否在已存在的数组中</span><br><span class="line"> <span class="keyword">if</span>($.inArray(newCount1, arr1) === -1)&#123;</span><br><span class="line"> FieldCount1=FieldCount1;</span><br><span class="line"> var input1 = <span class="string">"&lt;input type='text' name='edu_bg["</span>+FieldCount1 +<span class="string">"]' value='' autocomplete='off' placeholder='请输入' lay-verify='required' class='layui-input'&gt;"</span></span><br><span class="line"> var icon1 = <span class="string">"&lt;i class='layui-icon deleteEduBg' onclick='deleteElement(this)'&gt;&amp;#x1006;&lt;/i&gt;"</span>;</span><br><span class="line"> div1.append(input1, icon1);</span><br><span class="line"> $(<span class="string">"#edu_bg"</span>).append(div1); // 追加新元素</span><br><span class="line"> key1++;</span><br><span class="line"> &#125;<span class="keyword">else</span>&#123;</span><br><span class="line"> FieldCount1++;</span><br><span class="line"> insertInput();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> $(<span class="string">"body"</span>).on(<span class="string">"click"</span>,<span class="string">".deleteEduBg"</span>, <span class="keyword">function</span>(e)&#123; //user click on remove text </span><br><span class="line"> <span class="keyword">if</span>( key1 &gt; 1 ) &#123; </span><br><span class="line"> $(this).parent(<span class="string">'div'</span>).remove(); //移除对应的父级div元素 </span><br><span class="line"> key1--; //decrement textbox </span><br><span class="line"> &#125;<span class="keyword">else</span>&#123;</span><br><span class="line"> alert(<span class="string">"请至少填写1条教育背景信息!"</span>);</span><br><span class="line"> <span class="built_in">return</span> <span class="literal">false</span>; </span><br><span class="line"> &#125;</span><br><span class="line"> &#125;) </span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h4 id="补充CSS样式"><a href="#补充CSS样式" class="headerlink" title="补充CSS样式"></a>补充CSS样式</h4><p>这部分没必要,自己来就行,只是为了自己测试时样式顺眼一丢丢。。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;link rel=<span class="string">"stylesheet"</span> href=<span class="string">"/layui/dist/css/layui.css"</span>&gt;</span><br><span class="line">&lt;style <span class="built_in">type</span>=<span class="string">"text/css"</span>&gt;</span><br><span class="line"> /* 新增删除图标的样式 */</span><br><span class="line"> .yf-input-del .layui-input-inline .layui-input &#123;</span><br><span class="line"> padding-right: 20px;</span><br><span class="line"> margin-bottom: 10px;</span><br><span class="line"> &#125;</span><br><span class="line"> .yf-input-del .layui-input-inline i.layui-icon &#123;</span><br><span class="line"> position: absolute;</span><br><span class="line"> right: 2px;</span><br><span class="line"> top: 8px;</span><br><span class="line"> color: <span class="comment">#999999;</span></span><br><span class="line"> &#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><p>整个实现的过程是自己摸索和反复测试的过程,代码中也还有不少需要优化的地方,也可能会在以后的使用中继续优化整改,抛砖引玉,仅供大家参考。</p><blockquote><p>layui官网文档 <a href="http://www.layui.com/doc/" target="_blank" rel="noopener">http://www.layui.com/doc/</a></p><p>jQuery API中文文档 <a href="http://www.css88.com/jqapi-1.9/" target="_blank" rel="noopener">http://www.css88.com/jqapi-1.9/</a></p></blockquote>]]></content>
<summary type="html">
&lt;h3 id=&quot;前情回顾&quot;&gt;&lt;a href=&quot;#前情回顾&quot; class=&quot;headerlink&quot; title=&quot;前情回顾&quot;&gt;&lt;/a&gt;前情回顾&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;随意删除添加后保存到服务端的input,再次编辑时(先调用服务端保存的值)添加新的input输入框
</summary>
<category term="form" scheme="https://wangen.github.io/categories/form/"/>
<category term="form" scheme="https://wangen.github.io/tags/form/"/>
<category term="input" scheme="https://wangen.github.io/tags/input/"/>
<category term="layui" scheme="https://wangen.github.io/tags/layui/"/>
</entry>
<entry>
<title>jquery无刷新添加和删除input输入框 增加减少input框</title>
<link href="https://wangen.github.io/2017/12/25/form-input-1/"/>
<id>https://wangen.github.io/2017/12/25/form-input-1/</id>
<published>2017-12-25T14:48:11.000Z</published>
<updated>2017-12-26T15:49:15.044Z</updated>
<content type="html"><![CDATA[<h3 id="演示说明"><a href="#演示说明" class="headerlink" title="演示说明"></a>演示说明</h3><p><img src="http://www.freejs.net/demo/278/demo.jpg" alt="form-input-1"><br><a href="http://www.freejs.net/demo/278/index.html" target="_blank" rel="noopener">点击查看演示</a></p><h3 id="主要实现代码"><a href="#主要实现代码" class="headerlink" title="主要实现代码"></a>主要实现代码</h3><p>HTML代码部分<br>主要展示一个input输入框,一个点击事件的按钮;删除时判断至少存在一个元素,增加时可以限制最大允许生成的input个数<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;&lt;span&gt;&lt;a href=<span class="string">"#"</span> id=<span class="string">"AddMoreFileBox"</span> class=<span class="string">"btn btn-info"</span>&gt;添加更多的input输入框&lt;/a&gt;&lt;/span&gt;&lt;/p&gt; </span><br><span class="line">&lt;div id=<span class="string">"InputsWrapper"</span>&gt; </span><br><span class="line"> &lt;div&gt;</span><br><span class="line"> &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"mytext[]"</span> id=<span class="string">"field_1"</span> value=<span class="string">"Text 1"</span>/&gt;</span><br><span class="line"> &lt;a href=<span class="string">"#"</span> class=<span class="string">"removeclass"</span>&gt;×&lt;/a&gt;</span><br><span class="line"> &lt;/div&gt; </span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure></p><p>JavaScript代码部分<br>首先引入jQuery文件,调用代码如下:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt; </span><br><span class="line">$(document).ready(<span class="function"><span class="title">function</span></span>() &#123; </span><br><span class="line"> </span><br><span class="line"> var MaxInputs = 8; //maximum input boxes allowed </span><br><span class="line"> var InputsWrapper = $(<span class="string">"#InputsWrapper"</span>); //Input boxes wrapper ID </span><br><span class="line"> var AddButton = $(<span class="string">"#AddMoreFileBox"</span>); //Add button ID </span><br><span class="line"> </span><br><span class="line"> var x = InputsWrapper.length; //initlal text box count </span><br><span class="line"> var FieldCount=1; //to keep track of text box added </span><br><span class="line"> </span><br><span class="line"> $(AddButton).click(<span class="keyword">function</span> (e) //on add input button click </span><br><span class="line"> &#123; </span><br><span class="line"> <span class="keyword">if</span>(x &lt;= MaxInputs) //max input box allowed </span><br><span class="line"> &#123; </span><br><span class="line"> FieldCount++; //text box added increment </span><br><span class="line"> //add input box </span><br><span class="line"> $(InputsWrapper).append(<span class="string">'&lt;div&gt;&lt;input type="text" name="mytext['</span>+FieldCount+<span class="string">']" id="field_'</span>+ FieldCount +<span class="string">'" value="Text '</span>+ FieldCount +<span class="string">'"/&gt;&lt;a href="#" class="removeclass"&gt;×&lt;/a&gt;&lt;/div&gt;'</span>); </span><br><span class="line"> x++; //text box increment </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="built_in">return</span> <span class="literal">false</span>; </span><br><span class="line"> &#125;); </span><br><span class="line"> </span><br><span class="line"> $(<span class="string">"body"</span>).on(<span class="string">"click"</span>,<span class="string">".removeclass"</span>, <span class="keyword">function</span>(e)&#123; //user click on remove text </span><br><span class="line"> <span class="keyword">if</span>( x &gt; 1 ) &#123; </span><br><span class="line"> $(this).parent(<span class="string">'div'</span>).remove(); //remove text box </span><br><span class="line"> x--; //decrement textbox </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="built_in">return</span> <span class="literal">false</span>; </span><br><span class="line"> &#125;) </span><br><span class="line"> </span><br><span class="line">&#125;); </span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><blockquote><p>原文地址:<a href="http://www.freejs.net/article_biaodan_278.html" target="_blank" rel="noopener">http://www.freejs.net/article_biaodan_278.html</a></p></blockquote>]]></content>
<summary type="html">
&lt;h3 id=&quot;演示说明&quot;&gt;&lt;a href=&quot;#演示说明&quot; class=&quot;headerlink&quot; title=&quot;演示说明&quot;&gt;&lt;/a&gt;演示说明&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;http://www.freejs.net/demo/278/demo.jpg&quot; alt=&quot;form-i
</summary>
<category term="form" scheme="https://wangen.github.io/categories/form/"/>
<category term="jQuery" scheme="https://wangen.github.io/tags/jQuery/"/>
<category term="form" scheme="https://wangen.github.io/tags/form/"/>
<category term="input" scheme="https://wangen.github.io/tags/input/"/>
</entry>
<entry>
<title>使用HTML5 &lt;video&gt; 标签-调用视频的当前播放时间值</title>
<link href="https://wangen.github.io/2017/12/23/html5-video-2/"/>
<id>https://wangen.github.io/2017/12/23/html5-video-2/</id>
<published>2017-12-23T15:37:37.000Z</published>
<updated>2018-01-13T13:59:05.344Z</updated>
<content type="html"><![CDATA[<h3 id="Video对象"><a href="#Video对象" class="headerlink" title="Video对象"></a>Video对象</h3><p>Video 对象是 HTML5 中的新对象。</p><p>Video 对象表示 HTML &lt; video &gt; 元素。</p><h3 id="currentTime基础使用"><a href="#currentTime基础使用" class="headerlink" title="currentTime基础使用"></a>currentTime基础使用</h3><p>在用HTML5技术处理视频时,设置(setting)和获取(getting)时间都是非常重要的知识点,尤其是对于记录播放时间实现续播的功能。在管理视频状态时,最重要的是要了解 <code>currentTime</code>是个什么鬼,简而言之你可以通过这个属性获取当前播放到了哪个时间点(比如当前播放到了2分30秒,当然<code>currentTime</code> 的单位是 <code>秒</code> (seconds),所以我们获取到的值是 <code>150</code>).</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// https://www.youtube.com/watch?v=Cwkej79U3ek</span><br><span class="line">console.log(video.currentTime); // 25.431747</span><br></pre></td></tr></table></figure><h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><p>返回(getter) currentTime 属性(数字值,表示当前播放的时间,以秒计):</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">videoObject.currentTime</span><br></pre></td></tr></table></figure><p>设置 currentTime 属性:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">videoObject.currentTime=seconds</span><br></pre></td></tr></table></figure></p><blockquote><p>currentTime 属性设置或返回视频播放的当前位置(以秒计),当设置该属性时,播放会跳跃到指定的位置。</p></blockquote><h3 id="浏览器支持"><a href="#浏览器支持" class="headerlink" title="浏览器支持"></a>浏览器支持</h3><p>所有主流浏览器都支持 currentTime 属性。</p><blockquote><p>注意:Internet Explorer 8 或更早的浏览器不支持该属性。</p></blockquote><p><code>currentTime</code> 既是 getter 又是 setter 属性, 所以可以直接设置 currentTime 值来控制播放进度:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">video.currentTime = 0; // Restart,初始化设置当前播放到了0秒</span><br></pre></td></tr></table></figure><h3 id="补充说明"><a href="#补充说明" class="headerlink" title="补充说明"></a>补充说明</h3><p>API 接口很容易理解,而且是自解释的(self-explanatory)。你仍然需要处理“second”来指定时间,包括内在实际的和外在显示的(both inward and outward),但是秒(second)这个单位和你预期的一样公平,所以说这个API设计是非常巧妙的。</p><blockquote><p>使用参考:小米空气净化器 <a href="http://www.mi.com/air/" target="_blank" rel="noopener">http://www.mi.com/air/</a> (页面已撤销)</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;video id=<span class="string">"videoIntro"</span> class=<span class="string">"video"</span> data-video-name=<span class="string">"intro"</span> poster=<span class="string">"http://c1.mifile.cn/f/i/2014/cn/goods/air/overall/video-main-poster.jpg"</span> style=<span class="string">"height: 600px; width: 800px; display: none;"</span>&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> <span class="built_in">type</span>=<span class="string">"video/mp4"</span> src=<span class="string">"http://c1.mifile.cn/f/i/2014/cn/goods/air/overall/video-intro.mp4?2014120901"</span>&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> <span class="built_in">type</span>=<span class="string">"video/webm"</span> src=<span class="string">"http://c1.mifile.cn/f/i/2014/cn/goods/air/overall/video-intro.webm?2014120901"</span>&gt;</span><br><span class="line">&lt;/video&gt;</span><br></pre></td></tr></table></figure><h3 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt; </span><br><span class="line">&lt;html&gt; </span><br><span class="line">&lt;head&gt; </span><br><span class="line">&lt;meta charset=<span class="string">"utf-8"</span>&gt; </span><br><span class="line">&lt;title&gt;菜鸟教程(runoob.com)&lt;/title&gt; </span><br><span class="line">&lt;/head&gt; </span><br><span class="line">&lt;body&gt; </span><br><span class="line"></span><br><span class="line">&lt;video id=<span class="string">"myVideo"</span> width=<span class="string">"320"</span> height=<span class="string">"240"</span> controls&gt;</span><br><span class="line">&lt;<span class="built_in">source</span> src=<span class="string">"http://www.runoob.com/try/demo_source/movie.mp4"</span> <span class="built_in">type</span>=<span class="string">"video/mp4"</span>&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> src=<span class="string">"http://www.runoob.com/try/demo_source/movie.ogg"</span> <span class="built_in">type</span>=<span class="string">"video/ogg"</span>&gt;</span><br><span class="line"> 您的浏览器不支持 video 标签。</span><br><span class="line">&lt;/video&gt;&lt;br&gt;</span><br><span class="line">&lt;button onclick=<span class="string">"getCurTime()"</span> <span class="built_in">type</span>=<span class="string">"button"</span>&gt;获取当前时间点&lt;/button&gt;</span><br><span class="line">&lt;button onclick=<span class="string">"setCurTime()"</span> <span class="built_in">type</span>=<span class="string">"button"</span>&gt;设置时间位置为5秒&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">var x = document.getElementById(<span class="string">"myVideo"</span>);</span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">getCurTime</span></span>()&#123; </span><br><span class="line">alert(x.currentTime);</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">setCurTime</span></span>()&#123; </span><br><span class="line">x.currentTime = 5;</span><br><span class="line">&#125; </span><br><span class="line">&lt;/script&gt; </span><br><span class="line"></span><br><span class="line">&lt;/body&gt; </span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><p>其实关于HTML5-Video视频播放器,还有一款插件可以直接使用:<a href="http://videojs.com/" target="_blank" rel="noopener">Video.js</a>,使用方法和原生比较类似,不过目前中文文档还不多,大家有兴趣可以去了解下。</p><blockquote><p>整理参考1:<a href="http://blog.csdn.net/renfufei/article/details/44522887" target="_blank" rel="noopener">译:获取并设置HTML5 Video的当前进度</a> - <a href="http://davidwalsh.name/html5-video-current-time" target="_blank" rel="noopener">原文地址</a></p><p>整理参考2:<a href="http://www.runoob.com/jsref/prop-video-currenttime.html" target="_blank" rel="noopener">Video currentTime 属性</a></p></blockquote>]]></content>
<summary type="html">
&lt;h3 id=&quot;Video对象&quot;&gt;&lt;a href=&quot;#Video对象&quot; class=&quot;headerlink&quot; title=&quot;Video对象&quot;&gt;&lt;/a&gt;Video对象&lt;/h3&gt;&lt;p&gt;Video 对象是 HTML5 中的新对象。&lt;/p&gt;
&lt;p&gt;Video 对象表示 HTML &amp;lt;
</summary>
<category term="HTML5" scheme="https://wangen.github.io/categories/HTML5/"/>
<category term="HTML5" scheme="https://wangen.github.io/tags/HTML5/"/>
<category term="Video" scheme="https://wangen.github.io/tags/Video/"/>
<category term="视频" scheme="https://wangen.github.io/tags/%E8%A7%86%E9%A2%91/"/>
</entry>
<entry>
<title>视频播放插件Video.js一些API的使用介绍</title>
<link href="https://wangen.github.io/2017/12/23/html5-video-1/"/>
<id>https://wangen.github.io/2017/12/23/html5-video-1/</id>
<published>2017-12-23T15:37:17.000Z</published>
<updated>2017-12-23T15:59:07.986Z</updated>
<content type="html"><![CDATA[<h3 id="插件基本说明"><a href="#插件基本说明" class="headerlink" title="插件基本说明"></a>插件基本说明</h3><p>Video.js 是一个通用的在网页上嵌入视频播放器的 JS 库,Video.js 自动检测浏览器对 HTML5 的支持情况,如果不支持 HTML5 则自动使用 Flash 播放器。(要支持ie低版本请下载5.4.3版 )<br>github地址: <a href="https://github.com/videojs/video.js" target="_blank" rel="noopener">https://github.com/videojs/video.js</a> ,可以自行选择版本标签点击下载。</p><blockquote><p>V6.6.0版本下载地址:<a href="https://codeload.github.com/videojs/video.js/zip/v6.6.0" target="_blank" rel="noopener">点击下载</a><br>V5.4.3旧版本下载地址:<a href="https://codeload.github.com/videojs/video.js/zip/v5.4.3" target="_blank" rel="noopener">下载地址</a></p></blockquote><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><h4 id="静态调用"><a href="#静态调用" class="headerlink" title="静态调用"></a>静态调用</h4><blockquote><p>引入文件</p></blockquote><p>在页面中引用video-js.css样式文件和video.js<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;link href=<span class="string">"video-js.css"</span> rel=<span class="string">"stylesheet"</span> <span class="built_in">type</span>=<span class="string">"text/css"</span>&gt;</span><br><span class="line">&lt;script src=<span class="string">"video.js"</span>&gt;&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><p>设置flash路径,Video.js会在不支持html5的浏览中使用flash播放视频文件<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"> videojs.options.flash.swf = <span class="string">"video-js.swf"</span>;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><blockquote><p>HTML调用代码</p></blockquote><p>poster=”**”设置播放初始图片。<br>&lt; source src=”” &gt;可设置使用三种视频格式,根据所需要格式选择对应的。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;video id=<span class="string">"example_video_1"</span> class=<span class="string">"video-js vjs-default-skin"</span> controls preload=<span class="string">"none"</span> width=<span class="string">"640"</span> height=<span class="string">"264"</span> poster=<span class="string">"http://video-js.zencoder.com/oceans-clip.png"</span> data-setup=<span class="string">"&#123;&#125;"</span>&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> src=<span class="string">"http://视频地址格式1.mp4"</span> <span class="built_in">type</span>=<span class="string">'video/mp4'</span> /&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> src=<span class="string">"http://视频地址格式2.webm"</span> <span class="built_in">type</span>=<span class="string">'video/webm'</span> /&gt;</span><br><span class="line"> &lt;<span class="built_in">source</span> src=<span class="string">"http://视频地址格式3.ogv"</span> <span class="built_in">type</span>=<span class="string">'video/ogg'</span> /&gt;</span><br><span class="line"> &lt;track kind=<span class="string">"captions"</span> src=<span class="string">"demo.captions.vtt"</span> srclang=<span class="string">"en"</span> label=<span class="string">"English"</span>&gt;&lt;/track&gt;</span><br><span class="line"> &lt;!-- Tracks need an ending tag thanks to IE9 --&gt;</span><br><span class="line"> &lt;track kind=<span class="string">"subtitles"</span> src=<span class="string">"demo.captions.vtt"</span> srclang=<span class="string">"en"</span> label=<span class="string">"English"</span>&gt;&lt;/track&gt;</span><br><span class="line"> &lt;!-- Tracks need an ending tag thanks to IE9 --&gt;</span><br><span class="line">&lt;/video&gt;</span><br></pre></td></tr></table></figure><blockquote><p>JavaScript设置调用 </p></blockquote><p>通过JavaScript标签设置相关属性,比如设置<code>自动播放</code>,是将如下代码加到html中代码后面<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line"> var myPlayer = videojs(<span class="string">'example_video_1'</span>);</span><br><span class="line"> videojs(<span class="string">"example_video_1"</span>).ready(<span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> var myPlayer = this;</span><br><span class="line"> myPlayer.play();</span><br><span class="line"> &#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></p><blockquote><p>额外样式自定义</p></blockquote><p>默认情况下,大的播放按钮是被定为在左上角的,这样就不会覆盖视频内容。如果你想让这个播放按钮居中,你可以给你的 video 标签添加额外的 <code>vjs-big-play-centered</code> 样式,比如:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;video id=<span class="string">"example_video_1"</span> class=<span class="string">"video-js vjs-default-skin vjs-big-play-centered"</span> controls preload=<span class="string">"auto"</span> width=<span class="string">"640"</span> height=<span class="string">"264"</span> poster=<span class="string">"http://video-js.zencoder.com/oceans-clip.png"</span> data-setup=<span class="string">'&#123;"example_option":true&#125;'</span>&gt;</span><br><span class="line"> ...</span><br><span class="line">&lt;/video&gt;</span><br></pre></td></tr></table></figure><p>如果你还对播放按钮样式不满意可重新定义<code>.video-js .vjs-big-play-button</code>{/<em>继续将这里的样式重写</em>/}。</p><h4 id="动态加载使用"><a href="#动态加载使用" class="headerlink" title="动态加载使用"></a>动态加载使用</h4><p>如果你的 web 页面或者应用是动态加载video标签的(ajax,appendChild,等等),这样在页面加载后这个元素是不存在的,那么你会想要手动设置播放器而不是依靠<code>data-setup</code>属性。要做到这一点,首先将<code>data-setup</code> 属性从 video 标签中移除掉,这样在播放器初始化的时候就不会混乱了。接下来,运行下面的 JavaScript ,有时在 Video.js 加载后,有时是在 video 标签被加载进 DOM 后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">videojs(<span class="string">"example_video_1"</span>, &#123;&#125;, <span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> // Player (this) is initialized and ready.</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>videojs 方法中的第一个参数是你的 video 标签的 ID,用你自己的代替。<br>第二个参数是一个选项对象。它允许你像设置<code>data-setup</code>属性一样设置额外的选项。<br>第三个参数是一个’ready’回调。一旦Video.js初始化完成后,就会触发这个回调。</p><p>当然,你也可以传入一个元素本身的引用来代替元素ID:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">videojs(document.getElementById(<span class="string">'example_video_1'</span>), &#123;&#125;, <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> // This is functionally the same as the previous example.</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">videojs(document.getElementsByClassName(<span class="string">'awesome_video_class'</span>)[0], &#123;&#125;, <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> // You can grab an element by class <span class="keyword">if</span> you<span class="string">'d like, just make sure</span></span><br><span class="line"><span class="string"> // if it'</span>s an array that you pick one (here we chose the first).</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><blockquote><p>如果您无法播放内容,您得确保使用了正确的格式,你的 HTTP 服务器可能无法提供正确的<code>MIME类型</code>的内容</p></blockquote><h3 id="一些常用的API属性"><a href="#一些常用的API属性" class="headerlink" title="一些常用的API属性"></a>一些常用的API属性</h3><p>获取video实例:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var videoObj = videojs(“videoId”);</span><br></pre></td></tr></table></figure></p><p>初始化回调ready:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.ready(<span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> //在回调函数中,this代表当前播放器,</span><br><span class="line"> //可以调用方法,也可以绑定事件。</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></p><p>播放:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.play();</span><br></pre></td></tr></table></figure></p><p>暂停:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.pause();</span><br></pre></td></tr></table></figure></p><p>获取播放进度(当前播放时间):<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var whereYouAt = myPlayer.currentTime();</span><br></pre></td></tr></table></figure></p><p>设置播放进度:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.currentTime(120);</span><br></pre></td></tr></table></figure></p><p>视频持续时间,加载完成视频才可以知道视频时长,且在flash情况下无效:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var howLongIsThis = myPlayer.duration();</span><br></pre></td></tr></table></figure></p><p>缓冲,就是返回下载了多少:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var whatHasBeenBuffered = myPlayer.buffered();</span><br></pre></td></tr></table></figure></p><p>百分比的缓冲:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var howMuchIsDownloaded = myPlayer.bufferedPercent();</span><br></pre></td></tr></table></figure></p><p>声音大小(0-1之间):<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var howLoudIsIt = myPlayer.volume();</span><br></pre></td></tr></table></figure></p><p>设置声音大小:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.volume(0.5);</span><br></pre></td></tr></table></figure></p><p>获取/设置视频的宽度:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var howWideIsIt = myPlayer.width(); //getter width</span><br><span class="line">myPlayer.width(640); //setter width</span><br><span class="line">var howTallIsIt = myPlayer.height(); //getter height</span><br><span class="line">myPlayer.height(480); //setter height</span><br></pre></td></tr></table></figure></p><p>一步到位,设置视频大小(宽度高度):<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.size(640,480);</span><br></pre></td></tr></table></figure></p><p>设置进入全屏/退出全屏(HTML5播放器下有效):<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.enterFullScreen();</span><br><span class="line">myPlayer.exitFullScreen();</span><br><span class="line">//http://docs.videojs.com/html5<span class="comment">#enterFullScreen</span></span><br></pre></td></tr></table></figure></p><p>添加事件:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">durationchange //提示视频的时长已改变</span><br><span class="line">ended //播放结束</span><br><span class="line">firstplay</span><br><span class="line">fullscreenchange</span><br><span class="line">loadedalldata</span><br><span class="line">loadeddata</span><br><span class="line">loadedmetadata</span><br><span class="line">loadstart</span><br><span class="line">pause //暂停</span><br><span class="line">play //播放</span><br><span class="line">progress</span><br><span class="line">seeked</span><br><span class="line">seeking</span><br><span class="line">timeupdate</span><br><span class="line">volumechange</span><br><span class="line">waiting</span><br><span class="line">resize inherited</span><br><span class="line"> </span><br><span class="line">var myFunc = <span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> // Do something when the event is fired</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p><p>事件绑定:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.on(<span class="string">"ended"</span>, <span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> console.log(<span class="string">"end"</span>, this.currentTime());</span><br><span class="line">&#125;);</span><br><span class="line">myPlayer.on(<span class="string">"pause"</span>, <span class="function"><span class="title">function</span></span>()&#123;</span><br><span class="line"> console.log(<span class="string">"pause"</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>事件移除:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">myPlayer.removeEvent(“eventName”, myFunc);</span><br></pre></td></tr></table></figure></p><blockquote><p>同一页面多个视频调用示例:</p></blockquote><p>一个页面中有多个视频,需要点击后触发bootstrap 的模态窗,再弹出视频,实现如下:<br>主要HTML代码部分:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;a videohref=<span class="string">"http://xxx.mp4"</span> class=<span class="string">"video_link"</span>&gt;&lt;img src=<span class="string">"../images/xxx.jpg"</span>/&gt;&lt;/a&gt;</span><br></pre></td></tr></table></figure></p><p>主要JS代码部分:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">$(<span class="string">".video_link"</span>).click(<span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> var myPlayer = videojs(<span class="string">'my-video'</span>);</span><br><span class="line"> var videoUrl = $(this).attr(<span class="string">"videohref"</span>);</span><br><span class="line"> videojs(<span class="string">"my-video"</span>, &#123;&#125;, <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> window.myPlayer = this;</span><br><span class="line"> $(<span class="string">"#mymoda .video-con #my-video source"</span>).attr(<span class="string">"src"</span>, videoUrl);</span><br><span class="line"> myPlayer.src(videoUrl);</span><br><span class="line"> myPlayer.load(videoUrl);</span><br><span class="line"> myPlayer.play();</span><br><span class="line"> &#125;);</span><br><span class="line"> $(<span class="string">".click-modal"</span>).click();</span><br><span class="line">&#125;);</span><br><span class="line">// 模态窗消失时,关闭视频 </span><br><span class="line">$(<span class="string">'#mymoda'</span>).on(<span class="string">'hidden.bs.modal'</span>, <span class="function"><span class="title">function</span></span>() &#123;</span><br><span class="line"> myPlayer.pause();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>更多API使用可查看<a href="http://docs.videojs.com/html5" target="_blank" rel="noopener">官网文档</a>。</p><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><blockquote><p>转载来源:<a href="http://www.jq22.com/jquery-info404" target="_blank" rel="noopener">视频播放插件Video.js</a><br>插件官网:<a href="http://videojs.com" target="_blank" rel="noopener">Video.js</a></p></blockquote>]]></content>
<summary type="html">
&lt;h3 id=&quot;插件基本说明&quot;&gt;&lt;a href=&quot;#插件基本说明&quot; class=&quot;headerlink&quot; title=&quot;插件基本说明&quot;&gt;&lt;/a&gt;插件基本说明&lt;/h3&gt;&lt;p&gt;Video.js 是一个通用的在网页上嵌入视频播放器的 JS 库,Video.js 自动检测浏览器对 HTM
</summary>
<category term="HTML5" scheme="https://wangen.github.io/categories/HTML5/"/>
<category term="HTML5" scheme="https://wangen.github.io/tags/HTML5/"/>
<category term="Video" scheme="https://wangen.github.io/tags/Video/"/>
<category term="Video.js" scheme="https://wangen.github.io/tags/Video-js/"/>
<category term="视频" scheme="https://wangen.github.io/tags/%E8%A7%86%E9%A2%91/"/>
</entry>
<entry>
<title>如何优雅的在 Microsoft word中插入代码</title>
<link href="https://wangen.github.io/2017/12/20/office-word-1/"/>
<id>https://wangen.github.io/2017/12/20/office-word-1/</id>
<published>2017-12-20T15:10:14.000Z</published>
<updated>2017-12-20T15:19:21.304Z</updated>
<content type="html"><![CDATA[<h2 id="打开在线编辑代码网站"><a href="#打开在线编辑代码网站" class="headerlink" title="打开在线编辑代码网站"></a>打开在线编辑代码网站</h2><p>打开<a href="http://www.planetb.ca/syntax-highlight-word" target="_blank" rel="noopener">PlanetB 代码编辑高亮网站</a> </p><h2 id="编辑代码"><a href="#编辑代码" class="headerlink" title="编辑代码"></a>编辑代码</h2><p>1、将你需要插入在word中的代码完整的复制到该网站提示的文本框内,选择你的代码类型,如PHP,JavaScript,HTML等,并点击提交。<br>2、页面会自动跳转生成一个新的页面,包含编辑格式后的代码,此时ctrl+A全选,后ctrl+c复制到word中粘贴就好。</p><h2 id="在Word中使用"><a href="#在Word中使用" class="headerlink" title="在Word中使用"></a>在Word中使用</h2><p>1、插入-表格-插入1*1的表格<br>2、光标放在表格中,将刚刚复制的代码粘贴进入<br>3、设置仅对该文档不使用语法检查</p><blockquote><p>原文地址:<a href="http://blog.csdn.net/u011303443/article/details/50992651" target="_blank" rel="noopener">如何优雅的在 Microsoft word中插入代码</a></p></blockquote>]]></content>
<summary type="html">
&lt;h2 id=&quot;打开在线编辑代码网站&quot;&gt;&lt;a href=&quot;#打开在线编辑代码网站&quot; class=&quot;headerlink&quot; title=&quot;打开在线编辑代码网站&quot;&gt;&lt;/a&gt;打开在线编辑代码网站&lt;/h2&gt;&lt;p&gt;打开&lt;a href=&quot;http://www.planetb.ca/synta
</summary>
<category term="Office" scheme="https://wangen.github.io/categories/Office/"/>
<category term="Microsoft" scheme="https://wangen.github.io/tags/Microsoft/"/>
<category term="Word" scheme="https://wangen.github.io/tags/Word/"/>
<category term="Code" scheme="https://wangen.github.io/tags/Code/"/>
</entry>
<entry>
<title>使用Firefox火狐浏览器模拟手机等多种浏览器</title>
<link href="https://wangen.github.io/2017/12/19/firefox-set-1/"/>
<id>https://wangen.github.io/2017/12/19/firefox-set-1/</id>
<published>2017-12-19T15:58:31.000Z</published>
<updated>2017-12-20T15:08:47.040Z</updated>
<content type="html"><![CDATA[<h2 id="下载旧版本Firefox浏览器"><a href="#下载旧版本Firefox浏览器" class="headerlink" title="下载旧版本Firefox浏览器"></a>下载旧版本Firefox浏览器</h2><p>官方下载地址:<a href="http://ftp.mozilla.org/pub/firefox/releases/" target="_blank" rel="noopener">http://ftp.mozilla.org/pub/firefox/releases/</a><br>因为最新更新的Firefox57版本使用了新引擎,之前的绝大部分扩展组件都不再支持,所以我们要选用适合自己电脑系统的旧版本Firefox浏览器下载作为开发使用。<br>我先用的是<a href="http://ftp.mozilla.org/pub/firefox/releases/53.0/win64/" target="_blank" rel="noopener">Firefox 53.0 64位版本</a>(win10 64位系统环境下),仅作为参考</p><blockquote><p>安装完成后,打开浏览器在【工具】-【选项】-【高级】-【更新】中选择“不检查更新”</p></blockquote><h2 id="安装附加组件User-Agent-Switcher"><a href="#安装附加组件User-Agent-Switcher" class="headerlink" title="安装附加组件User Agent Switcher"></a>安装附加组件User Agent Switcher</h2><p>【工具】-【附加组件】-【搜索】User Agent Switcher,安装后重启浏览器</p><blockquote><p>点击菜单栏的【工具】下拉,选择”iPhone3.0”选项即可在火狐浏览器模拟手机浏览器了</p></blockquote><h2 id="扩展UA列表伪装更多平台版本"><a href="#扩展UA列表伪装更多平台版本" class="headerlink" title="扩展UA列表伪装更多平台版本"></a>扩展UA列表伪装更多平台版本</h2><p>1、工具-default user agent-User Agent Switcher-options,打开User Agent Switcher选项卡,点击右下角网页链接,就能找到最常用的UA列表了<br>2、打开techpatterns网页,下载网页为你提供的.xml文件地址。如果觉得此步骤麻烦,点击以下下载地址进入下载。<br>下载地址:<a href="https://techpatterns.com/forums/about304.html" target="_blank" rel="noopener">https://techpatterns.com/forums/about304.html</a><br>点击 <code>Download via Save As File Dialogue</code>将xml文件下载到本地。<br>3、打开 【User Agent Switcher】组件,在该组件面板【选项】中导入下载的xml文件后重启浏览器即可。导入下载好的.xml文件,即可体验更多的平台模拟了。</p>]]></content>
<summary type="html">
&lt;h2 id=&quot;下载旧版本Firefox浏览器&quot;&gt;&lt;a href=&quot;#下载旧版本Firefox浏览器&quot; class=&quot;headerlink&quot; title=&quot;下载旧版本Firefox浏览器&quot;&gt;&lt;/a&gt;下载旧版本Firefox浏览器&lt;/h2&gt;&lt;p&gt;官方下载地址:&lt;a href=&quot;ht
</summary>
<category term="Browser" scheme="https://wangen.github.io/categories/Browser/"/>
<category term="Firefox" scheme="https://wangen.github.io/tags/Firefox/"/>
<category term="组件" scheme="https://wangen.github.io/tags/%E7%BB%84%E4%BB%B6/"/>
</entry>
<entry>
<title>制作透明背景 PNG 图片和 GIF 动图的几种方法</title>
<link href="https://wangen.github.io/2017/12/17/png-gif-transparency/"/>
<id>https://wangen.github.io/2017/12/17/png-gif-transparency/</id>
<published>2017-12-16T16:51:42.000Z</published>
<updated>2018-01-21T09:27:35.866Z</updated>
<content type="html"><![CDATA[<p>偶尔需要将图片的背景透明,渐渐掌握了几种较为简便的处理方法。写篇文章记录一下经验,免得自己哪天又忘了。</p><h2 id="PowerPoint-→-PNG"><a href="#PowerPoint-→-PNG" class="headerlink" title="PowerPoint → PNG"></a>PowerPoint → PNG</h2><blockquote><p>微软幻灯片工具 PowerPoint 也可以用来简单处理下图片,比如透明化背景。</p></blockquote><p>1、打开 PowerPoint,新建一张幻灯片页面,然后把待处理的图片拖进去。<br>2、依次点击 <strong>格式</strong> 选项卡 - <strong>颜色</strong> 菜单 - <strong>设置透明色</strong> - 点选 <strong>背景色</strong>。这样背景就透明化了,再右键图片另存为 <code>PNG 格式</code> 即可。<br>3、 <strong>删除背景</strong> 功能类似,不过感觉没上面的方式快捷。</p><p><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/PPT-PNG.jpg" alt="PPT-PNG"></p><h2 id="PhotoShop-→-PNG"><a href="#PhotoShop-→-PNG" class="headerlink" title="PhotoShop → PNG"></a>PhotoShop → PNG</h2><blockquote><p>如果电脑上安了 PhotoShop,那我们可以更灵活地制作透明背景图片。<br>1、用 PS 打开待处理的静态图片,双击图层框右侧小锁标志解锁图层;<br>2、选用魔棒工具,调整容差为10左右(容差越大,选取的相似颜色越多),勾选消除锯齿;<br>3、点选背景,按键盘 <code>del</code>键删除之(按住 <code>shift</code> 键可以多选),之后将图片另存为 PNG 格式即可。<br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/PS-PNG.jpg" alt="PS-PNG"></p></blockquote><h2 id="PhotoShop-→-GIF"><a href="#PhotoShop-→-GIF" class="headerlink" title="PhotoShop → GIF"></a>PhotoShop → GIF</h2><blockquote><p>PhotoShop 用来透明化 GIF 动图背景也是很方便的。<br>1、用 PS 打开待处理的 GIF 动图,并确保时间轴窗口已显示(窗口菜单 - 勾选时间轴);<br>2、全选时间轴中的图片(可利用 <code>shift</code> 键全选),右键图片,勾选自动(跳过此步生产的动图会有重影);<br>3、点击文件菜单 - 存储为 Web 所用格式…;<br>4、在颜色表中,先点选的小星点,再点击下方第一个按钮将背景透明,之后点击存储…保存 GIF 到目标位置即可。<br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/PS-GIF-1.jpg" alt="PS-GIF-1"><br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/PS-GIF-2.jpg" alt="PS-GIF-2"></p></blockquote><h2 id="一些成品"><a href="#一些成品" class="headerlink" title="一些成品"></a>一些成品</h2><blockquote><p>展示一些已经透明化背景的图片。<br><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/Mihawk.gif" alt="Mihawk"><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/food-boy.gif" alt="food-boy"><img src="https://raw.githubusercontent.com/WangEn/BlogBackup/master/blogimgs/bilibili.gif" alt="bilibili"></p></blockquote><h4 id="拓展阅读"><a href="#拓展阅读" class="headerlink" title="拓展阅读"></a>拓展阅读</h4><blockquote><ul><li>移动端图片格式调研 by ibireme on 2015/11/2: <a href="http://blog.ibireme.com/2015/11/02/mobile_image_benchmark/" target="_blank" rel="noopener">http://blog.ibireme.com/2015/11/02/mobile_image_benchmark/</a></li><li>解决GIF动画图去背景后出现的重影 by 有烟飘过 on 2010/5/10: <a href="http://tieba.baidu.com/p/2106457600" target="_blank" rel="noopener">http://tieba.baidu.com/p/2106457600</a></li><li>制作透明背景 PNG 图片和 GIF 动图的几种方法 by MOxFIVE on 2015-11-17: <a href="http://moxfive.xyz/2015/11/16/png-gif-transparency/" target="_blank" rel="noopener">http://moxfive.xyz/2015/11/16/png-gif-transparency/</a></li></ul></blockquote>]]></content>
<summary type="html">
&lt;p&gt;偶尔需要将图片的背景透明,渐渐掌握了几种较为简便的处理方法。写篇文章记录一下经验,免得自己哪天又忘了。&lt;/p&gt;
&lt;h2 id=&quot;PowerPoint-→-PNG&quot;&gt;&lt;a href=&quot;#PowerPoint-→-PNG&quot; class=&quot;headerlink&quot; title=&quot;P
</summary>
<category term="Images" scheme="https://wangen.github.io/categories/Images/"/>
<category term="png" scheme="https://wangen.github.io/tags/png/"/>
<category term="gif" scheme="https://wangen.github.io/tags/gif/"/>
<category term="Photoshop" scheme="https://wangen.github.io/tags/Photoshop/"/>
<category term="PowerPoint" scheme="https://wangen.github.io/tags/PowerPoint/"/>
</entry>
<entry>
<title>DedeCMS技术可参考网站备份</title>
<link href="https://wangen.github.io/2017/12/17/dede-web-1/"/>
<id>https://wangen.github.io/2017/12/17/dede-web-1/</id>
<published>2017-12-16T16:25:27.000Z</published>
<updated>2017-12-16T16:32:26.428Z</updated>
<content type="html"><![CDATA[<h2 id="DedeCMS技术点及模板使用可参考网站部分备忘"><a href="#DedeCMS技术点及模板使用可参考网站部分备忘" class="headerlink" title="DedeCMS技术点及模板使用可参考网站部分备忘"></a>DedeCMS技术点及模板使用可参考网站部分备忘</h2><p>存在即合理,流行就代表优秀…</p><blockquote><p>1、<a href="http://www.dedediy.com/luojishuju/" target="_blank" rel="noopener">织梦二次开发</a></p><p>2、<a href="http://www.dedejs.com/html/list-11.html" target="_blank" rel="noopener">CMS资源网</a></p><p>3、<a href="http://www.dede58.com/a/dedeaz/2792.html" target="_blank" rel="noopener">织梦58</a></p></blockquote>]]></content>
<summary type="html">
&lt;h2 id=&quot;DedeCMS技术点及模板使用可参考网站部分备忘&quot;&gt;&lt;a href=&quot;#DedeCMS技术点及模板使用可参考网站部分备忘&quot; class=&quot;headerlink&quot; title=&quot;DedeCMS技术点及模板使用可参考网站部分备忘&quot;&gt;&lt;/a&gt;DedeCMS技术点及模板使
</summary>
<category term="DedeCMS" scheme="https://wangen.github.io/categories/DedeCMS/"/>
<category term="DedeCMS" scheme="https://wangen.github.io/tags/DedeCMS/"/>
<category term="参考网站" scheme="https://wangen.github.io/tags/%E5%8F%82%E8%80%83%E7%BD%91%E7%AB%99/"/>
</entry>
<entry>
<title>Dedecms织梦会员邮件验证与自定义表单发送邮件-官方类版-支持QQ邮箱163邮箱</title>
<link href="https://wangen.github.io/2017/12/17/dede-email-1/"/>
<id>https://wangen.github.io/2017/12/17/dede-email-1/</id>
<published>2017-12-16T16:11:03.000Z</published>
<updated>2018-01-13T10:34:38.121Z</updated>
<content type="html"><![CDATA[<h4 id="会员邮件验证效果"><a href="#会员邮件验证效果" class="headerlink" title="会员邮件验证效果"></a>会员邮件验证效果</h4><p><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031201926.png" alt="member-email"></p><h4 id="自定义表单发送邮件效果"><a href="#自定义表单发送邮件效果" class="headerlink" title="自定义表单发送邮件效果"></a>自定义表单发送邮件效果</h4><p><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031201550.png" alt="form-email"></p><h2 id="设置步骤如下:"><a href="#设置步骤如下:" class="headerlink" title="设置步骤如下:"></a>设置步骤如下:</h2><h4 id="1、QQ邮箱-或者-163邮箱-开启SMTP服务,拿到授权码"><a href="#1、QQ邮箱-或者-163邮箱-开启SMTP服务,拿到授权码" class="headerlink" title="1、QQ邮箱 或者 163邮箱 开启SMTP服务,拿到授权码"></a>1、QQ邮箱 或者 163邮箱 开启SMTP服务,拿到授权码</h4><p><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031202215.png" alt="email-shouquanma"></p><h4 id="2、网站后台-系统-系统基本参数-核心设置"><a href="#2、网站后台-系统-系统基本参数-核心设置" class="headerlink" title="2、网站后台 - 系统 - 系统基本参数 - 核心设置"></a>2、网站后台 - 系统 - 系统基本参数 - 核心设置</h4><blockquote><p>网站发信EMAIL:wuruhua@163.com 或者 65602960@qq.com (本文邮箱均为示例,请按需求填写自己的邮箱)</p><p>是否启用smtp方式发送邮件:是</p><p>smtp服务器:ssl://smtp.163.com 或者 ssl://smtp.qq.com</p><p>smtp服务器端口:465</p><p>SMTP服务器的用户邮箱:wuruhua@163.com 或者 65602960@qq.com</p><p>SMTP服务器的用户帐号:wuruhua 或者 65602960</p><p>SMTP服务器的用户密码:填你邮箱授权码,不是邮箱登录密码</p></blockquote><p>如图</p><blockquote><p>配置QQ邮箱的是这样<br><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031195906.png" alt="email-qq-set"></p><p>配置163邮箱的是这样<br><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031195754.png" alt="email-163-set"></p><p>至此会员邮件验证配置完成,会员就能收到验证邮件了;自定义表单发送邮件的小伙伴继续往下看</p></blockquote><h4 id="3、网站后台-系统-系统基本参数-添加新变量"><a href="#3、网站后台-系统-系统基本参数-添加新变量" class="headerlink" title="3、网站后台 - 系统 - 系统基本参数 - 添加新变量"></a>3、网站后台 - 系统 - 系统基本参数 - 添加新变量</h4><blockquote><p>变量名称:cfg_shoujianren<br>变量类型:文本<br>参数说明:收件人<br>变量值:发送邮件通知者,如65602960@qq.com<br>所属组:站点设置</p></blockquote><p>如图<br><img src="http://www.dedediy.com/uploads/allimg/QQimg20171031203350.png" alt="system-set"></p><h4 id="4、打开-plus-diy-php-找到"><a href="#4、打开-plus-diy-php-找到" class="headerlink" title="4、打开 /plus/diy.php 找到"></a>4、打开 /plus/diy.php 找到</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$id</span> = <span class="variable">$dsql</span>-&gt;GetLastID();</span><br></pre></td></tr></table></figure><p>在它的下面加入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$mailtitle</span> = <span class="string">"&#123;<span class="variable">$diy</span>-&gt;name&#125;--留言通知"</span>;</span><br><span class="line"><span class="variable">$mailbody</span> = <span class="string">''</span>;</span><br><span class="line">foreach(<span class="variable">$diy</span>-&gt;getFieldList() as <span class="variable">$field</span>=&gt;<span class="variable">$fieldvalue</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="variable">$mailbody</span> .= <span class="string">"&#123;<span class="variable">$fieldvalue</span>[0]&#125;:&#123;<span class="variable">$&#123;$field&#125;</span>&#125;\r\n"</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$headers</span> = <span class="string">"From: "</span>.<span class="variable">$cfg_adminemail</span>.<span class="string">"\r\nReply-To: "</span>.<span class="variable">$cfg_adminemail</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="variable">$cfg_sendmail_bysmtp</span> == <span class="string">'Y'</span> &amp;&amp; !empty(<span class="variable">$cfg_smtp_server</span>))</span><br><span class="line">&#123;</span><br><span class="line"><span class="variable">$mailtype</span> = <span class="string">'TXT'</span>;</span><br><span class="line">require_once(DEDEINC.<span class="string">'/mail.class.php'</span>);</span><br><span class="line"><span class="variable">$smtp</span> = new smtp(<span class="variable">$cfg_smtp_server</span>,<span class="variable">$cfg_smtp_port</span>,<span class="literal">true</span>,<span class="variable">$cfg_smtp_usermail</span>,<span class="variable">$cfg_smtp_password</span>);</span><br><span class="line"><span class="variable">$smtp</span>-&gt;debug = <span class="literal">false</span>;</span><br><span class="line"><span class="variable">$smtp</span>-&gt;sendmail(<span class="variable">$cfg_shoujianren</span>,<span class="variable">$cfg_webname</span> ,<span class="variable">$cfg_smtp_usermail</span>, <span class="variable">$mailtitle</span>, <span class="variable">$mailbody</span>, <span class="variable">$mailtype</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">@mail(<span class="variable">$cfg_shoujianren</span>, <span class="variable">$mailtitle</span>, <span class="variable">$mailbody</span>, <span class="variable">$headers</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>至此自定义表单发送邮件通知管理者设置完成</p><p>本文来源<a href="http://www.dedediy.com/luojishuju/175.html" target="_blank" rel="noopener">www.dedediy.com</a> ,仅作为备份参考使用</p>]]></content>
<summary type="html">
&lt;h4 id=&quot;会员邮件验证效果&quot;&gt;&lt;a href=&quot;#会员邮件验证效果&quot; class=&quot;headerlink&quot; title=&quot;会员邮件验证效果&quot;&gt;&lt;/a&gt;会员邮件验证效果&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;http://www.dedediy.com/uploads/allim
</summary>
<category term="DedeCMS" scheme="https://wangen.github.io/categories/DedeCMS/"/>
<category term="DedeCMS" scheme="https://wangen.github.io/tags/DedeCMS/"/>
<category term="邮件" scheme="https://wangen.github.io/tags/%E9%82%AE%E4%BB%B6/"/>
</entry>
</feed>
HTML
1
https://gitee.com/lovetime/wangen.github.io.git
git@gitee.com:lovetime/wangen.github.io.git
lovetime
wangen.github.io
blog
master

搜索帮助