引言
最近做的项目已经接近尾声,刚刚发到线上,回顾和总结一下这段时间遇到的问题和个人的一些想法。
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、性能、开发效率等等都追求完美有困难,找到一个良好的动态平衡点很重要。路漫漫其修远,吾将上下而求索。