4

引言

最近做的项目已经接近尾声,刚刚发到线上,回顾和总结一下这段时间遇到的问题和个人的一些想法。

select下拉修改和复原

//部分下拉选项
 <select  v-model="offer.measureUnit"  :data-index="index" v-select-change="offer.measureUnit">
                <option v-for="option in selectList['measureUnit']" v-bind:value="option" >
                        {{option}}
                 </option>
   </select>
  <!------------------------------------------->
 //select绑定的指令部分操作
  Vue.directive('select-change', {
      update: function (el,binding) {
         var oldValue=binding.oldValue;
          var newValue=binding.value;
          if(cache.submitFlag==true){
              return;
          }
          if(validatorRules.isBlank(oldValue)||validatorRules.isBlank(newValue)||(oldValue==newValue)){
              return;
          }
          if(el.getAttribute("measureUnitFlag")!="1"){
            var index= el.dataset.index;
                  new Dialog.tip({
                     ………………xxx逻辑
                      close(){
                                   el.setAttribute('measureUnitFlag','1');
                                    vm.formData[index].measureUnit=oldValue;
                              },
                  })
          }else {
              el.setAttribute("measureUnitFlag","0");
          }
          return false;
      }
  })
    <!------------------------------------------->
    恢复按钮部分逻辑操作
               vm.formData=formDataFail;
                   Vue.nextTick(function () {
                        cache.submitFlag=false;
                  })
                   

说明 需求:点击select下拉选项,弹窗提示是否修改(select最多有200个)。实现:不适合用watch和computed,因为offer.measureUnit太多,且每个都是独立的不同的响应式属性,考虑用指令,点击恢复按钮,列表重新渲染,此时指令会全部执行一遍,因为指令是在同一个组件模板中。通过在指令中比较前后值,以及设置cache.submitFlag避免不必要更新导致的弹窗,渲染。渲染完毕,复原submitFlag,防止select下拉选项单个点时击失效;measureUnitFlag是为了防止点击同一个下拉选项时,在弹窗逻辑中点击不修改赋原值时重复弹窗情况。

知识点1 指令的原理,在vue2中是函数式组件(就是说模板->render函数),由于数据变化,导致依赖watcher-->update(),在每次组件经vdom diff,update后绑定在组件上的指令,只要组件中响应式属性有一个更新,指令全部执行一遍.
知识点2 nextTick的机制

export function queueWatcher (watcher: Watcher) {
  const id = watcher.id
  //这里保证了相同的watcher只有一个会被加入到异步队列中,
  //虽然第一个watcher会放进去,但是对dom的操作是在nextTick异步操作中,所以最终执行依赖的update方法时,取的一定是最新的data值。
  if (has[id] == null) {
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    } else {
      //对应watch里面触发watch的情况,已经刷新的话,根据watcher标识的id删除watcher
      let i = queue.length - 1
      while (i >= 0 && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(Math.max(i, index) + 1, 0, watcher)
    }
    // queue the flush
    if (!waiting) {
      waiting = true
      nextTick(flushSchedulerQueue)  //异步队列执行  将waiting和flushing都设为false
    }
  }
}
然后nextTick(flushSchedulerQueue)-->三种兼容机制实现异步处理(基于优先级顺序依次是Promise、MutationObserver、setTimeout)-->nextTickHandler()-> watcher.run()

打包问题

因为几个项目依赖一个公共目录,项目1是基于webpack1,项目2是gulp。依赖的公共目录在被import时能被打包,但是不能编译。当时没找到原因,统一改成webpack2可以了,最后做项目3时,基于vue2脚手架,出现同样问题,探索一番,找到原因,include导致能打包但是不能编译。

 {
        test: /\.js$/,
        loader: 'babel-loader',
         exclude: /node_modules/,
        // include: [resolve('src'), resolve('test')],
        options: {
          presets: [
            ['es2015']
          ]
        }
 }

数据校验

数据200条校验,在错误多时要进行大量出错样式渲染,比较卡,改成异步(基于setTimeout)单条校验渲染,同时搭配上进度条动态展示处理过程,解决以上问题。

bug

get请求在ie和360兼容模式下多次操作被缓存,接口维护之前的,之前没测出来,发到线上测试验证时发现这个问题,同事一神助攻,帮助我快速定位找到这个bug,这个bug暴露我ie下调试工具使用欠缺,指的是win7上ie调试工具,我平时也没用到过。然后解决方式可以加时间戳或者改成post请求或者后端设置禁止缓存的header。

require.ensure

require.ensure只能是用来实现按需加载,同时具有代码分割的作用,不能实现并行加载,如果要实现并行并且按顺序可以用浏览器本身的机制。webpack的require.ensure底层是通过jsonp+promise的方式,下面是我写的例子被编译后source部分截取,展示出来以便更好的说明问题。

_//1:__webpack_require__.e 加载chunk.js 异步(动态创建script)的方式,这个操作被封装成promise返回_
__webpack_require__.e/* require.ensure */(0).then((function (require) {
    console.log("begin");
    var module2 = __webpack_require__(2);
   
  }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
  
_  ---------------------------
 // 2:jsonp方式,主要功能是安装chunk_
   window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
       var moduleId, chunkId, i = 0, resolves = [], result;
       for(;i < chunkIds.length; i++) {
          chunkId = chunkIds[i];
          if(installedChunks[chunkId])
             resolves.push(installedChunks[chunkId][0]);
          installedChunks[chunkId] = 0;
       }
       
       if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
       while(resolves.length)
          resolves.shift()();  _//3:执行第一步promise的resolve方法,从而可以继续执行then当中的业务逻辑。_
  
    };

开发

合理的使用dev-server的热加载机制,优化的开发配置提升开发效率;合理的使用mixins选项,模块化拆分封装功能;利用函数式思想,封装抽象函数单元,业务相近的一组功能封装成一个模块;关键变量以及逻辑单元加上必要注释,规范的编程风格等。感悟:以后我在code时,half or one day time,先在思想中先大致走一遍,做好完善的前期项目规划-->技术选型、结构组织、难优化点、可归纳的抽象功能等等 -->A good beginning is half of success.

总结

几乎没有实现不了的视觉和交互需求,只有小部分实现起来需考虑时间成本问题。规范、TDD、性能、开发效率等等都追求完美有困难,找到一个良好的动态平衡点很重要。路漫漫其修远,吾将上下而求索。


jsdt
4.9k 声望3.9k 粉丝

make a little progress every day


« 上一篇
fp-match