记录--手写$forceUpdate,vm.$destroy方法
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

vm.$forceUpdate
(1)作用
迫使Vue.js实例重新渲染。注意它仅仅影响实例本身以及插入插槽内容的子组件,而不是所有子组件。
(2)实现
只需要执行watcher的update方法,就可以让实例重新渲染。
Vue.js的每一个实例都有一个watcher。当状态发生改变时,会通知到组件级别,然后组件内部使用虚拟DOM进行更详细的重新渲染操作。
事实上,组件就是Vue.js实例,所以组件几倍的watcher和Vue.js实例上的watcher说的是同一个watcher。
手动执行实例watcher的update方法,就可以使Vue.js实例重新渲染。
Vue.prototype.$forceUpdate = function(){
const vm = this;
if(vm._watcher){
vm._watcher.update();
}
}
vm._watcher就是Vue.js实例的watcher,每当组件内依赖的数据发生变化时,都会自动触发Vue.js实例中_watcher的update方法。
重新渲染的实现原理并不难,Vue.js的自动渲染通过变化侦测来侦测数据,即当数据发生变化时,Vue.js实例重新渲染。而vm.$forceUpdate是手动通知Vue.js实例重新渲染。
vm.$destroy
(1)作用
完全销毁一个实例,它会清理该实例与其他实例的连接,并解绑其全部指令及监听器,同时会触发beforeDestory和destroyed的钩子函数。
(2)这个方法并不是很常用,大部分场景下并不需要销毁组件,只需要使用v-if或则v-for等指令以数据驱动的方式控制子组件的生命周期即可。
(3)实现原理
Vue.prototype.$destory = function(){
const vm = this;
if(vm._isBeingDestroyed){
return;
}
callHook(vm,"beforeDestroy");
vm._isBeingDestroyed = = true;
}
1、为了防止vm.$destroy被反复执行,先对属性_isBeingDestroyed进行判断,如果它为true,说明Vue.js实例正在被销毁,直接使用return语句退出函数执行逻辑。因为销毁只需要销毁一次即可,不需要反复销毁。
2、然后调用callHook函数触发beforeDestroy的钩子函数(callHook会触发参数中提供的钩子函数)。
(4)销毁实例的逻辑1 首先,需要清理当前组件与父组件之间的连接。组件就是Vue.js实例,所以要清理当前组件与父组件之间的连接,只需要将当前组件实例从父组件实例的$children属性中删除即可。
说明:Vue.js实例的$children属性存储了所有子组件
const parent = vm.$parent;
if(parent && !parent._isBeingDestroyed && !vm.$options.abstract){
remove(parent.$children,vm)
}
1、如果当前实例有父级,同时父级没有被销毁且不是抽象组件,那么将自己从父级的子列表中删除,也就是将自己的实例从父级的$children属性中删除。
2、事实上,子组件在不同父组件中是不同的Vue.js实例,所以一个子组件实例的父级只有一个,销毁操作也只需要从父级的子组件列表中销毁当前这个Vue.js实例。
export function remove(arr,item){
if(arr.length){
const index = arr.indexOf(item);
if(index>-1){
return arr.splice(index,1);
}
}
}
(5)销毁实例的逻辑2
1、父子组件间的链接断掉之后,需要销毁实例上的所有watcher,也就是说需要将实例上所有的依赖追踪断掉。
2、状态会收集一些依赖,当状态发生改变时会向这些依赖发送通知,而被收集的依赖就是watcher实例。因此,当Vue.js实例被销毁时,应该将实例所监听的状态都取消掉,也就是从状态的依赖列表中将watcher移除。
3、watcher的teardown方法,它的作用是从所有依赖项的Dep列表中将自己移除。即只要执行这个方法,就可以断掉这个watcher所监听的所有状态。
4、断掉Vue.js实例自身的watcher实例监听的所有状态。
if(vm._watcher){
vm._watcher.teardown();
}
5、执行了组件自身的watcher实例的teardown方法,从所有依赖项的订阅列表中删除watcher实例。删除之后,当状态发生变化时,watcher实例就不会再得到通知。
6、vm._watcher来源
当执行new Vue()时,会执行一系列初始化操作并渲染组件到实体上,其中就包括vm._watcher的处理
7、从Vue.js2.0开始,变化侦测的粒度调整为中等粒度,它只会发送通知到组件级别,然后组件使用虚拟DOM进行重新渲染。组件其实就是Vue.js实例。
8、怎么通知到组件级别
在Vue.js实例上,有一个watcher,也就是vm._watcher,它会监听这个组件中用到的所有状态,即这个组件内用到的所有状态的依赖列表中都会收集到vm._watcher。当这些状态发生变化时,也都会通知vm._watcher,然后这个watcher再调用虚拟DOM进行重新渲染。
(6)销毁实例的逻辑
1、只从状态的依赖列表中删除Vue.js实例上的watcher实例是不够的。Vue.js提供了vm.watch所创建的watcher实例。
2、从状态的依赖列表中销毁用户创建的watcher实例和销毁Vue实例上的watcher实例相同,只需要执行watcher的teardown方法。
3、问题:如何知道用户创建了多少个watcher?
1)Vue.js的解决方案是执行new Vue()时,在初始化的流程中,在this上添加一个_watchers属性
vm._watchers = [];
2)每当创建watcher实例时,都会将watcher实例添加到vm._watchers中
export default class Watcher{
constructor(vm,expOrFn,cb){
<!-- 每当创建watcher实例时,都将watcher实例添加到vm._watchers中 -->
vm._watchers.push(this);
}
}
4、只需要遍历vm._watchers并依次执行每一项watcher实例的teardown方法,就可以将watcher实例从它所监听的状态的依赖列表中移除。
let i = vm._watchers.length;
while(i--){
vm._watchers[i].teardown();
}
(7)向Vue.js实例添加_isDestroyed属性来表示Vue.js实例已经被销毁。
vm._isDestroyed = true;
(8)当vm.$destroy执行时,Vue.js不会将已经渲染到页面中的DOM节点移除,但会将模板中的所有指令解绑。
vm._patch_(vm._vnode,null)
(9)触发destroyed钩子函数
callHook(vm,'destroyed')
(10)最后,移除实例上的所有事件监听器。
vm.$off()
(11)完整代码
Vue.prototype.$destory = function(){
const vm = this;
<!-- 防止重复销毁 -->
if(vm._isBeingDestroyed){
return;
}
<!-- 调用钩子函数beforeDestroy -->
callHook(vm,"beforeDestroy");
vm._isBeingDestroyed = = true;
<!-- 删除自己与父级之间的连接 -->
const parent = vm.$parent;
if(parent && !parent._isBeingDestroyed && !vm.$options.abstract){
remove(parent.$children,vm);
}
<!-- 从watcher监听的所有状态的依赖列表中移除watcher -->
if(vm._watcher){
vm._watcher.teardown();
}
let i = vm._watchers.length;
<!-- 将从vm.$watcher创建的watcher实例从它所监听的状态的依赖列表中移除 -->
while(i--){
vm._watchers[i].teardown();
}
<!-- 表示实例已经被销毁 -->
vm._isDestroyed = true;
<!-- 将模板中的所有指令解绑 -->
vm._patch_(vm._vnode,null)
<!-- 触发destroyed钩子函数 -->
callHook(vm,'destroyed')
<!-- 移除实例上的所有事件监听器 -->
vm.$off();
}
本文转载于:
https://juejin.cn/post/6844904196840357902
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--手写$forceUpdate,vm.$destroy方法的更多相关文章
- JavaScript数组方法总结及手写
目录 手写数组衍生方法 1.检测是否为数组 2.类数组转化为数组 3.数组扁平化 4.数组去重 5.数组使用Math.max 手写数组内置方法 1. Array.prototype.filter 2. ...
- laravel中delete()方法和destroy()方法的区别
delete()方法是实例方法,需要查询到相应的数据并通过模型实例调用 destroy()方法可以直接调用,通过索引删除记录 举个栗子: /*delete()方法删除*/ //先查找记录 $blog ...
- 06_init()和destroy()方法
[工程截图] [HelloWorld.java] package com.HigginCui; public class HelloWorld { public HelloWorld(){ Syste ...
- JavaEE开发之Spring中Bean的作用域、Init和Destroy方法以及Spring-EL表达式
上篇博客我们聊了<JavaEE开发之Spring中的依赖注入以及AOP>,本篇博客我们就来聊一下Spring框架中的Bean的作用域以及Bean的Init和Destroy方法,然后在聊一下 ...
- PHP获取MySql新增记录ID值的3种方法
From: http://www.jb51.net/article/51473.htm 这篇文章主要介绍了PHP获取MySql新增记录ID值的3种方法,一般使用PHP自带函数mysql_insert_ ...
- map集合修改其中元素 去除Map集合中所有具有相同值的元素 Properties长久保存的流操作 两种用map记录单词或字母个数的方法
package com.swift.lianxi; import java.util.HashMap; import java.util.Iterator; import java.util.Map; ...
- ServletContext结合Servlet接口中的init()方法和destroy()方法的运用----网站计数器
我们一般知道Servlet接口中的init()方法在tomcat启动时调用,destroy()方法在tomcat关闭时调用.那么这两个方法到底在实际开发中有什么作用呢?这就是这个随笔主要讲的内容. 思 ...
- Qt开发的应用记录读取用户习惯设置的方法
Qt开发的应用记录读取用户习惯设置的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/w ...
- mysql中RAND()随便查询记录效率问题和解决的方法分享
在我们做开发的中效率一直是个问题,特别是对于非常多大数据量操作,今天我们碰到一个要随机查询数据,一開始我们可能想到最简单的order by rand() 来操作但效率不敢恭维啊 近期因为须要大概研究了 ...
- 记录手机端h5页面碰到的一些问题
关于input光标在手机端偏移 问题根本:不要使用line-height垂直居中. 解决方法:可直接定义height,然后高度由上下padding值撑开. 移动端清除input光标 ios input ...
随机推荐
- Power BI 2 DAY
目录 Power BI零散知识点 M函数 Power BI零散知识点 纵向合并 = 主页-组合-追加查询-追加查询(修改数据源)-将查询追加为信查询(创建新数据源) 横向合并 = 主页-组合-合并查询 ...
- 未配置Datasource时, 启动 SpringBoot 程序报错的问题
SpringBoot will show error if there is no datasource configuration in application.yml/application.pr ...
- STC89C52驱动MAX7219LED点阵级联, 文字滚动效果
级联下的传值方式 级联下, N个MAX7219相当于组成了一个8*N bit宽度的锁存器, 如果需要对第M个7219进行写入, 需要做M次寻址+写入后拉高CS, 才能到达这个7219. 如果仅仅对这个 ...
- Vue+SpringBoot+ElementUI实战学生管理系统-2.搭建Vue+elementUI脚手架
1.项目介绍 前一片介绍了项目的整体情况,这一篇开始搭建前端工程,需要的朋友可以拿去自己定制.:) 2.获取源码 源码是捐赠方式获取,详细请QQ联系我 :)! 3.项目截图 登录页 列表操作 动态图 ...
- ubantu中安装redis及遇到的问题
安装命令 sudo apt-get install redis-server 开启远程连接 找到vi /etc/redis/redis.conf文件修改如下 bind 127.0.0.1 为 0.0. ...
- 07-Redis系列之-双写一致性,缓存详解和优化点
双写一致性 双写一致性指的是当我们更新了数据库的数据之后redis中的数据也要同步去更新. redis和mysql数据同步方案 先更新缓存,再更新数据库(然并软...) 先更新数据库,再更新缓存(一般 ...
- 【系统选型】OA需求分析,OA系统选型及各供应商对比。
去年公司内部做OA信息化升级,需要更新换代一下OA系统,当时OA选型整理下来的资料分享一下. 需求调研整理后如下: 一共四个模块需要更新&升级 : OA模块(包括行政) + 合同模块 + 费 ...
- 【Filament】绘制圆形
1 前言 Filament环境搭建中介绍了 Filament 的 Windows 和 Android 环境搭,绘制三角形中介绍了绘制纯色和彩色三角形,绘制矩形中介绍了绘制纯色和彩色矩形,本文将使用 ...
- 使用二进制重排 & Clang插桩技术点来进行iOS冷启动进行优化
1.冷启动 1.1 什么是冷启动? 冷启动是指内存中不包含该应用程序相关的数据,必须要从磁盘载入到内存中的启动过程. 注意:重新打开 APP, 不一定就是冷启动. 当内存不足,APP被系统自动杀死后, ...
- Nebula Graph 1.0 Release Note
Nebula Graph 1.0 发布了.作为一款开源分布式图数据库,Nebula Graph 1.0 版本旨在提供一个安全.高可用.高性能.具有强表达能力的查询语言的图数据库. 基本功能 DDL & ...