Omi实战-QQ附近用户列表Web页

yuyujia 7年前
   <h2>写在前面</h2>    <p>Omi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。</p>    <p>项目开始之前,实现选择一个脚手架。这个项目用的就是 <a href="/misc/goto?guid=4959738586732205584" rel="nofollow,noindex">Omi Github上的scaffolding</a> 作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)</p>    <p>Gulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。</p>    <p>这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/13965b7cc43fba960b4948528e46e3a5.png"></p>    <p>所以,要使用Fiddler并配置Extention:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1d24210809fa8616ed5ce0f3c9d37237.png"></p>    <h2>目录</h2>    <p><img src="https://simg.open-open.com/show/c283ae06925e5522f497b1a5c5788864.png"></p>    <p>目录结构也是和 <a href="/misc/goto?guid=4959738586732205584" rel="nofollow,noindex">Omi Github上的scaffolding</a> 一样。</p>    <p>组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。</p>    <h2>命令</h2>    <p>开发</p>    <pre>  <code class="language-java">npm run dev</code></pre>    <p>发布</p>    <pre>  <code class="language-java">npm run dist</code></pre>    <h2>开始写码</h2>    <p>万事具备,开始写码。先写组件:</p>    <pre>  <code class="language-java">import Omi from 'omi'    class UserList extends Omi.Component {      constructor(data) {          super(data)      }        install() {          this.data.uin_info || (this.data.uin_info = [])          this.data.uin_info.forEach(user => {              this.prepareData(user)          })      }            prepareData(user){          user.desc_d = user.desc.split(" ")[0]          user.desc_t = user.desc.split(" ")[1]          user.isBoy = user.sex === "男"          user.qlogo = user.url.replace("http://", location.protocol + "//").replace(/&/g, "&")          if (user.profession_desc) {              user.hasProfession_desc = true          }      }            appendUsers (users) {          users.uin_info && users.uin_info.forEach(user =>{              this.prepareData(user)              this.data.uin_info.push(user)          })          this.update()      }        sendGift(uin, nick, qlogo) {          //送礼物并关闭webview,此处省略          //..          //..      }        render() {          return `  <div class="user_list">      {{#uin_info}}      <div class="item" onclick="sendGift('{{uin}}','{{nick}}','{{qlogo}}')">          <div class="qlogo">              <img style="width: 70px;" src="{{qlogo}}" />          </div>          <div class="main b1 bb">              <div class="nick">{{{nick}}}</div>              <div class="icons">                  {{#isBoy}}<span class="boy_age"><img src="component/user_list/boy.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}                 {{^isBoy}}<span class="girl_age"><img src="component/user_list/girl.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}                  {{#hasProfession_desc}} <span class="profession"><span>{{profession_desc}}</span></span> {{/hasProfession_desc}}              </div>              <div class="action">{{{intro}}}</div>          </div>          <div class="distance_info">{{desc_d}} · {{desc_t}}</div>      </div>      {{/uin_info}}      <div style="text-align:center;font-size:13px;line-height:30px;height:30px;"><span class="loading"></span> 加载中...</div>  </div>  `      }        style() {          return `      .qlogo {      overflow: hidden;      width: 70px;      height: 70px;      -webkit-border-radius: 50%;      border-radius: 50%;      position: absolute;      top: 10px;      left: 12px;  }  ...  ...  ..这里省略大量.....  ...  ...    .distance_info {      position: absolute;      top: 15px;      right: 9px;      color: #7B7B84;      font-size: 10px;  }            `      }  }    export default UserList</code></pre>    <p>组件里面有5个方法:</p>    <ul>     <li>constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this</li>     <li>install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理</li>     <li>prepareData 对数据进行一些处理来满足模板的渲染</li>     <li>appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用</li>     <li>sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..</li>    </ul>    <p>其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。</p>    <p>render里面使用了 <a href="/misc/goto?guid=4958341604691389041" rel="nofollow,noindex">mustache.js</a> 模板引擎;</p>    <p>如果使用omi.lite.js版本(不包含 <a href="/misc/goto?guid=4958341604691389041" rel="nofollow,noindex">mustache.js</a> 模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。</p>    <p>这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7ae4bedac7356ff0add4381bc81892c8.png"></p>    <p>下面来看index.js:</p>    <pre>  <code class="language-java">import Root from './config.js'  import Omi from 'omi'  import UserList from '../component/user_list/index.js'    Omi.makeHTML('UserList', UserList)    class Main extends Omi.Component {      constructor(data) {          super(data)      }        installed() {          window.onscroll = () => this.loadMore()          this.requestData(data => this.list.appendUsers(data))      }        loadMore() {          const body = document.body,              html = document.documentElement,              height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),              vp_height = window.innerHeight            if (height - document.body.scrollTop - vp_height < 200) {              this.requestData(data => this.list.appendUsers(data))          }      }        requestData(callback) {          if (Root.isDev) {              require.ensure([], ()=> {                  callback(require('./mock_data.js').default)              })          }else{              //ajax 请求数据,这里省略          }      }        render() {          return `      <div class="main">          <UserList name="list" />      </div>`      }  }    Omi.render(new Main(),'body')</code></pre>    <p>通过Omi.makeHTML('UserList', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:</p>    <pre>  <code class="language-java">render() {          return `      <div class="main">          <UserList name="list" />      </div>`      }</code></pre>    <p>下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。</p>    <pre>  <code class="language-java">window.onscroll = () => this.loadMore()</code></pre>    <p>通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:</p>    <pre>  <code class="language-java">if (height - document.body.scrollTop - vp_height < 200) {      this.requestData(data => this.list.appendUsers(data))  }</code></pre>    <p>requestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。</p>    <p>慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:</p>    <pre>  <code class="language-java"><UserList name="list" /></code></pre>    <p>上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!</p>    <p>再来看下数据模拟:</p>    <pre>  <code class="language-java">if (Root.isDev) {          require.ensure([], ()=> {              callback(require('./mock_data.js').default)          })      }</code></pre>    <p>这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!</p>    <h2>最后</h2>    <p>好了,就这么多,Omi让代码真心方便简洁~~~</p>    <p> </p>    <p>来自:http://www.cnblogs.com/iamzhanglei/p/6430457.html</p>    <p> </p>