赞
踩
在created中,页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态,DOM节点没出来,无法操作DOM节点。在mounted不会这样,比较好。
keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
其有三个参数
include
定义缓存白名单,会缓存的组件;exclude
定义缓存黑名单,不会缓存的组件;- 以上两个参数可以是逗号分隔字符串、正则表达式或一个数组,
include="a,b"
、:include="/a|b/"
、:include="['a', 'b']"
;- 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配;
max
最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉;- 不会在函数式组件中正常工作,因为它们没有缓存实例;
- 当组件在内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行。
当它们处于同一节点,
v-for
的优先级比v-if
更高,这意味着v-if
将分别重复运行于每个v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用。
- <ul>
- <li v-for="item in items" v-if="item.show">{{item}}</li>
- </ul>
如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或
<template>
)上。
- <ul v-if="items.length">
- <li v-for="item in items">{{item}}</li>
- </ul>
按Object.keys()的顺序的遍历,转成数组保证顺序。
主要看v-for渲染的是什么。
如果渲染是一个简单的列表,如不依赖子组件状态或临时DOM状态(例如:表单输入值)的列表渲染输出,不用key性能会更好,因为不用key采用的是“就地更新”的策略。如果数据项的顺序被改变, Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。
- <template>
- <div>
- <span v-for="item in lists">{{item}}</span>
- </div>
- </template>
- <script>
- export default {
- data() {
- return {
- lists: [1, 2, 3, 4, 5]
- }
- },
- }
- </script>
以上的例子,v-for的内容会生成以下的DOM节点数组,我们给每一个节点标记一个身份id,以辨别节点的位置:
- [
- '<span>1</span>', // id: A
- '<span>2</span>', // id: B
- '<span>3</span>', // id: C
- '<span>4</span>', // id: D
- '<span>5</span>' // id: E
- ]
将lists中的数据进行位置调换,变成
[2,4,3,1,5]
,在没有key的情景下,节点位置不变,但是节点的内容更新了,这就是“就地更新”
- [
- '<span>2</span>', // id: A
- '<span>4</span>', // id: B
- '<span>3</span>', // id: C
- '<span>1</span>', // id: D
- '<span>5</span>' // id: E
- ]
但是在有key的情景下,节点位置进行了交换,但是内容没有更新
- [
- '<span>2</span>', // id: B
- '<span>4</span>', // id: D
- '<span>3</span>', // id: C
- '<span>1</span>', // id: A
- '<span>5</span>' // id: E
- ]
如果渲染不是一个简单的列表,用key性能会更好一点,因为vue是采用diff算法来对比新旧虚拟节点来更新节点,在diff算法中,当新节点跟旧节点头尾交叉对比没有结果时,先处理旧节点生成一个健为key,值为节点下标index的map映射,如果新节点有key,会通过map映射找到对应的旧节点,如果新节点没有key,会采用遍历查找的方式去找到对应的旧节点,一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。
- // vue源码 src/core/vdom/patch.js 488行
- // 以下是为了阅读性进行格式化后的代码
- // oldCh 是一个旧虚拟节点数组
- // oldKeyToIdx map映射对象
- // idxInOld 对比后得到旧节点下标
- if (isUndef(oldKeyToIdx)) {
- oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
- }
- if (isDef(newStartVnode.key)) {
- // map 方式获取
- idxInOld = oldKeyToIdx[newStartVnode.key]
- } else {
- // 遍历方式获取
- idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
- }
创建map函数
- function createKeyToOldIdx(children, beginIdx, endIdx) {
- let i, key
- const map = {}
- for (i = beginIdx; i <= endIdx; ++i) {
- key = children[i].key
- if (isDef(key)) map[key] = i
- }
- return map
- }
遍历寻找函数
- // sameVnode 是对比新旧节点是否相同的函数
- function findIdxInOld(node, oldCh, start, end) {
- for (let i = start; i < end; i++) {
- const c = oldCh[i];
- if (isDef(c) && sameVnode(node, c)) return i
- }
- }
还可以强制替换元素/组件而不是重复使用它。在以下场景可以使用
- 完整地触发组件的生命周期钩子
- 触发过渡
- <transition>
- <span :key="text">{{ text }}</span>
- </transition>
当 text 发生改变时,
<span>
会随时被更新,因此会触发过渡。
不要使用对象或数组之类的非基本类型值作为key,请用字符串或数值类型的值;
不要使用数组的index作为key值,因为在删除数组某一项,index也会随之变化,导致key变化,渲染会出错。
例:在渲染
[a,b,c]
用 index 作为 key,那么在删除第二项的时候,index 就会从 0 1 2 变成 0 1(而不是 0 2),随之第三项的key变成1了,就会误把第三项删除了。
组件命名有两种方式,一种是使用链式命名my-component,一种是使用大驼峰命名MyComponent,
在字符串模板中
<my-component></my-component>
和<MyComponent></MyComponent>
都可以使用,在非字符串模板中最好使用
<MyComponent></MyComponent>
,因为要遵循W3C规范中的自定义组件名(字母全小写且必须包含一个连字符),避免和当前以及未来的 HTML 元素相冲突。
对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。
- 通过在父组件上自定义一个监听事件
<myComponent @diy="handleDiy"></myComponent>
,在子组件用this.$emit('diy',data)
来触发这个diy事件,其中data为子组件向父组件通信的数据,在父组件中监听diy个事件时,可以通过$event访问data这个值。- 通过在父组件上用修饰符
.sync
绑定一个数据<myComponent :show.sync="show"></myComponent>
,在子组件用this.$emit('update:show',data)
来改变父组件中show
的值。- 通过
v-model
。
- 递归组件时,组件调用自身使用;
- 用
is
特殊特性和component
内置组件标签时使用;keep-alive
内置组件标签中include
和exclude
属性中使用。
递归引用可以理解为组件调用自身,在开发多级菜单组件时就会用到,调用前要先设置组件的name选项, 注意一定要配合v-if使用,避免形成死循环,用element-vue组件库中NavMenu导航菜单组件开发多级菜单为例:
- <template>
- <el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
- <template slot="title">
- <Icon :type="menu.icon" v-if="menu.icon"/>
- <span>{{menu.title}}</span>
- </template>
- <template v-for="(child,i) in menu.menus">
- <side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
- <el-menu-item :index="child.id" :key="child.id" v-else>
- <Icon :type="child.icon" v-if="child.icon"/>
- <span>{{child.title}}</span>
- </el-menu-item>
- </template>
- </el-submenu>
- </template>
- <script>
- export default{
- name: 'sideMenuItem',
- props: {
- menu: {
- type: Object,
- default(){
- return {};
- }
- }
- }
- }
- </script>
$attrs
和$listeners
的使用场景?
$attrs
: 包含了父作用域中(组件标签)不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。 在创建基础组件时候经常使用,可以和组件选项inheritAttrs:false
和配合使用在组件内部标签上用v-bind="$attrs"
将非prop特性绑定上去;$listeners
: 包含了父作用域中(组件标签)的 (不含.native
) v-on 事件监听器。 在组件上监听一些特定的事件,比如focus事件时,如果组件的根元素不是表单元素的,则监听不到,那么可以用v-on="$listeners"
绑定到表单元素标签上解决。
在有使用
$on
的组件中要在beforeDestroy
钩子函数中用$off
销毁。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。