• 最近实际项目中遇到的技术问题与解决思路


      距上一篇博客发布已经过去整整2个月。这两个月中发生了一些事情,比如离职,面试,入职等等,感触颇多。其实一次好的面试,即使没有成功入职也会有很多收获。

      这次面试面了三家公司,拿了两家公司的offer,但是最让我中意的面试却没拿到offer,原因是下午去面试,精神状况不太好,有点疲倦并且反应有点迟钝,导致整个面试很糟糕。不过面试官还是很nice的,给我梳理了一下头绪,拓展了一下思维,并且在后来的交流中给了我一些建议。准确的说这其实是一次成功的面试,长进很多。

      最近一个月有点懒,说着努力进步的话做着混吃等死的事。因此给自己定了一个目标,每个月保证有20天晚上坚持学习,一周至少一篇博客,完成之后给自己一个小奖励,比如一双喜欢的AJ11之类的。

      入职新公司20来天吧,跟进了一个项目,pc端的运营后台和移动端的混合开发app,算是现在项目组同时在做pc和移动端的唯一一个吧,有时候很懵逼,打开编辑器第一反应是看看这是哪一端的代码。在这两端的项目中帮同事改了几个bug。

      1.改进自己写过的一个城市选择组件

      我以前写过一篇博客《独立完成一个城市选择组件(阿里前端题目,内附知识点、思路)》,并且将这个组件的代码分享在了github上,地址是https://github.com/lunlunshiwo/ChooseCity。在这个项目中我引入了一个比较出色的插件better-scroll为我提供滚动事件,其中有一段代码是这样的:

    // 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是组件提供的事件。

      理想很丰满,现实很骨感。直到端午节放假下班回家时的一天,一个人加了我的微信,给我说了一个bug:一定几率下,从上往下点击时会出现点击了E,列表滚动到E但是悬浮卡片只显示D的情况存在,而从下往上点击时不会存在。后来也得到了证实的确几率性的存在。但是作为我第一个发到github上的作品,我希望它是完美的。因此我花了端午假期在研究问题的所在,直到前几天偶尔想到了原因。我们在触发一下类似与mousemove的事件时,理想中应该一个像素触发一次,但是因为机器的性能的原因并不会这样。 “触发”这个行为,从硬件发中断,然后OS,产生消息,这个过程中,鼠标硬件本身判断自己移动了多少距离时产生硬件信号,800dpi之类的。主板上中断芯片的处理速度也会影响。也许每个版本的系统+硬件本身,这个时间片长短都不定。而程序本身由于GetMessage函数本身消耗的时间,与捕获 鼠标移动消息(switch分支的判断) 所需要的时间也不太确定。当你鼠标移动的比较慢时,可能每一个像素触发一次。鼠标比较快时,可能发现移动了n个像素才触发一次。

      这也就导致了上面bug的产生,当从上往下点击navList时,可能滚动到E这个列表的前10个像素时触发了一次,而滚动到E列表时也就有可能因为时间太短未触发,此时位置像素值实在D的最后10个像素上,忠诚的逻辑代码也就会因为这10个像素的误差不给我返回E这个字母。那我们要做的就是在滚动完成时让列表继续产生一个滚动事件,继续滚动一个像素即可。

      幸运的是同样是上面那个滚动事件scrollToElement为我提供了一个参数

      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

     

  • 相关阅读:
    【洛谷P3853】 [TJOI2007]路标设置
    【洛谷P1159】排行榜
    【洛谷P2921】[USACO08DEC]在农场万圣节
    【洛谷P1108】低价购买
    【洛谷P1363】幻象迷宫
    【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
    【数据结构】线段树的几种用法
    【题解】洛谷P1283 平板涂色(搜索+暴力)
    【题解】洛谷P1074 [NOIP2009TG] 靶形数独(DFS+剪枝)
    【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)
  • 原文地址:https://www.cnblogs.com/lunlunshiwo/p/9222456.html
Copyright © 2020-2023  润新知