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

hi~ 大家好队伟,我叫內(nèi)孤俭尖,一名web前端開發(fā)者/:B-,在小程序?qū)崿F(xiàn)在線選座實戰(zhàn)(中)里我們搭建完了layout桶良,下面我們來實現(xiàn)最核心的選座座舍。

在實現(xiàn)選座組件前,我們這里先介紹一下陨帆,我們需要的座位表數(shù)據(jù)結(jié)果

[
  {
    "id": 1,
    "price": 4,
    "x": 1,
    "y": 1
  }
]

其中x曲秉、y代表這個座位在整個座位表中的橫軸和縱軸坐標采蚀,下面我們就針對這個數(shù)據(jù)結(jié)果展開實現(xiàn)這個選座組件

1. 首先創(chuàng)建Seat.js文件,并且初始化基本架子:

var Seat = (function(factory) {
  return factory.call();
}(function() {
  var __CORE__ = {
    init: function() {

    },
    render: function() {

    },
    setData: function() {

    }
  };

  return __CORE__;
}));

下面創(chuàng)建并且在init初始化模版:

    // __CORE__ 里面的方法
    init: function(options) {
      this.$el = document.querySelector(options.el);
      this.data = [];
      this.selectedData = [];

      this.$el.innerHTML = this._getDefaultTpl();
    },
    _getDefaultTpl: function() {
      return (
        '<div class="seatComponent">' +
          '<div class="screen">' +
            '<span class="title">舞臺</span>' +
          '</div>' +
          '<div class="seat-container">' +
          '</div>' + 
        '</div>'        
      );
    },

這里還需要動態(tài)的計算seatComponentseat-container的大小

    // 添加計算容器的大小
    _computedContainerSize: function() {
      var seatContainer = this.$node.parentNode.getBoundingClientRect();
      return {
        width: seatContainer.width,
        height: seatContainer.height
      };
    }

// 修改init
    init: function(options) {
      this.$el = document.querySelector(options.el);
      this.data = [];
      this.selectedData = [];

      this.$el.innerHTML = this._getDefaultTpl();
      this.$node = this.$el.querySelector('.seatComponent');
      
      // 獲取座位容器主要的區(qū)域
      var $seatViewContainer = this.$node.querySelector('.seat-container');
      this.layer = $seatViewContainer;

      // 初始化設(shè)置容器的大小
      var boxSize = this._computedContainerSize();
      this.$node.style.width = boxSize.width + 'px';
      this.$node.style.height = boxSize.height + 'px';

      $seatViewContainer.style.width = boxSize.width + 'px';
      // 42 是舞臺模塊寫死的height+margin
      $seatViewContainer.style.height = boxSize.height - 42 + 'px';
    }

在渲染座位前承二,我們先寫一個setData方法來注入座位信息

    setData: function(data) {
      this.data = data;
      this._renderSeat();
    },
    // 渲染座位表
    _renderSeat: function() {
      var me = this;
      var data = me.data;
      if (!data.length) return;

      var seatsList = this._createdSeat(data);
      this.layer.innerHTML = seatsList;
    },
    _createdSeat: function(data) {
      var me = this;
      var seatsList = '';
      var width = this.width - 20;     // 減去20為了給整個座位表添加一個padding
      var maxSize = this._getWrapperSize(data);
      // 計算一個座位的大小
      var seatWidth = parseInt(width / maxSize.x);
      // 計算整個座位表x軸占滿后榆鼠,剩余的寬度
      var overWidth = width - maxSize.x * seatWidth;
      // 計算左右可用padding
      var offsetLeft = Math.floor(overWidth / 2);

      for (var i = 0, len = data.length; i < len; i++) {
        var item = data[i];
        var _seatLeft = seatWidth * item.x + offsetLeft;
        var _seatTop = seatWidth * item.y;
        // -2 為了空出座位和座位之間的間隙
        var _seatWidth = seatWidth - 2;
        var _seatHeight = seatWidth - 2;
        var style = 'position: absolute; transform: matrix(1, 0, 0, 1,' + _seatLeft.toFixed(1) + ',' + _seatTop.toFixed(1) + '); width:' + _seatWidth.toFixed(1) + 'px;height:' +
        _seatHeight.toFixed(1) + 'px;background-color:' + (item.status === 0 ? '#fff' : '#989898') + ';';
        seatsList += '<div class="seat ' + 'seatId-' + item.id + '" data-index="' + i + '" data-type="seat" data-id="' + item.id + '" data-status="' + item.status + '" style="' + style + '"></div>';
      }

      return seatsList;
    },
    // 獲取seat中最大的x和y
    _getWrapperSize: function(list) {
      var maxX = 0;
      var maxY = 0;

      if (!list) list = [];
      for (var i = 0, len = list.length; i < len; i++) {
        if (list[i].x > maxX) {
          maxX = list[i].x;
        }
        if (list[i].y > maxY) {
          maxY = list[i].y;
        }
      }

      return {
        x: maxX,
        y: maxY
      };
    }

通過_getWrapperSize方法算出最大x和y,然后根據(jù)容器的大小算出每一個座位占用的大小亥鸠。絕對定位每一個座位妆够,一個座位的left:“座位大小座位的x+偏移量”,top:“座位大小座位的y”负蚊,這樣遍歷整個座位列表我們就可以得到整個座位圖:

image.png

接下去實現(xiàn)神妹,拖動座位圖和放大縮小功能:

    _onTouchLayer: function() {
      var me = this, 
          startX, 
          startY, 
          distance = {},
          origin,
          scale;

      me.isMove = false;
      me.isCanScale = false;
      me.scale = 1;
      
      me.$node.addEventListener('touchstart', function(e) {
        e.preventDefault();

        me.isMove = false;
        if (e.touches.length === 1) {
          startX = e.touches[0].clientX;
          startY = e.touches[0].clientY;
        } else if (e.touches.length > 1) {
          // 開始縮放
          me.isCanScale = true;

          distance.start = me._getDistance({
            x: e.touches[0].clientX,
            y: e.touches[0].clientY
          }, {
            x: e.touches[1].clientX,
            y: e.touches[1].clientY
          });
        }
      }, false);

      me.$node.addEventListener('touchmove', function(e) {
        e.preventDefault();
        var moveX, moveY, disX, disY;

        if (e.touches.length === 1) {
          moveX = e.touches[0].clientX;
          moveY = e.touches[0].clientY;

          disX = Math.round(moveX - startX);
          disY = Math.round(moveY - startY);

          if (Math.abs(disX) + Math.abs(disY) > 0) {
            me.isMove = true;
          }
          startX = moveX;
          startY = moveY;
          // 執(zhí)行移動
          me._transformLayer(disX, disY);
        } else if (e.touches.length === 2) {
          origin = me._getOrigin({
            x: e.touches[0].clientX,
            y: e.touches[0].clientY
          }, {
            x: e.touches[1].clientX,
            y: e.touches[1].clientY
          });
          distance.stop = me._getDistance({
            x: e.touches[0].clientX,
            y: e.touches[0].clientY
          }, {
            x: e.touches[1].clientX,
            y: e.touches[1].clientY
          });

          scale = Math.ceil(distance.stop / distance.start + me.scale - 1);

          if (scale >= 2) {
            me.scale = 5;
          } else {
            me.scale = 1;
          }

          if (distance.stop - distance.start > 0) {
            // 放大
            me.scale = scale;     
            if (scale > 5) me.scale = 5;
          } else if (distance.stop - distance.start < 0) {
            // 縮小
            me.scale -= scale;
            if (scale < 5) me.scale = 1;
          }

          me.isMove = true;
          me._scaleLayer(origin, me.scale);
        }        

      }, false);

      me.$node.addEventListener('touchend', function(e) {
        e.preventDefault();
        me.isCanScale = false;
        if (me.scale === 1) {
          me._resetTransFormLayer();
        }
      }, false)
    },
    _scaleLayer: function(origin, scale) {
      var x, y;
      x = origin.x + (-origin.x) * scale;
      y = origin.y + (-origin.y) * scale;
      this.layer.style.transform = 'translate3d(' + this.layerLeft + 'px, ' + this.layerTop + 'px, 0) scale(' + scale + ')';
    },
    _transformLayer: function(disX, disY) {
      var me = this;
      // 如果正在縮放,則不進行移動
      if (me.isCanScale) true;

      if (this.layerTop > 100) {
        this.layerTop = 100;
      }

      if (me.scale === 5) {
        // doc.querySelector('.sureBtn').innerText = disY
        if (this.layerLeft >= 900 && disX > 0) {
          disX = 0;
        }

        if (this.layerLeft <= -900 && disX < 0) {
          disX = 0;
        }

        if (this.layerTop <= -1000 && disY < 0) {
          disY = 0;
        }
      }

      this.layerLeft += disX;
      this.layerTop += disY;
      // 開啟3D加速移動位置
      this.layer.style.transform = 'translate3d(' + this.layerLeft + 'px, ' + this.layerTop + 'px, 0) scale(' + me.scale + ')';
    },
    _resetTransFormLayer: function() {
      this.layer.style.transform = 'translate3d(' + this.oldLayerLeft + 'px, ' + this.oldLayerTop + 'px, 0) scale(' + this.scale + ')';
      this.layerLeft = this.oldLayerLeft;
      this.layerTop = this.oldLayerTop;
    },
    _getOrigin: function(first, second) {
      return {
        x: (first.x + second.x) / 2,
        y: (first.y + second.y) / 2
      };
    },
    _getDistance: function(start, stop) {
      return Math.sqrt(Math.pow((stop.x - start.x), 2) + Math.pow((stop.y - start.y), 2));
    }

這里監(jiān)聽容器的touchstart 家妆、touchmove 鸵荠、touchend判斷e.touches.length長度來判斷指數(shù),進行縮放或者移動的處理揩徊。

下面寫監(jiān)聽點擊了座位的事件腰鬼,并拋出外部數(shù)據(jù)

 _onTouchSeat: function () {
      var me = this;
      this.layer.addEventListener('touchend', function (e) {
        e.preventDefault();
        if (me.isMove) return;

        var target = e.target;
        var type = target.getAttribute('data-type');
        var id = target.getAttribute('data-id');
        var status = target.getAttribute('data-status');
        var index = target.getAttribute('data-index');
        var data = me.data;

        if (type && type === 'seat') {
          // 如果狀態(tài)為0, 則可以進行選擇
          if (status == 0) {
            // 檢測當前是取消還是選中
            if (target.className.indexOf('active') > -1) {
              // 取消
              target.className = target.className.replace('active', '');
              target.style.backgroundColor = '#fff';
              me._removeSelectedSeat(id, data[index], index);
            } else {
              // 選中
              target.className = target.className + ' active';
              target.style.backgroundColor = 'inherit';
              me._addSelectedSeat(id, data[index], index);
            }
          }
        }
      });
    },
    _addSelectedSeat: function(id, item, index) {
      item.index = index;
      this.selectedData.push(item);
      this._onChange();
    },
    _removeSelectedSeat: function(id, item) {
      var selectedData = this.selectedData;
      var index = 0;
      var i = 0;
      var len = selectedData.length;
      for (i; i < len; i++) {
        if (selectedData[i] === item.id) {
          index = i;
          break;
        }
      }
      selectedData.splice(index, 1);
      this._onChange();
    },
    _onChange: function() {
      var selectedData = this.selectedData;
      this.onChange(selectedData);
    }

以上基本已經(jīng)完成了座位表的功能,不過有一個缺點塑荒,不能根據(jù)指定縮放位置縮放

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熄赡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子齿税,更是在濱河造成了極大的恐慌彼硫,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凌箕,死亡現(xiàn)場離奇詭異拧篮,居然都是意外死亡,警方通過查閱死者的電腦和手機牵舱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門串绩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人芜壁,你說我怎么就攤上這事礁凡。” “怎么了慧妄?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵顷牌,是天一觀的道長。 經(jīng)常有香客問我塞淹,道長窟蓝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任饱普,我火速辦了婚禮运挫,結(jié)果婚禮上状共,老公的妹妹穿的比我還像新娘。我一直安慰自己滑臊,他們只是感情好口芍,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雇卷,像睡著了一般鬓椭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上关划,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天小染,我揣著相機與錄音,去河邊找鬼贮折。 笑死裤翩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的调榄。 我是一名探鬼主播踊赠,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼每庆!你這毒婦竟也來了筐带?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缤灵,失蹤者是張志新(化名)和其女友劉穎伦籍,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腮出,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡帖鸦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胚嘲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片作儿。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖馋劈,靈堂內(nèi)的尸體忽然破棺而出立倍,到底是詐尸還是另有隱情,我是刑警寧澤侣滩,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站变擒,受9級特大地震影響君珠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娇斑,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一策添、第九天 我趴在偏房一處隱蔽的房頂上張望材部。 院中可真熱鬧,春花似錦唯竹、人聲如沸乐导。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽物臂。三九已至,卻和暖如春产上,著一層夾襖步出監(jiān)牢的瞬間棵磷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工晋涣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仪媒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓谢鹊,卻偏偏與公主長得像算吩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佃扼,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

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

  • 《這輩子偎巢,我只寵你》 ——寫給媽媽 我曾寄居在你的血肉里 我來到這個世界時 是這輩子 你最疼痛的記憶 此后的日子里...
    sunroot閱讀 616評論 0 0
  • 姓名:巴桂成 公司:寧波大發(fā)化纖有限公司 寧波盛和塾《六項精進》235期學員 【日精進打卡第155天】 【知~學習...
    巴桂成_c6dd閱讀 194評論 0 0
  • 今天我做作業(yè)盒子的時候,爸爸幫我分析問題的時候我不聽松嘶,結(jié)果全錯了艘狭,我以后一定要虛心,不能驕傲翠订。
    韋金瀅閱讀 167評論 0 0
  • 緣知絕尽超,散落天涯官撼。 “宋維,如果從此不見似谁,你會想我嗎傲绣?” 宋維轉(zhuǎn)過頭安靜地看著宇康,“康巩踏,怎么了秃诵?” “你先回答我...
    昕圜閱讀 227評論 5 1
  • 這是李婷2018年讀書計劃的第2篇讀書筆記 這是一本什么類型的書? 這不是一本虛擬的小說塞琼,而是一本論述性的書菠净,更準...
    婷婷玉立水墨畫閱讀 606評論 0 0