重要的事情说三遍:在VUE中任何直接更改DOM的行为都是作死
重要的事情说三遍:在VUE中任何直接更改DOM的行为都是作死
重要的事情说三遍:在VUE中任何直接更改DOM的行为都是作死
关于VUE的数据流模式
通常来说 有的人会通过VUE的特性而把它理解成双向数据流模式,但是VUE其实是单向数据流框架,而他其中的v-model只是一个语法糖而已,他使用其他的方法可以同样达到一个双向绑定的效果,如下
<P v-model="phoneInfo"/>
<PersonalInfo v-model="phoneInfo"/>
<PersonalInfo
//我input里面的数据
:phone-info="phoneInfo"
我要双向绑定的数据
:zip-code="zipCode"
//我在改变的时候同时改变我自己的值
@change="val => (phoneInfo = val)"
//我在数据更新的时候同时改变我的数据
@update:zipCode="val => (zipCode = val)"
/>
这两种写法都可以达到双向绑定的效果,更加证实了v-model只是一个语法糖的结论
而在面试时,面试官可能会问VUE是如何做到双向数据流绑定的,大部分人都会回答:是通过是通过Object.defineProperty来达到双向数据流绑定的.
但这种说法是很不稳妥的,这是可以先说这种,然后再说但是,再把上面的例子讲出来,这样会更好一点
ps:VUE中单向数据流和双向数据流并不冲突!!!!
关于VUE的虚拟DOM比对模式
答:"由于程序员是无法接受全部比对这种机制的,所以VUE采用了通过比对同级节点来达到找到需要更新的节点,这样的话更加节省资源和提高性能,比对的是Before和After中处于同一层级的数据",来看看下面这个图片
扩展:为什么要绑定key值?
由于VUE的比对机制,如果在同一层级中只是改变了组件的位置,但是这个机制并不是改变位置,而是先删除再创建,这样就会导致组件不可复用及其他不可预知的bug,所以加入了绑定key的这个机制,加入key之后当你改变数据时,就不会发生数据删除再创建的这个问题了..(重点,要理解原因,)...
还有绝对不能绑定index,因为在项目中,你的数据大部分都是数组格式,如果发生数据删除或者位移,肯定会产生严重bug,所以要绑定id之类的
关于VUE的运行驱动方法
从开头的那三句话,咱们门就能看出来,VUE是通过操作数据来改变视图(DOM),也就是数据驱动.这是VUE的核心思想,还有一种说法就是,在特殊情况下再直接更改DOM,但是你有没有想过,你认为的特殊情况在可能只是你认为特殊情况,这时不妨抽根烟冷静下来好好思考一下,或许换一种思路,这个问题就不再是特殊情况了,对吧,哈哈,所以还是那句话!!!!!!在VUE中任何直接更改DOM的行为都是作死!!!!!!
关于VUE组件的数据来源
1.来自于父元素的属性
2.来自于自身的data
3.来自于状态管理器,如Vuex,Vue.observable(vue2.6新增的的一个api)
VUE2.6具体更新信息
如何触发组件的更新
1.状态 data vs 属性 props
状态是组件自身的数据
属性是来自于父组件的数据
状态的改变未必会触发更新
属性的改变未必会触发更新
举个例子
//
data(){
//当你在改变这个msg时,不会触发更新,原因是他没有做响应式,如果想出发的话要给msg做响应式,也就是放到return里面
msg:""
return{
//而当你改变number.list是也不会触发更新,这是因为你对number做了响应式,短时对于要更改的数据并没有出初始化或者是定义
number:{
//list:""
}
}
}
生命周期里面的注意事项
注意,万万不可在beforeUpdate和updated中修改依赖数据,原因是你一旦更改就会重新触发beforeUpdate而出现死循环....
关于递归查找及如何优雅地获取跨组件实例
组件创建完成之后,都会生成一个实例,理想状态下你并不需要关注这个实例,但随着业务逻辑越来越深,这这时候你难免需访问到某些个组件的实例.就像我们有时会使用Echarts,这样就很难避免不操作实例的情况.所以VUE为我们预留了一个api来让我们能更加方便的获取到,如下:
//这个会获取到当前节点的DOM
<p ref="XXX">
//这个会获取到当前指定的vue实例
<XXX-compoents ref="XXX">
但是如果说我们要获取跨层级的实例,那就很不方便了 ,加入我们要或取父组件的实例咱们就需要使用parent.ref,获取子组件的咱们就需要children.ref...这样的话就会产生类似与跨组件传值的问题,就是递归查找,而你每次运行实力的时候都会进行一次递归查找,因为你的实例是不能被缓存的,并且如果你的子组件更新的,你的父组件式无法及时的获取到这个状态的,这样做的话,冗余且繁琐脆弱...所以很多大佬都在寻找解决方案..如果你熟悉react,那么你应该知道react的ref是通过一个callback回调的方式,这样的话,这样的话我们就可以在回调之中做很多事情,他就比较灵活,这里咱们要使用组件通知和组件接收.唐金洲老师写了一个自定义指令可以解决这个问题大家可以看一下,方便大家未来解决未来的编程问题,需要注意的一点,这里也明确地表示 他可能会与未来的VUE产生冲突,具体实现方法如下:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
install: function install(Vue) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var directiveName = options.name || 'ref';
Vue.directive(directiveName, {
bind: function bind(el, binding, vnode) {
binding.value(vnode.componentInstance || el, vnode.key);
},
update: function update(el, binding, vnode, oldVnode) {
if (oldVnode.data && oldVnode.data.directives) {
var oldBinding = oldVnode.data.directives.find(function (directive) {
var name = directive.name;
return name === directiveName;
});
if (oldBinding && oldBinding.value !== binding.value) {
oldBinding && oldBinding.value(null, oldVnode.key);
binding.value(vnode.componentInstance || el, vnode.key);
return;
}
}
// Should not have this situation
if (vnode.componentInstance !== oldVnode.componentInstance || vnode.elm !== oldVnode.elm) {
binding.value(vnode.componentInstance || el, vnode.key);
}
},
unbind: function unbind(el, binding, vnode) {
binding.value(null, vnode.key);
}
});
}
};
这里不作过多阐述,我正在研究,大体已了解后续会补上实现原理,注:代码已开源请大家自行查找地址
关于Element-ui与ECharts相结合的问题
这个问题是我这段时间遇到的,某个公司的员工说它的项目中无法添加新数据等等,所以用了一些比较野的方法解决了这个问题,但自我感觉并不稳妥,我希望我在以后的学习过程中,能找到更好的解决方法,不过我是在尽量不改变他原本代码的基础上进行修复的,所以代码量大大增加,但是也学到了很多,具体实现方法请看我的另一篇文章处理Element-UI与ECharts融合问题,这个个人感觉很重要,因为数据统计在现在特别重要,所以在面试时把这个作为突出点可能会是一个突破
关于生命周期
每个VUE组件在被创建的时候,都会经过一系列的初始化过程,以及组件更新的时候,也会经历一系列的钩子函数,给我们执行一些业务逻辑代码,这一系列过程我们就叫做生命周期,.分为创建阶段-更新阶段-销毁阶段,而创建阶段和销毁阶段,在组件的声明周期中,只会执行一次,而更新阶段则会执行多次..可以参考下图
创建阶段
在创建阶段我们会先经过一个beforeCreate在这之前我们会有一个事件的初始化还有生命周期的初始化,而在beforeCreate之后我们则会会我们的数据进行响应式的处理一级对组件中的数据,属性及监听器进行一系列的配置等,之后我们就开始了created生命周期接着之后我们就要进行一个将模板编译到render,但如果你写的直接就是render函数,name这一步就会被跳过,之后咱们就到了beforeMount这个阶段,这时候我们就要执行我们的render,生成一个虚拟DOM之后之后咱们就要将这个虚拟DOM挂载到我们的真实DOM,挂在完整之后就到了mounted阶段,我们在mounted中一般要做的是一些异步请求,操作DOM等....
更新阶段
这个阶段是会执行多次的,每当我们的数据发生变化的这时候,都会执行这一端生命周期,这就是为什么我们不能再这里修改依赖的数据的原因,会导致无限循环而宕机,生命周期到这就差不多了,但要注意一点还有两个销毁阶段,虽然不常用,但要记住在这里写清除计时器等等,否则会内存溢出.
穿插几个小问题
关于子组件为何不能修改父组件的传来的props
因为Vue是单向数据流,它的具体实现,同样也是通过Object.defineProperty实现的,
如果想更改这个数据可以使用$emit来进行更改,这些在前面也提到过了.
关于插槽在vue2.5中,和在vue2.6+中有什么区别
在2.5版本中插槽是合并的机制,作用域插槽则是替换的机制
在2.6+版本中则全部为替换的方式,因为在2.6+后所有插槽都是以作用域插槽存在的两者并无太大区别