虚拟dom、请求方式、生命周期内共十个钩子函数(一)

面试题: v-if vs v-show区别?

v-show 如果为false,会将元素display:none
v-if 如果为false,会将元素直接从dom树删除掉
v-else 需配合 v-if一起使用,不能单独使用
template因为这个标签不会被浏览器解析,所以v-show对其无效,只能用v-if
v-if 是否可以与 v-for同时使用? 不行的? v-for优先级与v-if优先级高

为什么用data()?
每个组件或实例都有一个被对象返回独立的拷贝

polyfill:

判断当前浏览器的版本是否支持fetch,支持就直接用,若不支持就用polyfill
polyfill只是做了个兼容
1、$ npm install fetch-ie8 --save 安装
2、$ npm install es6-promise 安装
3、require(‘es6-promise’).polyfill(); 项目入口文件调用该方法
get请求:

get(){
    fetch("./json/temp.json").then(res=>{
        // return res.text()        //返回了string格式的数据
        return res.json()           //返回了json格式的数据
    }).then(res=>{
        console.log(res)
    })
}post请求:
post(){
    fetch("http://localhost:3000/add",{
        method:"post",
        headers:{"Content-Type":"application/x-www-form-urlencoded"},
        body:"name=XXX&age=10"
    }).then(res=>{return res.json()}).then(res=>{console.log(res)})
}
​
//第二种方法
post(){
    fetch("地址",{
        method:"post",
        headers:{
            "Content-Type":‘’application/json"
        },
        body:JSON.stringify({
            name:"123",
            age:12
        })
    }).then(res=>{
        return res.json()
    }).then(res=>{
        console.log(res);
    })
}

为什么v-for指令当中添加key?

(key值是唯一的,不变的,尽量不要用index下标,除非你知道下标是不变的)
1、虚拟dom对比的时候,添加元素、删除元素的时候 key 提高对比效率
2、因为如果没有加key,内部插入新的元素,后面的元素都会经历卸载与重新装载的过程,效率太低了
3、添加key之后,内部本着key值相同,dom节点复用原则。
虚拟DOM
vue中引入了虚拟dom(真实dom映射,js对象) 属于内存数据的
1.vue在内存中生成一颗虚拟dom树

    *var* vDom = {
tag:"div",
attr:{id:"content"},
 children:[
{tag:"p",content:"2"},
{tag:"ul",attr:{className:"list-group"}}
]
}

2.将内存当中的虚拟dom将其初始化渲染,渲染成真实dom树,浏览器就可以看到了。
3.当我们修改vue实例当中data数据项的时候

this.arr.push("<li>1111</li><li>2222</li>")

4.将之前的虚拟dom结合更改后的数据,生成一颗新的虚拟dom数

    *var* newVDom = {
​
tag:"div",
​attr:{id:"content"},
​children:[
​ {tag:"p",content:"2"},
​ {tag:"ul",attr:{className:"list-group"},children:[
​{tag:"li",content:"1111"},
​  {tag:"li",content:"2222"}
​ ]}
​]
​ }

//5.将新的虚拟dom树 与 之前的虚拟dom树,进行diff算法的比较,对比差异
//6.再去将对比后的差异的部分进行重新的真实dom的渲染操作。

虚拟dom的原理

频繁且复杂的dom操作通常是前端性能瓶颈的产生点,Vue提供了虚拟dom的解决办法

虚拟的DOM的核心思想是:对复杂的文档DOM结构,提供一种方便的工具,进行最小化地DOM操作。这句话,也许过于抽象,却基本概况了虚拟DOM的设计思想

(1) 提供一种方便的工具,使得开发效率得到保证
(2) 保证最小化的DOM操作,使得执行效率得到保证

也就是说,虚拟dom的框架/工具都是这么做的:

  1. 根据虚拟dom树最初渲染成真实dom
  2. 当数据变化,或者说是页面需要重新渲染的时候,会重新生成一个新的完整的虚拟dom
  3. 拿新的虚拟dom来和旧的虚拟dom做对比(使用diff算法)。得到需要更新的地方之后,更新内容

这样的话,就能大量减少真实dom的操作,提高性能
diff

什么是虚拟dom?与key值的关系?
Virual DOM是用JS对象记录一个dom节点的副本,当dom发生更改时候,先用虚拟dom进行diff,算出最小差异,然后再修改真实dom。

当用传统的方式操作DOM的时候,浏览器会从构建DOM树开始从头到尾执行一遍流程,效率很低。而虚拟DOM是用javascript对象表示的,而操作javascript是很简便高效的。虚拟DOM和真正的DOM有一层映射关系,很多需要操作DOM的地方都会去操作虚拟DOM,最后统一一次更新DOM。因而可以提高性能

虚拟DOM的Diff算法

虚拟DOM中,在DOM的状态发生变化时,虚拟DOM会进行Diff运算,来更新只需要被替换的DOM,而不是全部重绘。
在Diff算法中,只平层的比较前后两棵虚拟DOM树的节点,没有进行深度的遍历。

1.如果节点类型改变,直接将旧节点卸载,替换为新节点,旧节点包括下面的子节点都将被卸载,如果新节点和旧节点仅仅是类型不同,但下面的所有子节点都一样时,这样做也是效率不高的一个地方。
2.节点类型不变,属性或者属性值改变,不会卸载节点,执行节点更新的操作。
3.文本改变,直接修改文字内容。
4.移动,增加,删除子节点时:

如果想在中间插入节点F,简单粗暴的做法是:卸载C,装载F,卸载D,装载C,卸载E,装载D,装载E。如下图:
key1

写代码时,如果没有给数组或枚举类型定义一个key,就会采用上面的粗暴算法。
如果为元素增加key后,Vue就能根据key,直接找到具体的位置进行操作,效率比较高。如下图:

本寻着key值相同的即可复用的原则。key2

*在v-for中提供key,一方面可以提高性能,一方面也会避免出错

生命周期中的8个钩子函数和keep-alive动态组件内的2个钩子函数:

生命周期
每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁

  1. 实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载到,只是一个空壳,无法访问到数据和真实的dom,一般不做操作

  2. 挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里同步更改数据不会触发updated函数,一般可以在这里做初始数据的获取。 做异步ajax,绑定初始化事件

  3. 接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,这是在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始化数据的获取

  4. 接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情…

  5. 当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿

  6. 当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的dom

  7. 当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

  8. 组件的数据绑定、监听…去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

<div id="app"> 
    <my-component></my-component>
</div>

<!--定义组件的模板-->
<template id="my-component">
    <div>
        <h1 id="title">我是h1 -- {{msg}}</h1>    
        <input type="text" v-model="msg">
        <button @click="destroy">销毁组件</button>
    </div>
</template>
<script>
    /*
        组件从创建到销毁的一系列过程叫做组件的声明周期。
        vue在整个生命周期里面提供了一些函数,可以在内部实现一些业务逻辑,
        并且这些函数会在一些特定的场合下去执行。(在生命周期的某一个时刻进行触发)
        
        组件的生命周期大体可以分为三个阶段: 初始化、运行中、销毁
        初始化阶段:beforeCreate created beforeMount (render) mounted
        运行中阶段:beforeUpdate updated
        销毁阶段:  beforeDestroy destroyed
    */

    //初始化阶段
    //1.一个组件或者实例的生命周期都是从new开始的
    //2.实例化之后,内部会做一些初始化的事件与生命周期相关的配置
    Vue.component("my-component",{
        template:"#my-component",
        data(){
            return {
                msg:"hello"
            }
        },
        methods:{
            destroy(){
                this.$destroy() //组件销毁方法
            }
        },
        //3.beforeCreate这个钩子函数初始化的时候就会执行
        //但是数据是获取不到的,并且真实dom元素也是没有渲染出来的
        beforeCreate(){
            console.log("beforeCreate...")
            console.log(this.msg,document.getElementById("title"))
        },
        //4.created钩子函数内部可以访问到数据了,但是页面当中真实dom节点还是没有渲染出来
        //在这个钩子函数里面,可以进行相关初始化事件的绑定、发送ajax操作
        //当组件还没有挂载完毕之前,更改数据的话,是不会触发运行时钩子函数的执行!
        created(){
            console.log("created...")
            this.timer = setInterval(()=>{
                console.log("定时器开着哦...")
                this.msg = this.msg+"!"
            },2000)
            // this.msg = 11111111111
            console.log(this.msg,document.getElementById("title"))
        },
        //5.接下来的过程,就是组件或者实例去查找各自的模板结构,然后将其编译成虚拟dom
        //6.beforeMount代表dom马上就要被渲染出来了,但是却还没有真正的渲染出来
        //这个钩子函数与created钩子函数用法基本一致,可以进行相关初始化事件的绑定、发送ajax操作
        beforeMount(){
            console.log("beforeMount...")
            console.log(this.msg,document.getElementById("title"))
        },
        //生成好虚拟dom,然后内部通过render函数将对应的el进行替换,做一个初始化的虚拟dom渲染真实dom过程
        // render(){
        //     console.log("render....")
        // }
        //7.mounted钩子函数是挂载阶段的最后一个钩子函数
        //数据挂载完毕,真实dom元素也已经渲染完成了
        //这个钩子函数内部可以做一些实例化相关的操作   拖拽
        mounted(){
            console.log("mounted...")
            console.log(this.msg,document.getElementById("title"))
        },
        //8.这个钩子函数初始化的不会执行
        //当组件挂载完毕的时候,并且当数据改变的时候,才会立马执行
        //这个钩子函数获取dom的内容是更新之前的内容
        beforeUpdate(){
            console.log("beforeUpdate...",this.msg ,document.getElementById("title").innerHTML)
        },
        //9.这个钩子函数获取dom的内容是更新之后的内容
        //生成新的虚拟dom,新的虚拟dom与之前的虚拟dom进行比对,差异之后,就会进行真实dom渲染。
        //在updated钩子函数里面就可以获取到因diff算法比较差异得出来的真实dom渲染了。
        updated(){
            console.log("updated....", this.msg,document.getElementById("title").innerHTML)
        },
        //10.当组件销毁的时候,就会触发
        //这个钩子函数代表销毁之前,可以做一些善后操作
        //可以清除一些初始化事件、定时器相关的东西。
        beforeDestroy(){
            console.log("beforeDestory....")
            clearInterval(this.timer)
        },
        //11.组件销毁的时候执行
        //watch/数据劫持等功能已经完全丧失 
        destroyed(){
            console.log("destroyed...")
        }
    })
    new Vue().$mount("#app");
</script>

keep-alive动态组件
用keep-alive标签包裹动态组件的时候,会缓存不活动的组件实例,就不会去执行beforeDestroy钩子函数,那么动态组件就不会被销毁,
当用keep-alive包裹动态组件的时候,他也提供两个钩子函数:activated和deactivated(这两个函数只有在被keep-包裹的时候才会触发)
activated放的是一些初始化事件,而deactived是将初始化的一些事件除去(可以将created和beforeDestroy对应的替换掉)
include只有名称匹配的组件会被缓存,exclude只有名称匹配的组件不会被缓存,与include相反,默认缓存所有动态组件

<div id="app">
    <button @click="type=type=='mya'?'myb':'mya'">切换</button>
    <keep-alive include="mya">
        <component :is="type"></component>
    </keep-alive>
</div>
<script>
    Vue.component("mya",{
        template:"<h3>A组件</h3>",
        created(){          //created钩子函数只执行一次
            console.log("created...A")
        },
        beforeDestroy(){
            console.log("beforeDestroy...A")
        },
        activated(){
            console.log("activated...A")
        },
        deactivated(){
            console.log("deactivated...A")
        }
    })
    Vue.component("myb",{
        template:"<h3>B组件</h3>",
        created(){
            console.log("created...B")
        },
        beforeDestroy(){
            console.log("deforeDestroy...B")
        },
        activated(){
            console.log("activated...B")
        },
        deactivated(){
            console.log("deactivated...B")
        }
    })
    new Vue({
        el:"#app",
        data:{
            type:"mya"
        }
    })
</script>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值