Vue

MVVM框架

  • Model层关注数据处理,从服务端获取数据
  • View层渲染页面
  • VM连接view层和model层,通过数据响应式来监听数据更改,以触发视图更新。通过双向绑定来同步视图和数据。让我们不需要过多关注dom操作,更专注于业务逻辑。同时用jQuery的话会觉得这2者在写的时候方式很不同

组件化思想

每个组件都是一个Vue实例,由Vue组件去拼装成页面。每个组件可以包含自己的数据、视图、逻辑

1. 刷新页面的几种方式

  • this.$foreceUpdate()
  • location.reload()
  • this.$router.go(0)
  • 用变量控制组件是否渲染(v-if),要刷新时先将变量置为false,再在$nextTick里面置为true

2. computed和watch

2.1 computed - 计算属性

有缓存,不支持异步

① 有缓存什么意思?
当视图更新的时候,写在模板里的方法调用或者表达式都会重新执行,但如果使用的是computed计算出的值,只有它依赖的值发生改变时才会重新计算

② 怎么实现的缓存?
在依赖的值发生改变以后,计算属性的watcher的dirty属性会置为true,只有dirty为true才会重新计算结果,计算完之后又会置为false。

③ 自动计算的属性,是否支持主动修改?
可以。我们定义的函数实际上定义的是这个值的get函数,如果需要修改,还需要定义set。(但不建议这么做)

④ watch有深度监听,为什么computed没有deep: true?
因为computed依赖的值是确定的,用到了谁就把谁加入依赖。
而watch是指定的,需要用deep来区分是监听“指向修改”还是“任意修改”

2.2 watch - 数据监听

支持异步

① 为什么deep设置true能设置深度监听?
默认情况下,Object.defineProperty就是只能监听到对象指向的变化。如果需要监听内部属性,则指定deep为true,以让Vue对这个对象进行深度遍历,给每个属性都加上监听器

3. $nextTick

① 为什么需要$nextTick?
当数据修改驱动视图更新,我们立即想要操作更新后的dom,此时无法立即获取到更新后的视图,需要使用 this.$nextTick(() => {})。因为视图更新是异步的,$nextTick的回调会在视图更新之后尽快执行。

② 为什么vue是异步渲染的?
为了性能,否则每次数据修改都要重新渲染,所以一轮数据修改完后再渲染,减少渲染次数

4. keep-alive

它能够把不活动的组件实例保存在内存中,而不是直接将其销毁

① 为什么组件需要缓存?
主要是想在组件切换时能保持上一次的状态,使用<keep-alive></keep-alive>,使组件被缓存在内存中,防止重复渲染,减少加载时间,重新激活时能保持上次状态

② 如何实现的缓存?
vm.$vnode.parent.componentInstance.cache

image.png
image.png
image.png

③ 用v-show也能保持上次状态,为什么不用v-show?
因为v-show一开始为false的时候也会进行渲染

④ 如果遇到二级路由

5. diff算法

① 虚拟节点
用对象的方式来描述真实dom的结构和内容

vNode = {
    tag: 'div',
    attrs: {
        id: 'app',
    },
    children: [
        { tag: 'h2' }
    ]
}
image.png

② 虚拟dom怎么创建为真实dom?

// 极度简易版-噗
function createNode(vnode) {
    if (typeof vnode === 'number') {
        vnode = String(vnode);
    }
    if (typeof vnode === 'string') {
        return document.createTextNode(vnode);
    }
    // 创建
    const n = document.createElement(vnode.tag); 

    // 设置属性
    if (vnode.attrs) {
        let attrs = vnode.attrs;
        for (let attr in attrs) {
            n.setAttribute(attr, attrs[attr]);
        }
    }

    // 添加子元素
    if (Array.isArray(vnode.children)) {
        vnode.children.forEach(childNode => {
            n.appendChild(createNode(childNode));
        });
    }
    return n;
}

③ diff 算法
三棵树:旧的虚拟dom树、新的虚拟dom树、实际的dom树。
数据更新需要重新渲染视图时,为了最小范围更新dom,需要把新生成的虚拟dom和原虚拟dom对象进行比较,计算出变更,再根据变更去操作真实dom

image.png
function patch
function patchVnode
function updateChildren
// 同级比对
// 如果新节点为空,记录dom要被销毁。老节点为空,记录dom需要新建
// 如果新旧都是文本节点,再比较内容,不同则记录新的文本
// 如果新旧的节点类型或者key不相同,记录dom需要替换
// 如果认定为同节点,再比较新旧的各个属性,记录要修改的和要新增的属性值
// 同节点情况下,对比子节点:
// 首尾指针法 oldStart oldEnd  newStart newEnd
// 比对:
// oldStart - newStart 
// oldEnd  - newEnd
// oldStart - newEnd
// oldEnd - newStart
// 这四种有匹配到的情况,则如果是start,则指针右移,是end则指针左移,进行下一轮比较
// 都没匹配到,则在old节点中查找与newStart节点相同的,有则复用,无则创建newStart节点,然后newStart指针向右移动
// 结束比对的节点是end小于start

6. SPA(single page application)

① 什么是单页面应用?
所有的活动在一个Web页面中进行。由一个外壳页面和多个页面片段组成,页面局部刷新,页面片段间的切换快,用户体验更好。

② 单页面的优缺点?

优点 缺点
(页面刷新不需要重新加载整个页面、路由切换不用去请求其他html资源) 首次加载速度较慢、不利于seo

③ 如何给SPA做SEO?
如果需要单页面应用有更好的SEO,那么通常需要使用SSR(Server-Side Rendering)服务端渲染,将组件或页面通过服务器生成html,再返回给浏览器。
SSR的优点:利于SEO,利于首屏加载

服务端渲染是先向后端服务器请求数据,然后生成完整首屏html返回给浏览器;
而客户端渲染是等js代码下载、加载、解析完成后再请求数据渲染,等待的过程页面是什么都没有的,就是用户看到的白屏。
就是服务端渲染不需要等待js代码下载完成并请求数据,就可以返回一个已有完整数据的首屏页面。

7. Vue开发中的性能优化

  1. 路由懒加载
    const page = () => import("@/views/test/index");,只有当路由被访问时才会加载对应的组件

  2. 组件懒加载(异步组件)


    image.png
  3. v-show/v-if(v-if在显示隐藏过程中有DOM的添加和删除,v-show就简单多了,只是操作css)

  4. v-for不和v-if同时使用,v-for要加唯一的key

  5. 能用computed的就用computed(有缓存)

  6. watch监听对象属性时,指定属性

  7. vue2中,data里面数据层级不要太深

  8. 有些数据仅展示不会改变,不需要响应式处理,可以使用Object.freeze进行冻结(因为vue判断 configurable 为 false 的对象直接返回不做响应式处理,而冻结的对象的 configurable 为 false)

  9. 长列表-分页和虚拟加载(只渲染可视部分的内容)

  10. 图片压缩,查看时再下载原图

  11. 对于一些纯展示,没有响应式数据,没有状态管理,也不用生命周期钩子函数的组件,就可以设置成函数式组件(函数式组件并不会创建vue对象)

<!-- 在模板中通过props来访问 -->
<template functional>
    <h1>{{ props.msg }}</h1>
</template>
image.png
Vue.component('component-name', {
  functional: true
});
  1. 保存多次引用的变量,因为响应式对象每次读取都会触发getter,然后去走收集依赖的逻辑

8. 样式穿透

style标签的scoped属性实现了组件样式的私有化,防止组件之间的样式污染,如果需要样式穿透:
① 创建全局css文件并在main.js中引入
② 在单页面使用/deep/

image.png

9. 为什么vue组件data是一个函数

避免共享同一数据造成的数据污染。因为组件可能被用来创建多个实例,如果data直接声明为对象,当组件复用时,这些实例用的同一个构造函数,造成data公用的情况

10. 优先级

props\methods\data\computed\watch

11. key

① for 循环为什么要加 key?
增加key可以标识组件的唯一性,为了在更新视图的时候尽可能地复用dom,而不是创建节点

② 没有现成的key
如果数组中没有唯一的 key值可用,且数组更新时不是全量更新而是采用类似push,splice来插入或者移除数据时,可以考虑对其添加一个 key 字段,值为 Symbol() 即可保证唯一

③ 加上key就一定性能最优吗?
dom节点的移动操作相比简单node的text修改,前者开销更大。key更多的情况下与v-for一起使用;在数据量少的简单情况下,就地更新更快

④ key为什么不用index?
加key就是为了识别,index完全依靠列表顺序,不具备识别的作用

12. v-for 和 v-if 为什么不同时在一个元素上使用

v-for的优先级大于v-if,也就是先循环再判断,如果最后判断为false,不需要渲染,那开始的循环就是无谓的开销了。

13. vue中操作dom

13.1 ref

在标签上加属性ref,可以使用vm.$refs拿到对应的dom

<h1 ref='title'></h1>
this.$refs.title // node h1

13.2 ref标记dom的原理

不是“选择”来的,不需要query,而是标记的。一开始就用ref告诉vue我们要用哪些dom,它直接帮我们存在$refs里

image.png

14. 扩展组件的方式

  • mixin
    代码复用上很方便,但是只适合小范围使用。
    mixin多了可能出现命名冲突,而且维护mixin的内容会变得困难,因为影响范围的内部是不确定的;来源不明:组件内部调用的时候难以判定来源是哪个mixin(这时候需要在命名上加以区分,可以加上mx_[modulename]_前缀)

  • 插槽
    容器型的组件

15. 父子组件挂载过程

父组件 :beforeCreate => created => beforeMount => render
子组件挂载完毕: beforeCreate => created => beforeMount => Mounted => render
父组件挂载:mounted

16. component可以递归使用自己来进行渲染

<!--MenuKJ组件-递归渲染多级菜单-->
<template>
    <ul v-if="menu.length">
        <li v-for="m in menu" :key="m.name">
            {{ m.name }}
            <menuKJ v-if="m.children" :menu="m.children"></menuKJ>
        </li>
    </ul>
</template>
<script>
export default {
    name: 'MenuKJ',
    props: {
        menu: {
            type: Array,
            default: () => []
        }
    }
};
</script>

17. v-model原理

v-bind="value"
@input="value=$event.target.value"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容