最近有空,心血来潮想着再去把 vue 文档给读一遍,记一下收获
1、避免 v-if
和 v-for
用在一起
这里的问题以前完全没有注意过,导致经常写 iview 出现这一类的代码
<Select>
<Option v-for="(item, index) in menuList" v-if="item.isUsed" :key="index">{{item.name}}<Option>
</Select>
原因:
v-for 的优先级 比 v-if 要高,导致 渲染的时候,先执行了 v-for ,后执行了 v-if ,这是一个完全没有必要的 开销
以上还有一个问题:
:key="index"
key 属性实际上是用来 diff 的时候,看能不能复用 节点的。
在diff 的时候,他会先查看 key 属性有没有一样的,一样的就拿过来复用,减少开销。
所以尽量使用类似于 id 之类独一无二,又不像index 这一类毫无意义的 key
======
2020.04.09 补充
深入了解了 vue diff 之后(勉强算深入了解吧) 发现 类似于 这种重复性很高的模块上的时候,类似于 上文的 Option,尤其是 分页的表单之类的
key 直接使用 index 说不定渲染速度会 更快一点
2、slot-scope 和 #default="{}"
相信不少同学对这个是比较陌生的,也有同学是比较了解的,
但是在iview 开发文档中,Table 中 提供了这个属性,相当好用,不需要再 render 了 iview 更新日志
所以我特地关注了一下这个, 具名插槽 slot-scope
文档给出的demo:
<Table :data="tableDate" :columns="columnContract" >
<template slot-scope="{ row }" slot="contractNo">
<MyToolTip :words="row.contractNo" :maxLength="20"></MyToolTip>
</template>
</Table>
vue 淘汰了上面的使用方法,: 新版用法
<Table :data="tableDate" :columns="columnContract">
<!-- 这里 使用了结构 -->
<template #contractNo="{ row }">
<MyToolTip :words="row.contractNo" :maxLength="20"></MyToolTip>
</template>
</Table>
slot-scope="{ row }" slot="contractNo"
完全可以使用
#contractNo="{ row }"
来代替
#表示 v-slot: 后面的 contractNo 就是 slot name,注意 ,如果是default的话,一定要写 #default=""
3、监听生命周期
所以说,人丑多读书(*/ω\*),我看了这个之后,发现自己以前写的代码都是辣鸡
场景:有一个页面,进入之后就设计了一个定时器,每5秒 去请求一次数据,在离开的时候,需要clear 这个定时器
beforeDestroy () {
clearInterval(this.time);
},
看起来完全没问题,但是 程序化的事件侦听器
- 它需要在这个组件实例中保存这个
picker
,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。 - 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。
所以可以有更好的
mounted: function () {
在mounted 创建 定时器
var time = new setInterval(fn, 5000)
监听 beforeDestory 事件,然后清除定时器
this.$once('hook:beforeDestroy', function () {
clearInterval(time)
})
}
至于为什么监听的是 'hook:beforeDestroy' ,这个 hook: 又是哪里来的,我看了一下 vue 的源码
function callHook (vm, hook) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget();
var handlers = vm.$options[hook];
var info = hook + " hook";
if (handlers) {
for (var i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, null, vm, info);
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook);
}
popTarget();
}
vue 中, 直接 vm.$emit('hook:' + hook);
4、事件修饰符 .passive
说实话,看到这个我是有点不知所措地,可能以前完全没有注意到,我竟然不知道这个属性是什么意思,
查了之后,发现是 addEventListener 的 第三个参数对象中的一个 具体的可以对应的 文档
举个栗子,你在移动端使用原生的滚动的时候,如果addEventListener 监听了实际上刚刚开始 是有200ms 的停顿的,
因为他不知道你是否会 preventDefault(),所以会先执行你addEventListener,然后再原生的滚动,即使你放进去的代码是自定义的空函数 ,依旧会有这样的一个延迟
而这个属性就是为了告诉浏览器,我没有执行preventDefault(),你放心地先滚起来把
注意,passive 和 preventDefault() 放一起会无视 preventDefault() 并向你扔一个错误
5、动态+异步 组件
这个其实没什么好像,就是单纯的记一下 链接
<component :is="currentComponent" ></component>
import LoadingComponent from "./components/LoadingComponent.vue";
import ErrorComponent from "./components/ErrorComponent.vue";
------
components: {
'componentA': () => ({
component: import('./components/componentA.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
}),
'componentB': () => ({
component: import('./components/componentB.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
})
},
computed: {
currentComponent: function () {
return 'component' + this.AB;
}
},