<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      QQ日跡Omi實戰開發,從0到1

      2017-07-17 09:52  【當耐特】  閱讀(1863)  評論(1)    收藏  舉報

      寫在前面

      相信大家對Omi應該都不陌生了,如果還有不了解的同學先看看這里。了解并使用Omi之后你會發現真的回不去了~~~

      先簡單說一下吧,Omi就是一個可以快速開發項目的組件化框架,和vue/react一樣為了節省生產力的。想了解Omi和vue還有react區別的,上面文檔有講解,或者加入群256426170,可以面對面咨詢Omi作者dnt。我這篇文章將使用Omi從0到1來完成一個移動端的項目,讓大家了解Omi開發的方便快捷。


      開發準備:

      這次我們挑選了一個日跡發現頁來作為例子開發,如果有用手機QQ的同學,應該有知道“日跡”這個項目,這次我們就挑選了一個日跡的一個發現頁,入口在手機QQ -> 動態 -> 日跡 -> 右上角發現
      發現頁如下

      開發一個移動端頁面和PC上開發是一樣的,首先要分析頁面劃分模塊,發現頁很簡單,可以看成一個列表,然后里面每一塊是一個item
      如果不用組件化的話,ul+li是不是就可以上手干了~但我們要告別原始社會的開發方式,采用Omi框架進行開發,下面就正式開始開發~

      開發過程:


      ## 1/ 腳手架 開發一個項目(一個頁面也是一個項目),首先我們需要腳手架,腳手架可以從歷史項目中復制過來,也可以自己重新搭建。使用Omi的話就方便很多啦,我們只需要下面兩步
          npm install omi-cli -g
          omi-cli init [project name]
      

      然后腳手架就OK了,下面簡單的看一下腳手架,了解一下項目結構

      下面那些.babelrc/.eslintrc/package.json等就不說了
      先看目錄,config是配置目錄,里面有基礎配置和項目配置,一般我們不需要修改
      tools里面是構建相關,webpack.base.js是基礎配置,然后測試環境和生產環境的區分就靠script.js了

      src是開發的目錄,也是我們代碼所在地,打開src再看一下

      應該還是很好理解的,page是頁面,這里面每個目錄就意味著有一個頁面。頁面的入口是目錄下的main

      component是組件,組件也是以文件夾為粒度來的,里面一定有一個js文件,然后組件相關的資源文件,樣式文件也都放在js的同一目錄下,比如這樣

      組件的圖片/樣式和js都有了,那外面的css/img/js呢?是一些全局資源和公共方法等,這樣一來復用就極為方便了。

      2/ 正式開發

      首先我們引入一下rem統一的js代碼,現在來說用rem還是比px方便很多的,代碼如下:

          ;(function(win) {
              var doc = win.document;
              var docEl = doc.documentElement;
              var tid;
      
              function refreshRem() {
                  var width = docEl.getBoundingClientRect().width;
                  if (width > 540) { // 最大寬度
                      width = 540;
                  }
                  var rem = width / 10; // 將屏幕寬度分成10份, 1份為1rem
                  docEl.style.fontSize = rem + 'px';
              }
      
              win.addEventListener('resize', function() {
                  clearTimeout(tid);
                  tid = setTimeout(refreshRem, 300);
              }, false);
              win.addEventListener('pageshow', function(e) {
                  if (e.persisted) {
                      clearTimeout(tid);
                      tid = setTimeout(refreshRem, 300);
                  }
              }, false);
      
              refreshRem();
      
          })(window);
      

      這樣我們就將不同屏幕下的rem與px轉換統一了,視覺稿上面的px單位除以37.5就可以了,這一步也可以在構建的時候做

      接下來我們考慮到項目是一個長列表,說到長列表就肯定離不開滾動,說到滾動就想到了安卓下局部滾動會很卡。那么這里可以用全局滾動搞定么?可以的,因為頁面本身不復雜。
      那么復雜的情景下,必須是局部滾動的場景怎么辦呢?AlloyTouch歡迎你~解決各類滾動問題,而且有Omi插件的無縫支持版本。

      使用omi-touch

      準備工作都考慮完善之后我們就開始寫第一個組件了!第一個組件可以看成是整個列表的一個包裹盒,盒子里面不僅有list,還有按鈕和一些其他的玩意
      先上一下代碼

          import List from '../list/index';
      
          Omi.tag('List', List);
      
          class Main extends Omi.Component {
              constructor(data) {
                  super(data);
      
                  this.inTouch = false;
                  this.touchXY = [];
                  this.data.loadWord = '正在加載中...';
              }
      
              style() {
                  return `
                      .record {
                          position: fixed;
                          bottom: 0.533333rem;
                          left: 50%;
                          -webkit-transform: translateX(-50%);
                          transform: translateX(-50%);
                          background-image: url(${require('./img/record.png')});
                          width: 2.000000rem;
                          height: 2.000000rem;
                          background-size: 100% 100%;
                      }
                      .isend {
                          position: relative;
                          text-align: center;
                          margin: 0 auto;
                          margin-left: -12px;
                          padding: 12px 0;
                          font-size: 14px;
                          color: rgba(119, 119, 119, 1);
                      }
                  `;
              }
      
              render() {
                  return `
                  <div class="main">
                      <List omi-id="list"></List>
                      <div class="record" ontouchmove="handleTouchMove(this, event)" ontouchstart="handleTouchStart(this, event)" ontouchend="handleTouchEnd(this, event)"></div>
                      <div class="isend">${this.data.loadWord}</div>
                  </div>`;
              }
              handleTouchMove(dom, e) {
                  this.inTouch = false;
              }
              handleTouchStart(dom, e) {
                  this.inTouch = true;
      
                  this.touchXY[0] = e.touches[0].screenX;
                  this.touchXY[1] = e.touches[0].screenY;
              }
              handleTouchEnd(dom, e) {
                  console.log(e.changedTouches[0]);
      
                  var diffX = Math.abs(e.changedTouches[0].screenX - this.touchXY[0]);
                  var diffY = Math.abs(e.changedTouches[0].screenY - this.touchXY[1]);
      
                  if(this.inTouch && diffX < 30 && diffY < 30) {
                      // handle tap event....
                      this.inTouch = false;
                  }
                  e.preventDefault();
                  
              }
          }
      
          export default Main;
      

      超級簡單明了,constructor是組件的構造函數,也是生命周期的開始,因為我們包裹盒的組件一直存在,所以沒有用上其他生命周期的方法。但Omi對組件生命周期的控制可是非常強大的,如下圖

      接著是style和render,這里是用模版字符串寫css和html,很方便,但如果覺得麻煩也可以用文件的形式,后面會說

      下面三個是啥呢?是自己模擬的tap,因為移動端下onclick有300ms的延遲,所以我們用的點擊都是模擬的。tap用語言描述就是一次點擊,我們要保證touchend時候手指的位置不能距離touchstart的位置太遠,而且end和start期間不能觸發touchmove,這也就是自己實現tap的核心了。

      如果有zepto的話本身可以用ontap事件,不必自己去寫,但是我這里沒有引入zepto,而且zepto本身是jquery類似的寫法,和框架開發還是比較背馳的。那么我們就只能自己寫這么多代碼去模擬么??
      當然不是!因為我們有alloyfinger-omi版,我們只需要這樣

      安裝:

      npm install omi-finger
      

      使用:

          import OmiFinger from 'omi-finger';
          OmiFinger.init();
      

      使用omi-finger

      就可以了!alloytouch里面的手勢操作omi-finger都可以用,而且用起來也超級方便!

          ......
          render() {
              return `
              <div class="main">
                  <List omi-id="list"></List>
                  <div class="record" omi-finger tap="handleTap"></div>
                  <div class="isend">${this.data.loadWord}</div>
              </div>`;
          }
      
          handleTap() {
              // handle tap event....
          }
          ......
      

      這樣就可以了,這就是Omi插件體系的好處,順帶一提alloytouch也可以像finger這樣使用~

      這樣最外層的包裹組件就已經ok了,我們來看核心的list組件。
      再上代碼

          class List extends Omi.Component {
              constructor(data) {
                  super(data);
      
                  this.length = 0;
      
                  this.data.leftList = [];
                  this.data.rightList = [];
      
              }
              style() {
                  return require('./_index.less');
              }
      
              render() {
                  return `
                      <div class="wrap clear" omi-finger tap="handleTap">
                      <div class="left">
                          ${
                              this.data.leftList.map((a, b) => 
                                  `<Item data="data.leftList[${b}]"></Item>`
                              ).join('')
                          }
                      </div>
      
                      <div class="right">
                          ${
                              this.data.rightList.map((a, b) => 
                                  `<Item data="data.rightList[${b}]"></Item>`
                              ).join('')
                          }
                      </div>
                  </div>`;
              }
              add(data) {
                  for(let i = 0; i < data.length; i++) {
                      // handle data
      
      
                      if(i % 2 === 0) {
                          this.data.leftList.push(info);
                      } else {
                          this.data.rightList.push(info);
                      }
                  }
      
                  this.update();
              }
              handleTap(e) {
      
                  // handle tap;
      
              }
              reset() {
                  this.data.leftList = [];
                  this.data.rightList = [];
              }
          }
      

      首先可以看到和main不同的是,這里我們就把css給抽離成文件的形式了,純看個人喜好。不過有一些需要注意的地方:
      1. 全局css只需要在文件中import就可以了
      2. 局部css或者less文件名必須以_開頭,loader會針對進行操作,就像上面的代碼一樣
      3. html抽離成文件的話需要用模版引擎的方式,上面代碼用的是ES6模版字符串,這樣的話是無法抽離成文件的。

      omi.js默認的模版引擎是soda,如果還有喜歡ejs、mustache語法的同學,雖然omi.js本身沒有內置該寫法,但是用omi.mustache.js卻將其默認為內置模版引擎
      具體的情況如下:

      • omi.js 使用 sodajs 為內置指令系統
      • omi.art.js 使用 art-template 為內置模版引擎
      • omi.lite.js 不包含任何模板引擎
      • omi.mustache.js 使用 mustache.js為內置模版引擎

      接下來重點講的就是其中的循環生成子組件部分
      循環渲染有多種方式,剛剛代碼部分用的是ES6執行map,然后獲取到數組中每一個元素,渲染
      我們也可以使用omi中內置的soda模版的指令方式,如下代碼也可以實現同樣的功能

          render() {
              return `
                  <div class="wrap clear" omi-finger tap="handleTap">
                  <div class="left">
                      <Item o-repeat="item in leftList" group-data="data.leftList"></Item>
                  </div>
      
                  <div class="right">
                      <Item o-repeat="item in rightList" group-data="data.rightList"></Item>
                  </div>
              </div>`;
          }
      

      我們在add方法中進行數據的處理,這里組件的data下面有兩個數組,分別是左右兩邊的。注意這里add方法最后有調用一個update()方法,omi本身沒有雙向綁定,將更新的操作交給了開發者。當然如果希望雙向綁定的話也可以引入Mobx之類的第三方庫。

      list組件里面有一個item組件,這個item組件就是最后一個啦,它需要從list中接受到自己的數據,然后將數據給展示出來
      數據傳遞的方式有很多種,簡單的說一下

      • on-* 代表傳遞父組件向子組件注入的回調函數,比on-page-change="pageChangeHandler"
      • data-* 代表直接傳遞字符串
      • :data-* 代表傳遞javascript表達式,比如data-num="1" 代表傳遞數字1而非字符串,data-num="1+1"可以傳遞2。
      • ::data-* 代表傳遞父組件的屬性,比如上面的::data-items="data.items"就代表傳遞this.data.items給子組件
      • data 代表傳遞父組件的屬性,比如data="user"代表傳遞this.user給子組件
      • :data 代表傳遞javascript表達式,比如data="{ name : 'dntzhang' , age : 18 }"代表傳遞{ name : 'dntzhang' , age : 18 }給子組件
      • group-data 代表傳遞父組件的數組一一映射到子組件

      我們采用的是第x種,然后item中就是簡單的展示啦

          class Item extends Omi.Component {
              constructor(data) {
                  super(data);
                  console.log('data', data);
              }
              style() {
                  return require('./_index.less');
              }
              render() {
                  return `
                      <div class="item">
                          <div class="card" vid="${this.data.vid}" shoot="${this.data.shoot}" uin="${this.data.uin}">
                              <div class="pic" style="background-image: url(${this.data.pic})"></div>
                              <div class="txt">
                                  <div class="head" style="background-image: url(${this.data.head})"></div>
                                  <div class="other">
                                      <div class="nick" data-content='${this.data.nick}'>${this.data.nick}</div>
                                      <div class="info">
                                          <span class="watch"><i></i>${this.data.watch}</span>
                                          <span class="like"><i></i>${this.data.like}</span>
                                      </div>
                                  </div>
                              </div>
                          </div>
                      </div>
                  `;
              }
          }
      
          export default Item;
      

      3/ 構建相關

      開發過程中我們只需要npm start,然后就可以專注的擼代碼了
      可以用默認的localhost:9000端口進行訪問
      也可以修改config目錄下的config.js文件,用路由的方式訪問,比如我這樣

          module.exports = {
              "webserver": "http://xxx.qq.com/mobile/",
              "cdn": "",
              "port": "9000",
              "route": "/mobile/"
          };
      

      當然我這里是有配置代理的,將xxx.qq.com/mobile指向了本地的localhost:9000
      當你開發完成后,只需要運行

      **npm run dist**
      

      生產環境的代碼就已經搞定了~接下來就是部署、提測...

      結語

      文章一些cgi、util相關的代碼就省略掉了,主要目的是講解Omi的開發。雖然是一個很小的頁面,不過可以看出來用omi+omi-cli開發還是很簡單的哈!Omi的能力當然不止這一點點,我這篇文章只是拋磚引玉,大家想解放生產力的話,快來使用Omi吧~~

      在線體驗地址,請使用手機QQ掃描下方二維碼

      github地址:

      有問題的話可以留言大家一起交流~

      主站蜘蛛池模板: 亚洲免费一区二区av| 少妇人妻偷人精品免费视频| 亚洲精品自拍区在线观看| 久热这里只有精品视频3| 亚欧美闷骚院| 国产精品男女爽免费视频| 疯狂添女人下部视频免费| 中文无码乱人伦中文视频在线| 国产色视频一区二区三区qq号| 国产乱妇无码大片在线观看| 思热99re视热频这里只精品| 国产亚洲一区二区三区四区| 东京热人妻丝袜无码AV一二三区观| 午夜精品福利亚洲国产| 一区二区三区精品自拍视频| 国产精品一区二区三区蜜臀| 成人av一区二区三区| 亚洲一区成人在线视频| 欧美影院成年免费版| 久久精品国产91精品亚洲| 熟女系列丰满熟妇AV| 国产永久免费高清在线| 极品尤物被啪到呻吟喷水| 国内精品伊人久久久久影院对白| 在线视频中文字幕二区| 自拍视频亚洲精品在线| 日本视频一两二两三区| 妓女妓女一区二区三区在线观看 | 日韩高清在线亚洲专区不卡| 精品无码国产自产拍在线观看蜜| 超碰成人人人做人人爽| 国内自拍av在线免费| 黑人精品一区二区三区不| 在线看无码的免费网站| 少妇高潮水多太爽了动态图| 午夜夜福利一区二区三区| 2020无码专区人妻系列日韩| 国产精品自在自线视频| 中文字幕午夜福利片午夜福利片97| 91色老久久精品偷偷性色| 中文字幕第一页亚洲精品|