最近實際項目中遇到的技術問題與解決思路 獨立完成一個城市選擇組件(阿里前端題目,內附知識點、思路)

  距上一篇博客發佈已通過去整整2個月。這兩個月中發生了一些事情,好比離職,面試,入職等等,感觸頗多。其實一次好的面試,即便沒有成功入職也會有不少收穫。html

  此次面試面了三家公司,拿了兩家公司的offer,可是最讓我中意的面試卻沒拿到offer,緣由是下午去面試,精神情況不太好,有點疲倦而且反應有點遲鈍,致使整個面試很糟糕。不過面試官仍是很nice的,給我梳理了一下頭緒,拓展了一下思惟,而且在後來的交流中給了我一些建議。準確的說這實際上是一次成功的面試,長進不少。前端

  最近一個月有點懶,說着努力進步的話作着混吃等死的事。所以給本身定了一個目標,每月保證有20天晚上堅持學習,一週至少一篇博客,完成以後給本身一個小獎勵,好比一雙喜歡的AJ11之類的。vue

  入職新公司20來天吧,跟進了一個項目,pc端的運營後臺和移動端的混合開發app,算是如今項目組同時在作pc和移動端的惟一一個吧,有時候很懵逼,打開編輯器第一反應是看看這是哪一端的代碼。在這兩端的項目中幫同事改了幾個bug。git

  1.改進本身寫過的一個城市選擇組件

  我之前寫過一篇博客《獨立完成一個城市選擇組件(阿里前端題目,內附知識點、思路)》,而且將這個組件的代碼分享在了github上,地址是https://github.com/lunlunshiwo/ChooseCity。在這個項目中我引入了一個比較出色的插件better-scroll爲我提供滾動事件,其中有一段代碼是這樣的:github

// pos爲位置參數
this.scroll.on('scroll', (pos) => {
   this.$emit('distance', Math.abs(pos.y))
   this.$emit('scrollStore', true)
})

  上面這段代碼個人用意是觸發滾動事件時應該向我返回滾動的位置,我在下面這段代碼中用到了這個pos.y這個變量爲個人組件在滾動時提供一個指示,好比點擊右邊的navList的A時,城市列表會滾動到A處,此時會有一個懸浮的卡片展現A。面試

    // 滾動到相應的dom節點
    singleLetter (dom) {
      this.$refs.suggest.scrollToElement(dom, 200, false, false)
    },
    // 根據滑動距離顯示字母牌上的字
    distance (val) {
      for (let i = 0, len = this.arrHeight.length; i < len; i++) {
        if (val < this.arrHeight[i]) {
          this.flagText = this.cityIndexList[i]
          return false
        }
      }
    }

  以上爲之前的代碼,scrollToElement是組件提供的事件。vuex

  理想很豐滿,現實很骨感。直到端午節放假下班回家時的一天,一我的加了個人微信,給我說了一個bug:必定概率下,從上往下點擊時會出現點擊了E,列表滾動到E可是懸浮卡片只顯示D的狀況存在,而從下往上點擊時不會存在。後來也獲得了證明的確概率性的存在。可是做爲我第一個發到github上的做品,我但願它是完美的。所以我花了端午假期在研究問題的所在,直到前幾天偶爾想到了緣由。咱們在觸發一下相似與mousemove的事件時,理想中應該一個像素觸發一次,可是由於機器的性能的緣由並不會這樣。 「觸發」這個行爲,從硬件發中斷,而後OS,產生消息,這個過程當中,鼠標硬件自己判斷本身移動了多少距離時產生硬件信號,800dpi之類的。主板上中斷芯片的處理速度也會影響。也許每一個版本的系統+硬件自己,這個時間片長短都不定。而程序自己因爲GetMessage函數自己消耗的時間,與捕獲 鼠標移動消息(switch分支的判斷) 所須要的時間也不太肯定。當你鼠標移動的比較慢時,可能每個像素觸發一次。鼠標比較快時,可能發現移動了n個像素才觸發一次。微信

  這也就致使了上面bug的產生,當從上往下點擊navList時,可能滾動到E這個列表的前10個像素時觸發了一次,而滾動到E列表時也就有可能由於時間過短未觸發,此時位置像素值實在D的最後10個像素上,忠誠的邏輯代碼也就會由於這10個像素的偏差不給我返回E這個字母。那咱們要作的就是在滾動完成時讓列表繼續產生一個滾動事件,繼續滾動一個像素便可。app

  幸運的是一樣是上面那個滾動事件scrollToElement爲我提供了一個參數dom

  scrollToElement(el, time, offsetX, offsetY, easing)

  • 參數:返回值:無
    • {DOM | String} el 滾動到的目標元素, 若是是字符串,則內部會嘗試調用 querySelector 轉換成 DOM 對象。
    • {Number} time 滾動動畫執行的時長(單位 ms)
    • {Number | Boolean} offsetX 相對於目標元素的橫軸偏移量,若是設置爲 true,則滾到目標元素的中心位置
    • {Number | Boolean} offsetY 相對於目標元素的縱軸偏移量,若是設置爲 true,則滾到目標元素的中心位置
    • {Object} easing 緩動函數,通常不建議修改,若是想修改,參考源碼中的 ease.js 裏的寫法
  • 做用:滾動到指定的目標元素。

  咱們能夠將上面的函數改成:

    // 滾動到相應的dom節點
    singleLetter (dom) {
      this.$refs.suggest.scrollToElement(dom, 200, false, 1)
    } 

  滾動到相關dom節點後繼續向下滾動一個像素,再次觸發一次滾動事件,解決。

  相關代碼已更新,請放心使用,https://github.com/lunlunshiwo/ChooseCity,求個star。

  2.vue2.0s中eventBus的綁定與解綁

  在移動端項目中,有兩個頁面共用了一個我封裝的列表組件,而且這兩個頁面都會有一個上拉獲取更多的功能,所以,我作這個組件時使用eventBus做爲兄弟組件傳值的轉接站。當頁面滾動至底部而且觸發上拉事件時向列表組件傳遞一個事件,在列表頁面綁定一個獲取更多的事件,並觸發。代碼以下:

//滾動組件
pullup(event) {  
   Bus.$emit('getMore');   
} 

//列表組件
created() {  
   Bus.$on('getMore', this.getMoreList);  
},
methods: {  
   getMoreList() { 
    //
    // 
    //
   }  
}   

  很不幸的是,這兩個列表組件我共用了一個組件,致使了下面這個問題:當這兩個列表切換幾回以後,上拉刷新時會觸發屢次getMoreList事件,而且切換多少次就會出發多少次。百思不得騎姐以後我想到Bus.$on('getMore', this.getMoreList)比較相似原生Js的事件監聽:

//僞代碼
相關列表組件.addEventListener("getMore",getMoreList);
function getMoreList(){
 alert("hello world!");
}

  在上述的問題中,假如事件getMore與組件中的getMoreList綁定,即便組件銷燬了,可是這個綁定關係仍是存在的。等再次渲染組件時,created生命週期又會綁定一次事件,而且之前的綁定關係仍是存在的,如今組件中有兩個綁定關係,並且相同。所以,在組件銷燬時,咱們應清除組件中的這個綁定關係:

destroyed() {  
   Bus.$off('getMore', this.getMoreList);  
}

  3.路由前進後退時的切換動態

  打開手機app頁面,當頁面前進時,切換效果通常爲從右向左滑動。當後退時,咱們會但願他是從左向右退出的,可是vue提供的過渡效果只容許咱們有一種的效果的存在,除非根據路由的切換來改變過渡效果綁定的name值。在實現這個效果的時候,我對原有的方法進行改進。我首先想到改寫router.back()這個事件,可是由於以爲這樣不太好,所以對這個進行了一層封裝:

//router文件
Router.prototype.goBack = function () {
  store.commit("changeIsBack",true)
  this.back(-1)
}
//vuex文件
const state = {
  isBack:false
}
const mutations = {
  changeIsBack(state, flag) {
    state.isBack = flag
  }
}
export default {
  state,
  mutations
}

  這個封裝中的this.back(-1)就是this.$router.back(-1)。在router中引入vuex的store文件,使用commit改變state的值。

//pageMain.vue文件
methods: {
    ...mapMutations([
      'changeIsBack'
    ])
}
beforeRouteUpdate (to, from, next) {
    let isBack = this.$store.state.routerState.isBack
    if (isBack) {
      this.transitionName = 'enter-right'
    } else {
      this.transitionName = 'enter-left'
    }
    this.changeIsBack(false)
    next()
}
//其他單頁返回上一級
this.$router.goback()

  在頁面展現頁使用beforeRouteUpdate這個鉤子函數檢測store中isBack的值。當頁面返回時調用this.$router.goback()這個方法,此時會改變store中isBack的值。當路由更新時,檢測isBack是否爲true,若是是則爲返回的頁面,此時更新過渡transition的name,達到更新的目的。方案地址:https://github.com/lunlunshiwo/pageChange

 

  以上就是最近遇到的問題與改進解決思路。

  當初由於以爲很酷炫選擇了這條路,就要好好地走下去,晚安。

  掘金地址:https://juejin.im/post/5b304c65f265da59702de4c8

 

 

相關文章
相關標籤/搜索