Vue踩坑實(shí)錄(二)

在上一篇中說(shuō)了一下踩過(guò)的前三個(gè)坑杭抠,剩下的坑就在這篇中全部搞定吧蚌父。
Vue踩坑實(shí)錄(一)


  1. Vue-cli .js?.Vue?
  2. 父組件向子組件傳值
  3. eslint format
  4. Vue中使用SCSS
  5. class綁定與順序
  6. v-for 子組件DOM的取得
  7. 子組件向父組件的傳遞
  8. 數(shù)組的更新方法

Vue中使用SCSS

目前流行的CSS預(yù)出處理大大減少了書(shū)寫(xiě)CSS的不便性姿现,自然這些在Vue中也是可以使用的冰单。
Vue中使用SCSS的方法十分簡(jiǎn)單纹腌,只要在style標(biāo)簽添加lang="scss"即可霎终。

<style lang="scss">
.picture-continer {
  width: 320px;
  height: 360px;
  margin: auto;
  padding: 40px 40px 0px 40px;
  box-sizing: border-box;
  border-radius: 1px;
  background-color: #fff;
  position: absolute;
  cursor: pointer;
  transform-style: preserve-3d;
  transform-origin: 0 50% 0; // 改變變化的原點(diǎn)為x軸原點(diǎn)
  transition: left .8s ease-in-out, top .8s ease-in-out, transform .5s;
  perspective: 1800px;
  h2 {
    height: 80px;
    margin: 0;
    line-height: 80px;
    color: #727272;
    text-align: center;
    font-size: 16px;
  }
}
</style>

class綁定與順序

在畫(huà)廊應(yīng)用中對(duì)于圖片翻轉(zhuǎn)的樣式是通過(guò)CSS來(lái)控制,這一點(diǎn)通過(guò)使用Vue的class綁定可以很方便的完成升薯。與React不同莱褒,連判斷語(yǔ)句都不需要。

<template>
  <figure class="picture-continer"
          :style="{top: imgPos.position.top + 'px', left: imgPos.position.left + 'px',  transform:'rotate(' + this.imgPos.rotate + 'deg)'}"
          :class="{'is-center':imgPos.isCenter,'is-inverse':imgPos.isInverse}"  // 綁定class涎劈,通過(guò)判斷class開(kāi)控制圖片樣式的顯示
          @click.stop="pictureAction">
    <img :src="picture.src"
         :alt="picture.title" />
    <h2 class="img-title">{{picture.title}}</h2>
    <div class="img-back">
      <p>{{picture.desc}}</p>
    </div>
  </figure>
</template>

因此广凸,在這里就需要注意。如果上面例子中的isCenterisInverse同時(shí)都為true的時(shí)候蛛枚,此時(shí)添加在標(biāo)簽中class的順序是與書(shū)寫(xiě)順序相同的谅海。
當(dāng)兩個(gè)class中有重復(fù)或者沖突的屬性的時(shí)候,就要根據(jù)CSS的后書(shū)寫(xiě)的屬性生效的規(guī)則來(lái)設(shè)計(jì)class的書(shū)寫(xiě)順序蹦浦。
如果在這邊順序?qū)φ{(diào)的話扭吁,那么is-inverse是不會(huì)生效的。即頁(yè)面上的圖片不會(huì)翻轉(zhuǎn)盲镶。

.is-center {
  transform: rotate(0deg);
  z-index: 11;
}

.is-inverse {
  transform: translate(320px) rotateY(180deg);
}

v-for 子組件DOM的取得

Vue中提供了v-for指令能很方便的循環(huán)標(biāo)簽智末。在這次的應(yīng)用中,圖片和導(dǎo)航條都是通過(guò)循環(huán)單個(gè)組件生成的徒河。

<template>
  <div id="container"
       class="stage">
    <!-- 圖片區(qū)域 -->
    <section class="img-sec">
      <picture v-for="(picture, index) in pictureList"
               :key="index"
               :index="index"
               :picture="picture"
               :img-pos="imgArrangeList[index]"
               ref="pictureList"></picture>
    </section>
    <!-- 導(dǎo)航條區(qū)域 -->
    <section class="nav-sec">
      <navbar v-for="(picture, index) in pictureList"
              :key="index"
              :index="index"
              :img-pos="imgArrangeList[index]"></navbar>
    </section>
  </div>
</template>

雖然說(shuō)Vue主要通過(guò)數(shù)據(jù)驅(qū)動(dòng)的方式來(lái)進(jìn)行操作,不過(guò)還是會(huì)遇上要直接操作DOM的時(shí)候送漠。
這個(gè)時(shí)候可以通過(guò)this.$el來(lái)獲取DOM的實(shí)體元素顽照。
對(duì)于子組件來(lái)說(shuō),可以在mounted方法中獲取闽寡。

methods: {
    setStageSize: function (sizeObj) {
      var stage = this.$el; // 這里獲取實(shí)體DOM
      stage.style.width = sizeObj.width + 'px';
      stage.style.height = sizeObj.height + 'px';
    },
    // 省略一些代碼
    mounted() {
        this.pictureList = imgList;
        this.initImgArrangeList(this.pictureList);
        this.setStageSize(stageOpt); // 這個(gè)方法用到了實(shí)體DOM元素
        // 省略一些代碼
      },
    // 省略一些代碼
}

注意點(diǎn):
其實(shí)如果按照React那一版(請(qǐng)參照React 圖片畫(huà)廊 踩坑筆記)對(duì)于圖片組件大小的設(shè)定代兵,實(shí)際上是通過(guò)element.scrollWidthelement.scrollHeight的方式來(lái)設(shè)定的。由于React中爷狈,這些是寫(xiě)在render函數(shù)中的植影,因此可以通過(guò)ReactDOM.find()的方法來(lái)獲取。
而在Vue中涎永,如果采用類似的方法思币,在mounted或者updated$nextTick方法中來(lái)獲取DOM元素來(lái)進(jìn)行設(shè)定的話鹿响,會(huì)造成死循環(huán)。
對(duì)此的情況谷饿,應(yīng)該是Vue在對(duì)子組件進(jìn)行渲染前需要獲取到實(shí)體DOM惶我,而此時(shí)實(shí)體DOM并沒(méi)有生成,因此造成死循環(huán)博投。(個(gè)人的理解绸贡,有錯(cuò)誤的地方還望指正)
所以最后的解決方法是修改數(shù)據(jù)結(jié)構(gòu),添加了圖片組件的寬高信息毅哗,使得Vue在渲染前就能獲取到從而成功渲染听怕。(其實(shí)本來(lái)在CSS中也是寫(xiě)死的寬高)


子組件向父組件的傳遞

在上一篇中提到了Vue通過(guò)props屬性來(lái)向子組件傳值。自然子組件也需要通過(guò)一定的方法向父組件進(jìn)行通信虑绵。在React中尿瞭,通過(guò)向子組件傳入一個(gè)回調(diào)函數(shù)的方法(即子組件實(shí)際調(diào)用的仍是父組件的方法)來(lái)解決這個(gè)問(wèn)題。

    // 省略代碼
    // 利用rearrange函數(shù)
    // 讓被點(diǎn)擊的圖片劇中
    center(index) {
      return function() {
        this.rearrange(index);
      }.bind(this);
    }
    // 省略代碼
    // 向子組件傳遞事件
    // 省略代碼
    PictureList.push( < Picture imgData = {imgData} key = {index} imgPos = {this.state.imgArrangeList[index]}
            inverse = {this.inverse(index)}  
            center = {this.center(index)} // 往子組件中傳遞 center 事件
            ref = {'imgData' + index} />);
    // 省略代碼

在子組件中通過(guò)this.props.center()來(lái)調(diào)用蒸殿。

    // 省略代碼
        // 點(diǎn)擊函數(shù)
    handleClick = (event) => {
        if (this.props.imgPos.isCenter) {
            this.props.inverse();
        } else {
            this.props.center();
        }
        event.stopPropagation();
        event.preventDefault();
    }
    // 省略代碼

而在Vue中通過(guò)使用EventBus來(lái)進(jìn)行事件的傳遞筷厘,類似于設(shè)計(jì)模式中的觀察者模式。其中EventBus就是一個(gè)全局的Vue實(shí)例宏所,在子組件中通過(guò)$emit方法進(jìn)行事件的發(fā)射酥艳,而在父組件中通過(guò)v-on進(jìn)行事件綁定。
子組件中通過(guò)emit進(jìn)行的事件設(shè)定爬骤。

// 省略代碼
pictureAction: function () {
      if (this.$props.imgPos.isCenter) {
        // 通過(guò)$emit 來(lái)設(shè)置事件充石,可以傳入對(duì)應(yīng)的參數(shù)
        bus.$emit('refresh-pic', this.$props.index);
      } else {
        bus.$emit('do-rearrange', this.$props.index);
      }
    }
// 省略代碼

父組件通過(guò)v-on進(jìn)行事件的響應(yīng)。

// 省略代碼
  mounted() {
    this.pictureList = imgList;
    this.initImgArrangeList(this.pictureList);
    this.setStageSize(stageOpt);
    this.setAreaPosition();
    this.rearrange(0);
    this.$nextTick(function () {
      // 監(jiān)聽(tīng)子組件傳來(lái)的事件
      bus.$on('do-rearrange', this.doRearrange);
      bus.$on('refresh-pic', this.refreshPic);
    });
  },
// 省略代碼

可以看出霞玄,無(wú)論Vue還是React骤铃,子組件實(shí)際上最后調(diào)用的還是父組件中的方法。
只不過(guò)在閱讀層面上坷剧,Vue的觀察者模式更容易讀懂一點(diǎn)惰爬。不過(guò)這種通過(guò)EventBus的方法,只適用與小型的程序惫企,當(dāng)項(xiàng)目比較復(fù)雜時(shí)撕瞧,還是應(yīng)該使用Vuex來(lái)進(jìn)行狀態(tài)管理。


數(shù)組的更新方法

Vue最大的特色是數(shù)據(jù)的雙重綁定狞尔。其中對(duì)于數(shù)組丛版,在官方文檔中給出了相關(guān)的注意事項(xiàng)。特別要注意下面的情況偏序,因?yàn)樵跀?shù)組操作中页畦,這樣的用法是最方便也是最容易想到的。

由于 JavaScript 的限制研儒, Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:
當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí)豫缨,例如: vm.items[indexOfItem] = newValue
當(dāng)你修改數(shù)組的長(zhǎng)度時(shí)独令,例如: vm.items.length = newLengt

自然,這一次從React轉(zhuǎn)到Vue的過(guò)程中也遇到了這個(gè)問(wèn)題州胳。并且還是在最關(guān)鍵的圖片重排函數(shù)中记焊。
React版本

// 省略代碼
    // 重新布局所有圖片 centerIndex 是居中圖片的索引
    rearrange(centerIndex) {

      let imgArrangeList = this.state.imgArrangeList;

      let AreaPos = this.AreaPos;

      let center = AreaPos.center;

      let hPosRangeLeftRange = AreaPos.hPosRange.leftRange;
      let hPosRangeRightRange = AreaPos.hPosRange.rightRange;
      let hPosRangeTop = AreaPos.hPosRange.top;
      let vPosRangeX = AreaPos.vPosRange.x;
      let vPosRangeTopRange = AreaPos.vPosRange.topRange;

      let imgTopArray = [];
      let topImgNumber = Math.floor(Math.random() * 2); // 取上測(cè)區(qū)域的圖片數(shù)量

      // 取得居中圖片
      let centerImgArray = imgArrangeList.splice(centerIndex, 1);
      centerImgArray[0].position = center;
      centerImgArray[0].rotate = 0; // 中間圖片不需要旋轉(zhuǎn)
      centerImgArray[0].isCenter = true;

      // 取出上側(cè)圖片的信息
      let topImgSpliceIndex = Math.floor(Math.random() * (imgArrangeList.length - topImgNumber));
      imgTopArray = imgArrangeList.splice(topImgSpliceIndex, topImgNumber);
      // 布局上側(cè)圖片
      imgTopArray.forEach(function(img) {
        img.position = {
          left: getRandomValue(vPosRangeX[0], vPosRangeX[1]),
          top: getRandomValue(vPosRangeTopRange[0], vPosRangeTopRange[1])
        }
        img.rotate = getRandomRange();
        img.isCenter = false;
      });

      // 布局左右兩側(cè)圖片
      for(let i = 0, len = imgArrangeList.length, k = len / 2; i < len; i++) {

        let hPosRangeTmp = null;
        // 取布局的隨機(jī)值
        if(i < k) {
          hPosRangeTmp = hPosRangeLeftRange;
        } else {
          hPosRangeTmp = hPosRangeRightRange;
        }
        
       // 這一部分在Vue中是不會(huì)進(jìn)行數(shù)據(jù)更新的因此需要做轉(zhuǎn)換
        imgArrangeList[i].position = {
          left: getRandomValue(hPosRangeTmp[0], hPosRangeTmp[1]),
          top: getRandomValue(hPosRangeTop[0], hPosRangeTop[1])
        }
        imgArrangeList[i].rotate = getRandomRange();
        imgArrangeList[i].isCenter = false;
      }

      // 重新合成數(shù)組
      if(imgArrangeList && imgTopArray[0]) {
        imgArrangeList.splice(topImgSpliceIndex, 0, imgTopArray[0]);
      }

      imgArrangeList.splice(centerIndex, 0, centerImgArray[0]);

      this.setState({
        imgArrangeList: imgArrangeList
      });
    }
// 省略代碼

Vue版本

// 省略代碼
    rearrange: function (centerIndex) {
     // 省略代碼
      // 布局左右兩側(cè)圖片
      for (let i = 0, len = imgArrangeList.length, k = len / 2; i < len; i++) {
        // 設(shè)置一個(gè)臨時(shí)變量,其結(jié)構(gòu)與每一個(gè) imgArrangeList[i]相同
        let tmpItem = {};
        let hPosRangeTmp = null;
        // 取布局的隨機(jī)值
        if (i < k) {
          hPosRangeTmp = hPosRangeLeftRange;
        } else {
          hPosRangeTmp = hPosRangeRightRange;
        }
        // 將原來(lái)的方法用Vue中對(duì)應(yīng)的數(shù)組更新方法替代栓撞,為此需要設(shè)置一個(gè)臨時(shí)對(duì)象
        // 然后通過(guò)Vue給出的方法進(jìn)行實(shí)現(xiàn)
        // imgArrangeList[i].position = {
        //   left: getRandomValue(hPosRangeTmp[0], hPosRangeTmp[1]),
        //   top: getRandomValue(hPosRangeTop[0], hPosRangeTop[1])
        // }
        // imgArrangeList[i].rotate = getRandomRange();
        // imgArrangeList[i].isCenter = false;
        tmpItem = {
          position: {
            left: getRandomValue(hPosRangeTmp[0], hPosRangeTmp[1]),
            top: getRandomValue(hPosRangeTop[0], hPosRangeTop[1])
          },
          rotate: getRandomRange(),
          isCenter: false,
          isInverse: imgArrangeList[i].isInverse
        };

        this.$set(imgArrangeList, i, tmpItem);
      }

      //省略代碼
    },
// 省略代碼

至于上部和中間的圖片由于本來(lái)就是通過(guò)splice方法進(jìn)行設(shè)定的遍膜,因此可以在Vue中進(jìn)行正常的更新。同時(shí)也是因此發(fā)現(xiàn)了上面的問(wèn)題的瓤湘。


后記

對(duì)于這個(gè)項(xiàng)目瓢颅,從代碼量上來(lái)說(shuō),Vue和React差距并不大弛说。不過(guò)由于.Vue文件分布相對(duì)清晰一點(diǎn)挽懦,在代碼閱讀方面還是比較容易讀懂的。
此外木人,React和Vue在設(shè)計(jì)思考的角度上信柿,其實(shí)差別還是蠻大的。React在感覺(jué)上更貼合我們一直以來(lái)的開(kāi)發(fā)思路醒第,上手React還是一件比較輕松容易的事情渔嚷。而Vue則是通過(guò)數(shù)據(jù)來(lái)進(jìn)行驅(qū)動(dòng),一切都要以數(shù)據(jù)為重稠曼。剛開(kāi)始的時(shí)候形病,還是挺不習(xí)慣的。不過(guò)在踩過(guò)幾個(gè)坑之后也漸漸開(kāi)始接受起了這種思考方式霞幅。

這一次Vue的踩坑開(kāi)始很愉快的漠吻。之后大概會(huì)學(xué)習(xí)一下全家桶中的Vuex和Vue-router吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末司恳,一起剝皮案震驚了整個(gè)濱河市途乃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扔傅,老刑警劉巖欺劳,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铅鲤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)枫弟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)邢享,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人淡诗,你說(shuō)我怎么就攤上這事骇塘∫谅模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵款违,是天一觀的道長(zhǎng)唐瀑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)插爹,這世上最難降的妖魔是什么哄辣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮赠尾,結(jié)果婚禮上力穗,老公的妹妹穿的比我還像新娘。我一直安慰自己气嫁,他們只是感情好当窗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寸宵,像睡著了一般崖面。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梯影,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天巫员,我揣著相機(jī)與錄音,去河邊找鬼光酣。 笑死疏遏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的救军。 我是一名探鬼主播财异,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼唱遭!你這毒婦竟也來(lái)了戳寸?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拷泽,失蹤者是張志新(化名)和其女友劉穎疫鹊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體司致,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拆吆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脂矫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枣耀。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庭再,靈堂內(nèi)的尸體忽然破棺而出捞奕,到底是詐尸還是另有隱情牺堰,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布颅围,位于F島的核電站伟葫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏院促。R本人自食惡果不足惜筏养,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望一疯。 院中可真熱鬧撼玄,春花似錦、人聲如沸墩邀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)眉睹。三九已至荔茬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竹海,已是汗流浹背慕蔚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斋配,地道東北人孔飒。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像艰争,于是被迫代替她去往敵國(guó)和親坏瞄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • 苗青有點(diǎn)不相信自己的耳朵甩卓,無(wú)論從身體的高度還是寬度鸠匀,春生都是略輸一籌,但就是在這并不出眾的體內(nèi)逾柿,竟然蘊(yùn)藏著如此巨大...
    西嶺布衣閱讀 255評(píng)論 0 3
  • 幾分鐘前缀棍,母親發(fā)來(lái)視頻,說(shuō)是想看寶寶机错,平常說(shuō)寶寶睡了便不再堅(jiān)持爬范,今日卻是還想看看,后來(lái)才說(shuō)鄰居陳叔叔過(guò)世了弱匪,說(shuō)這話...
    瀟瀟成謎閱讀 91評(píng)論 0 0
  • 據(jù)說(shuō),現(xiàn)代鐵路兩條鐵軌之間的標(biāo)準(zhǔn)距離是四英尺又八點(diǎn)五英寸狱窘。 那依據(jù)是什么呢?來(lái)由絕對(duì)顛覆你的認(rèn)知财搁。 因?yàn)樵缙诘蔫F路...
    周愚閱讀 1,441評(píng)論 0 0