小程序?qū)崿F(xiàn)在線選座實(shí)戰(zhàn)(上)

hi~ 大家好喻括,我叫內(nèi)孤蒲拉,一名web前端開(kāi)發(fā)者/:B-甸各,今天我來(lái)分享一個(gè)移動(dòng)端在線選座的功能頁(yè)面慌随,我們知道微信小程序可以用web-view嵌入html頁(yè)面芬沉,所以這個(gè)選座功能我們就用html、css阁猜、javascript一步一步實(shí)現(xiàn)丸逸。避免篇幅太長(zhǎng),我將整個(gè)功能的實(shí)現(xiàn)分為上剃袍、中黄刚、下。

假設(shè)下圖就是我們要實(shí)現(xiàn)的功能頁(yè)面民效,我們先對(duì)這個(gè)功能頁(yè)面進(jìn)行組件劃分憔维,header、main畏邢、footer三個(gè)組件來(lái)分別實(shí)現(xiàn):


image.png

1. 創(chuàng)建index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1.0,user-scalable=no,viewport-fit=cover"/>
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <!-- 初始化樣式 -->
  <link rel="stylesheet" href="./css/reset.css">
  <link rel="stylesheet" href="./css/styles.css">
  <!-- rem 的解決方案 -->
  <script type="text/javascript">
  (function(e,t){var i=document,n=window;var l=i.documentElement;var r,a;var d,o=document.createElement("style");var s;function m(){var i=l.getBoundingClientRect().width;if(!t){t=540}if(i>t){i=t}var n=i*100/e;o.innerHTML="html{font-size:"+n+"px;}"}r=i.querySelector('meta[name="viewport"]');a="width=device-width,initial-scale=1,maximum-scale=1.0,user-scalable=no,viewport-fit=cover";if(r){r.setAttribute("content",a)}else{r=i.createElement("meta");r.setAttribute("name","viewport");r.setAttribute("content",a);if(l.firstElementChild){l.firstElementChild.appendChild(r)}else{var c=i.createElement("div");c.appendChild(r);i.write(c.innerHTML);c=null}}m();if(l.firstElementChild){l.firstElementChild.appendChild(o)}else{var c=i.createElement("div");c.appendChild(o);i.write(c.innerHTML);c=null}n.addEventListener("resize",function(){clearTimeout(s);s=setTimeout(m,300)},false);n.addEventListener("pageshow",function(e){if(e.persisted){clearTimeout(s);s=setTimeout(m,300)}},false);if(i.readyState==="complete"){i.body.style.fontSize="16px"}else{i.addEventListener("DOMContentLoaded",function(e){i.body.style.fontSize="16px"},false)}})(750,750);
  </script>
  <title>在線選座</title>
</head>
<body>
  <div class="page">

    <div class="header">
    </div>

    <div class="main">

    </div>

    <div class="footer">

    </div>
    
  </div>
</body>
</html>

這里我們定義了header业扒、main、footer容器棵红,分別來(lái)裝載三個(gè)組件凶赁,所有的樣式都放在styles.css中咧栗,reset.css是來(lái)重置樣式逆甜,結(jié)合header里的那段腳本實(shí)現(xiàn)rem不同屏幕自適應(yīng)虱肄。

2. 書(shū)寫(xiě)對(duì)應(yīng)的布局樣式(styles.css)

/* 基本布局樣式 */
.page {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  color: #999;
}
.header {
  height: .9rem;
  overflow: hidden;
  background-color: #fff;
}
.main {
  background-color: #eee;
  flex-grow: 1;
  overflow: hidden;
}
.footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 1.2rem;
  background-color: #fff;
}
.mrgR60 {
  margin-right: 0.6rem;
}

3. reset.css

  body,dl,dd,ul,ol,h1,h2,h3,h4,h5,h6,pre,form,input,textarea,p,hr,thead,tbody,tfoot,th,td{margin:0;padding:0;}
  ul,ol{list-style:none;}
  a{text-decoration:none;}
  html{-ms-text-size-adjust:none;-webkit-text-size-adjust:none;text-size-adjust:none;font-size:50px;}
  body{line-height:1.5;font-size:16px;}
  body,button,input,select,textarea{font-family:'helvetica neue',tahoma,'hiragino sans gb',stheiti,'wenquanyi micro hei',\5FAE\8F6F\96C5\9ED1,\5B8B\4F53,sans-serif;}
  b,strong{font-weight:bold;}
  i,em{font-style:normal;}
  table{border-collapse:collapse;border-spacing:0;}
  table th,table td{border:1px solid #ddd;padding:5px;}
  table th{font-weight:inherit;border-bottom-width:2px;border-bottom-color:#ccc;}
  img{border:0 none;width:auto\9;max-width:100%;vertical-align:top;}
  button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;vertical-align:baseline;}
  button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
  button[disabled],input[disabled]{cursor:default;}
  input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}
  input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}
  input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
  @media screen and (-webkit-min-device-pixel-ratio:0){
  input{line-height:normal!important;}
  }
  select[size],select[multiple],select[size][multiple]{border:1px solid #AAA;padding:0;}
  article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}
  audio,canvas,video,progress{display:inline-block;}


  .g-doc{width:7.5rem;margin:0px auto;}

4. 組件1: 座位狀態(tài)示意圖

這里沒(méi)有互動(dòng),是很簡(jiǎn)單的展示組件

// 在index.html中的header中添加

<div class="header">
  <div class="seatStatusList">
    <div class="statusLabel mrgR60">
      <img src="./image/seat.png"/>
      <span>已選中</span>
    </div>
    <div class="statusLabel">
      <img src="./image/seat_disabled.png"/>
      <span>不可選</span>
    </div>
  </div>
</div>

// 添加到styles.css中交煞,座位狀態(tài)組件
.seatStatusList {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 1rem;
}
.seatStatusList .statusLabel img {
  width: .5rem;
  height: .4rem;
  margin-right: .1rem;
}

到這一步我們可以看到基本的架子了

image.png

5. 實(shí)現(xiàn)底部的組件

這個(gè)組件我們就創(chuàng)建一個(gè)footer.js實(shí)現(xiàn)

var Footer = (function(factory) {
  return factory.call();
}(function() {
  // 定義默認(rèn)的回調(diào)
  var __DESC__ = {
    onClickInfoModule: function() {},
    onHandleSure: function() {},
    /**
     * 默認(rèn)格式化數(shù)據(jù)的回調(diào)
     * @param {Array} data 例如:[{id: 1, price: 2}]
     * 注意: 如果沒(méi)有定義formatData回調(diào)咏窿,需要確保item中包含price
     * @return {total, count}
     */
    formatData: function(data) {
     var total = 0, count = 0, res = {};
     if (Object.prototype.toString.call(data) === "[object Array]") {
      for (var i = 0, len = data.length; i < len; i++) {
        count++;
        if (data[i].price) {
          total += data[i].price;
        } else {
          new Error('座位信息中沒(méi)有price字段');
          break;
        }
      }
      res.total = total;
      res.count = count;
     } else {
      new Error('data 不是一個(gè)數(shù)組');
     }
     return res;
    }
  };
  var __CORE__ = {
    init: function(options) {
      this.$el = document.querySelector(options.el);
      this.onHandleSure = options.onHandleSure || __DESC__.onHandleSure;
      this.formatData = options.formatData || __DESC__.formatData;
      this.onClickInfoModule = options.onClickInfoModule || __DESC__.onClickInfoModule;
      this.data = [];
      this._renderDefaultTpl();
      this._onClickSureBtn();
      this._onClickInfoModule();
      return this;
    },
    // 監(jiān)聽(tīng)點(diǎn)擊了信息模塊的回調(diào)
    _onClickInfoModule: function () {
      var me = this;

      me.$el.addEventListener('touchstart', function(e) {
        var target = e.target;
        var parentNode = target.parentNode;
        if (parentNode.className && parentNode.className.indexOf('priceBox') > -1 || parentNode.parentNode.className && parentNode.parentNode.className.indexOf('priceBox') > -1) {
          if (typeof me.onClickInfoModule === 'function') {
            me.onClickInfoModule.call(me, me.data);
          }
        }
      });
    },
    // 監(jiān)聽(tīng)確定選座按鈕
    _onClickSureBtn: function() {
      var me = this;
      me.$el.addEventListener('touchstart', function(e) {
        var target = e.target;
        // 用me.$el 代理點(diǎn)擊事件
        if (target.className && target.className.indexOf('sureBtn') > -1) {
          if (typeof me.onHandleSure === 'function') {
            me.onHandleSure.call(me, me.data);
          }
        }
      });
    },
    // 私有方法:渲染選中的座位信息
    _renderSelectedSeatInfo: function(total, count) {
      var tpl = '<div class="priceBox"><i>應(yīng)付: <span class="price">' + total + '元' + '</span></i>' +
        '<span>共' + count + '張</span></div>';
      this.$el.querySelector('.total').innerHTML = tpl;
    },
    // 私有方法:渲染默認(rèn)的組件狀態(tài)
    _renderDefaultTpl: function() {
      var tpl = ('<div class="footer-component">' +
        '<div class="total">' +
        '請(qǐng)選擇座位' +
        '</div>' +
        '<div class="sureBtn">確定選座</div>' +
        '</div>');
      this.$el.innerHTML = tpl;
    },
    /**
     * 
     * @param {*} data 傳入的數(shù)據(jù)
     * 如果沒(méi)有自定義formatData回調(diào),約定data數(shù)據(jù)中必須包含price, 例如: [{ price: 2 }]
     */
    setData: function(data) {
      var res = {};
      this.data = data;
      if (typeof this.formatData === 'function') {
        res = this.formatData(data);
      }
      if (res && res.total && res.count) {
        this._renderSelectedSeatInfo(res.total, res.count);
      } else {
        new Error('formatData 返回的參數(shù)沒(méi)有total和count');
      }
    },
    // 重置初始化狀態(tài)
    resetStatus: function() {
      this.data = [];
      this._renderDefaultTpl();
    }
  };

  return __CORE__;
}));

以上我們用閉包創(chuàng)建了一個(gè)Footer組件素征,通過(guò)Footer.init實(shí)現(xiàn)組件初始化集嵌,對(duì)外留著一個(gè)setData方法,用來(lái)設(shè)置約定格式的數(shù)據(jù)然后進(jìn)行視圖渲染御毅。還有一個(gè)resetStatus方法根欧,來(lái)重置狀態(tài)和視圖。

然后我們?cè)趇ndex.js對(duì)組件進(jìn)行初始化

// 監(jiān)聽(tīng)document加載完畢才去初始化各個(gè)組件
document.addEventListener("DOMContentLoaded", function (e) {
  Footer.init({
    el: '.footer',
    onHandleSure: function(data) {
      console.log('點(diǎn)擊確定等到我們選中的座位信息端蛆,發(fā)送給服務(wù)器', data);
    },
    onClickInfoModule: function(data) {
      console.log('點(diǎn)擊了信息模塊', data);
    }
  });
  var selectedData = [
    {
      id: 1,
      price: 1,
    },
    {
      id: 2,
      price: 2
    }
  ];

  Footer.setData(selectedData);

  setTimeout(function() {
    Footer.resetStatus();
  }, 2000);
});

創(chuàng)建了Footer組件后凤粗,我們完成的界面如下:


image.png

回顧

  1. 在整體布局的搭建中我們使用了rem自適應(yīng)屏幕大小方案
  2. 在Footer組件中,我們使用了閉包構(gòu)建組件今豆、使用了事件代理等嫌拣,實(shí)現(xiàn)了如何用javascript構(gòu)建一個(gè)自己的組件

接下去,我們將在《小程序?qū)崿F(xiàn)在線選座實(shí)戰(zhàn)(中)》實(shí)現(xiàn)選座組件呆躲,在《小程序?qū)崿F(xiàn)在線選座實(shí)戰(zhàn)(下)》中實(shí)現(xiàn)數(shù)據(jù)交互异逐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市插掂,隨后出現(xiàn)的幾起案子灰瞻,更是在濱河造成了極大的恐慌,老刑警劉巖辅甥,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箩祥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡肆氓,警方通過(guò)查閱死者的電腦和手機(jī)袍祖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)谢揪,“玉大人蕉陋,你說(shuō)我怎么就攤上這事〔Ψ觯” “怎么了凳鬓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)患民。 經(jīng)常有香客問(wèn)我缩举,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任仅孩,我火速辦了婚禮托猩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辽慕。我一直安慰自己京腥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布溅蛉。 她就那樣靜靜地躺著公浪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪船侧。 梳的紋絲不亂的頭發(fā)上欠气,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音镜撩,去河邊找鬼晃琳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛琐鲁,可吹牛的內(nèi)容都是我干的卫旱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼围段,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼顾翼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起奈泪,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤适贸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涝桅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拜姿,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年冯遂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蕊肥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛤肌,死狀恐怖壁却,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情裸准,我是刑警寧澤展东,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炒俱,受9級(jí)特大地震影響盐肃,放射性物質(zhì)發(fā)生泄漏爪膊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一砸王、第九天 我趴在偏房一處隱蔽的房頂上張望推盛。 院中可真熱鬧,春花似錦处硬、人聲如沸小槐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至件豌,卻和暖如春疮方,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背茧彤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工骡显, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人曾掂。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓惫谤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親珠洗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溜歪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見(jiàn)瀏覽器兼容性問(wèn)題與解決方案? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5许蓖? 答:HTML5是最新的HTML標(biāo)準(zhǔn)蝴猪。 注意:講述HT...
    kismetajun閱讀 27,489評(píng)論 1 45
  • 一:什么是閉包?閉包的用處膊爪? (1)閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)自阱。在本質(zhì)上,閉包就 是將函數(shù)內(nèi)部和函數(shù)外...
    xuguibin閱讀 9,619評(píng)論 1 52
  • $HTML米酬, HTTP沛豌,web綜合問(wèn)題 1、前端需要注意哪些SEO 2赃额、 的title和alt有什么區(qū)別 3琼懊、HT...
    Hebborn_hb閱讀 4,602評(píng)論 0 20
  • 時(shí)間盲注原理: 代碼存在sql注入漏洞,然而頁(yè)面既不會(huì)回顯數(shù)據(jù)爬早,也不會(huì)回顯錯(cuò)誤信息 語(yǔ)句執(zhí)行后也不提示真假哼丈,我們不...
    shadowflow閱讀 2,433評(píng)論 0 0