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


      距上一篇博客发布已经过去整整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

     

  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/lunlunshiwo/p/9222456.html
Copyright © 2020-2023  润新知